Выполнение хранимых процедур — обработка кодов возврата и выходных параметров
Применимо к: SQL Server Azure SQL Database
Управляемый экземпляр SQL Azure
Azure Synapse Analytics Analytics
Platform System (PDW)
Драйвер ODBC SQL Server поддерживает выполнение хранимых процедур как удаленных. Выполнение хранимых процедур как удаленных хранимых процедур позволяет драйверу и серверу повысить производительность при выполнении процедуры.
Хранимые процедуры SQL Server могут иметь целочисленные коды возврата и выходные параметры. Коды возврата и выходные параметры пересылаются в последнем пакете от сервера, они не доступны приложению, пока SQLMoreResults не возвратит SQL_NO_DATA. Если из хранимой процедуры возвращается ошибка, вызовите SQLMoreResults, чтобы перейти к следующему результату, пока не будет возвращен SQL_NO_DATA.
Важно!
По возможности используйте аутентификацию Windows. Если проверка подлинности Windows недоступна, запросите у пользователя ввод учетных данных во время выполнения. Избегайте хранения учетных данных в файле. Если необходимо сохранить учетные данные, зашифруйте их с помощью API-интерфейса шифрования Win32.
Обработка кодов возврата и выходных параметров
Сконструируйте инструкцию SQL, использующую escape-последовательность ODBC CALL. Инструкция должна использовать маркеры параметров для каждого параметра входа, входа-выхода и выхода, а также для возвращаемого процедурой значения (если оно имеется).
Вызовите SQLBindParameter для каждого параметра входа, входа-выхода и выхода, а также для значения, возвращаемого процедурой (если оно имеется).
Выполните инструкцию с помощью SQLExecDirect.
Обрабатывайте результирующие наборы до тех пор, пока SQLFetch или SQLFetchScroll не возвратит SQL_NO_DATA при обработке последнего результирующего набора или до тех пор, пока SQLMoreResults не возвратит SQL_NO_DATA. На этот момент переменные, привязанные к коду возврата, а также выходные параметры заполнены возвращенными значениями данных.
Пример
В данном образце демонстрируется обработка кода возврата и выходного параметра. Этот образец не поддерживается на архитектуре IA64. Этот образец разработан для ODBC версии 3.0 или более поздней.
Также необходим источник данных ODBC с именем AdventureWorks, для которого базой данных по умолчанию является образец базы данных AdventureWorks. (Пример базы данных AdventureWorks можно скачать на домашней странице примеров и проектов сообщества Microsoft SQL Server.) Этот источник данных должен основываться на драйвере ODBC, предоставленном операционной системой (имя драйвера — "SQL Server"). При построении и запуске этого образца как 32-разрядного приложения в 64-разрядной операционной системе необходимо создать источник данных ODBC с помощью программы администрирования ODBC (исполняемый файл %windir%\SysWOW64\odbcad32.exe).
В этом примере выполняется подключение к экземпляру SQL Server компьютера по умолчанию. Чтобы соединиться с именованным экземпляром, измените определение источника данных ODBC, указав экземпляр в следующем формате: Сервер\ИменованныйЭкземпляр. По умолчанию SQL Server Express устанавливается на именованный экземпляр.
Первый листинг кода (Transact-SQL) создает хранимую процедуру, используемую в этом примере.
Скомпилируйте второй листинг кода (C++) с библиотекой odbc32.lib. Затем запустите программу.
Третий листинг кода (Transact-SQL) удаляет хранимую процедуру, используемую в этом примере.
USE AdventureWorks2022;
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'TestParm')
DROP PROCEDURE TestParm
GO
CREATE PROCEDURE TestParm
@OutParm int OUTPUT
AS
SELECT Name FROM Purchasing.Vendor
SELECT @OutParm = 88
RETURN 99
go
// compile with: odbc32.lib
#include \<stdio.h>
#include \<string.h>
#include \<windows.h>
#include \<sql.h>
#include \<sqlext.h>
#include \<odbcss.h>
#define MAXBUFLEN 255
SQLHENV henv = SQL_NULL_HENV;
SQLHDBC hdbc1 = SQL_NULL_HDBC;
SQLHSTMT hstmt1 = SQL_NULL_HSTMT;
void Cleanup() {
if (hstmt1 != SQL_NULL_HSTMT)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
if (hdbc1 != SQL_NULL_HDBC) {
SQLDisconnect(hdbc1);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
}
if (henv != SQL_NULL_HENV)
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
int main() {
RETCODE retcode;
// SQLBindParameter variables.
SWORD sParm1 = 0, sParm2 = 1;
SQLLEN cbParm1 = SQL_NTS;
SQLLEN cbParm2 = SQL_NTS;
// Allocate the ODBC environment and save handle.
retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLAllocHandle(Env) Failed\n\n");
Cleanup();
return(9);
}
// Notify ODBC that this is an ODBC 3.0 app.
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLSetEnvAttr(ODBC version) Failed\n\n");
Cleanup();
return(9);
}
// Allocate ODBC connection handle and connect.
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLAllocHandle(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
// This sample use Integrated Security. Create the SQL Server DSN by using the Windows NT authentication.
retcode = SQLConnect(hdbc1, (UCHAR*)"AdventureWorks", SQL_NTS, (UCHAR*)"",SQL_NTS, (UCHAR*)"", SQL_NTS);
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
printf("SQLConnect() Failed\n\n");
Cleanup();
return(9);
}
// Allocate statement handle.
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
printf("SQLAllocHandle(hstmt1) Failed\n\n");
Cleanup();
return(9);
}
// Bind the return code to variable sParm1.
retcode = SQLBindParameter(hstmt1, 1, SQL_PARAM_OUTPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &sParm1, 0, &cbParm1);
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
printf("SQLBindParameter(sParm1) Failed\n\n");
Cleanup();
return(9);
}
// Bind the output parameter to variable sParm2.
retcode = SQLBindParameter(hstmt1, 2, SQL_PARAM_OUTPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &sParm2, 0, &cbParm2);
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
printf("SQLBindParameter(sParm2) Failed\n\n");
Cleanup();
return(9);
}
// Execute the command.
retcode = SQLExecDirect(hstmt1, (UCHAR*)"{? = call TestParm(?)}", SQL_NTS);
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
printf("SQLExecDirect Failed\n\n");
Cleanup();
return(9);
}
// Show parameters are not filled.
printf("Before result sets cleared: RetCode = %d, OutParm = %d.\n", sParm1, sParm2);
// Clear any result sets generated.
while ( ( retcode = SQLMoreResults(hstmt1) ) != SQL_NO_DATA )
;
// Show parameters are now filled.
printf("After result sets drained: RetCode = %d, OutParm = %d.\n", sParm1, sParm2);
// Clean up.
SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
SQLDisconnect(hdbc1);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
USE AdventureWorks2022;
DROP PROCEDURE TestParm
GO
См. также:
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по