Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
До ODBC 3.8 приложение может получить только выходные параметры запроса с привязанным выходным буфером. Однако трудно выделить очень большой буфер, если размер значения параметра очень велик (например, большой образ). ODBC 3.8 представляет новый способ получения выходных параметров в частях. Теперь приложение может вызывать SQLGetData с небольшим буфером несколько раз, чтобы получить большое значение параметра. Это похоже на извлечение больших данных из столбцов.
Чтобы привязать выходной параметр или параметр ввода-вывода для извлечения частями, вызовите SQLBindParameter с аргументом InputOutputType, установленным в значение SQL_PARAM_OUTPUT_STREAM или SQL_PARAM_INPUT_OUTPUT_STREAM. С помощью SQL_PARAM_INPUT_OUTPUT_STREAM приложение может использовать SQLPutData для ввода данных в параметр, а затем использовать SQLGetData для получения выходного параметра. Входные данные должны быть представлены в форме данных-при-выполнении (DAE), используя SQLPutData вместо привязки данных к заранее выделенному буферу.
Эту функцию можно использовать приложениями ODBC 3.8 или повторно компилировать приложения ODBC 3.x и ODBC 2.x, и эти приложения должны иметь драйвер ODBC 3.8, поддерживающий получение выходных параметров с помощью SQLGetData и ODBC 3.8 Driver Manager. Сведения о том, как включить более старое приложение для использования новых функций ODBC, см. в таблице совместимости.
Пример использования
Например, попробуйте выполнить хранимую процедуру {CALL sp_f(?,?)}, где оба параметра привязаны как SQL_PARAM_OUTPUT_STREAM, а хранимая процедура не возвращает результирующий набор (далее в этом разделе вы найдете более сложный сценарий):
Для каждого параметра вызовите SQLBindParameter с параметром InputOutputType , равным SQL_PARAM_OUTPUT_STREAM, а параметрValuePtr — маркеру, например номеру параметра, указателю на данные или указателю на структуру, которую приложение использует для привязки входных параметров. В этом примере в качестве токена используется порядковый номер параметра.
Выполните запрос с помощью SQLExecDirect или SQLExecute. SQL_PARAM_DATA_AVAILABLE возвращается, указывая, что для извлечения доступны потоковые выходные параметры.
Вызовите SQLParamData, чтобы получить параметр, доступный для получения. SQLParamData возвращает SQL_PARAM_DATA_AVAILABLE с маркером первого доступного параметра, который устанавливается в SQLBindParameter (шаг 1). Маркер возвращается в буфере, на который указывает ValuePtrPtr.
Вызовите SQLGetData с аргументом Col_or_Param_Num, установленным на порядковый номер параметра, чтобы получить данные первого доступного параметра. Если SQLGetData возвращает SQL_SUCCESS_WITH_INFO и SQLState 01004 (усечение данных), и тип имеет переменный размер как на клиенте, так и на сервере, доступны дополнительные данные для извлечения из первого доступного параметра. Вы можете продолжать вызывать SQLGetData, пока он не вернет SQL_SUCCESS или SQL_SUCCESS_WITH_INFO, но с измененным SQLState.
Повторите шаг 3 и шаг 4, чтобы получить текущий параметр.
Снова вызовите SQLParamData . Если он возвращает что-либо, кроме SQL_PARAM_DATA_AVAILABLE, больше нет данных параметров потока для извлечения, а возвращаемый код будет кодом возврата следующей выполняемой инструкции.
Вызовите SQLMoreResults для обработки следующего набора параметров, пока SQLMoreResults не вернет SQL_NO_DATA. SQLMoreResults возвращает SQL_NO_DATA в этом примере, если для атрибута инструкции SQL_ATTR_PARAMSET_SIZE задано значение 1. В противном случае SQLMoreResults возвращает SQL_PARAM_DATA_AVAILABLE, чтобы указать, что для получения следующего набора параметров доступны потоковые выходные параметры.
Как и входной параметр DAE, маркер, используемый в аргументе ParameterValuePtr в SQLBindParameter (шаг 1), может быть указателем, указывающим на структуру данных приложения, которая содержит порядковый номер параметра и дополнительные сведения о приложении при необходимости.
Порядок возвращаемых потоковых выходных данных или входных и выходных параметров является определенным драйвером и может не всегда совпадать с порядком, указанным в запросе.
Если приложение не вызывает SQLGetData на шаге 4, значение параметра удаляется. Аналогичным образом, если приложение вызывает SQLParamData до того, как все значение параметра считывается SQLGetData, оставшаяся часть значения удаляется, а приложение может обрабатывать следующий параметр.
Если приложение вызывает SQLMoreResults до обработки всех потоковых выходных параметров (SQLParamData по-прежнему возвращает SQL_PARAM_DATA_AVAILABLE), все остальные параметры удаляются. Аналогичным образом, если приложение вызывает SQLMoreResults до того, как все значение параметра считывается SQLGetData, оставшаяся часть значения и все остальные параметры удаляются, и приложение может продолжать обрабатывать следующий набор параметров.
Обратите внимание, что приложение может указать тип данных C в SQLBindParameter и SQLGetData. Тип данных C, указанный в SQLGetData, переопределяет тип данных C, указанный в SQLBindParameter, если только тип данных C, указанный в SQLGetData, не SQL_APD_TYPE.
Хотя потоковые выходные параметры более полезны, если тип данных выходного параметра имеет тип BLOB, эта функция также может использоваться с любым типом данных. Типы данных, поддерживаемые потоковыми выходными параметрами, указываются в драйвере.
Если для обработки есть параметры SQL_PARAM_INPUT_OUTPUT_STREAM, SQLExecute или SQLExecDirect сначала вернет SQL_NEED_DATA. Приложение может вызывать SQLParamData и SQLPutData для отправки данных параметров DAE. При обработке всех входных параметров DAE SQLParamData возвращает SQL_PARAM_DATA_AVAILABLE для указания доступных потоковых выходных параметров.
При потоковой обработке выходных параметров и привязанных выходных параметров драйвер определяет порядок обработки выходных параметров. Таким образом, если выходной параметр привязан к буферу (параметр InputOutputTypeSQLBindParameter имеет значение SQL_PARAM_INPUT_OUTPUT или SQL_PARAM_OUTPUT), буфер может не заполняться, пока SQLParamData не возвращает SQL_SUCCESS или SQL_SUCCESS_WITH_INFO. Приложение должно считывать привязанный буфер только после того, как SQLParamData возвращает SQL_SUCCESS или SQL_SUCCESS_WITH_INFO после обработки всех потоковых выходных параметров.
Источник данных может возвращать, помимо поточного выходного параметра, предупреждение и результирующий набор. Как правило, предупреждения и результирующие наборы обрабатываются отдельно от потокового выходного параметра путем вызова SQLMoreResults. Обработать все предупреждения и весь результирующий набор перед обработкой выходного параметра потоковых данных.
В следующей таблице описываются различные сценарии одной команды, отправляемой на сервер, и способ работы приложения.
| Scenario | Возвращаемое значение из SQLExecute или SQLExecDirect | Дальнейшие действия |
|---|---|---|
| Данные включают только потоковые выходные параметры | SQL_PARAM_DATA_AVAILABLE | Используйте SQLParamData и SQLGetData для получения потоковых выходных параметров. |
| Данные включают результирующий набор и потоковые выходные параметры | SQL_SUCCESS | Извлеките результирующий набор с SQLBindCol и SQLGetData. Вызовите SQLMoreResults, чтобы начать обработку потоковых выходных параметров. Он должен возвращать SQL_PARAM_DATA_AVAILABLE. Используйте SQLParamData и SQLGetData для получения потоковых выходных параметров. |
| Данные включают предупреждающее сообщение и потоковые выходные параметры | SQL_SUCCESS_WITH_INFO | Используйте SQLGetDiagRec и SQLGetDiagField для обработки предупреждений. Вызовите SQLMoreResults, чтобы начать обработку потоковых выходных параметров. Он должен возвращать SQL_PARAM_DATA_AVAILABLE. Используйте SQLParamData и SQLGetData для получения потоковых выходных параметров. |
| Данные включают предупреждение, результирующий набор и потоковые выходные параметры | SQL_SUCCESS_WITH_INFO | Используйте SQLGetDiagRec и SQLGetDiagField для обработки предупреждений. Затем вызовите SQLMoreResults, чтобы начать обработку результирующего набора. Извлеките набор результатов с SQLBindCol и SQLGetData. Вызовите SQLMoreResults, чтобы начать обработку потоковых выходных параметров. SQLMoreResults должен возвращать SQL_PARAM_DATA_AVAILABLE. Используйте SQLParamData и SQLGetData для получения потоковых выходных параметров. |
| Запрос с входными параметрами DAE, например параметром потокового ввода и вывода (DAE) | SQL NEED_DATA |
Вызовите SQLParamData и SQLPutData для отправки входных данных параметров DAE. После обработки всех входных параметров DAE SQLParamData может возвращать любой возвращаемый код, возвращаемый SQLExecute и SQLExecDirect . Затем можно применить случаи в этой таблице. Если код возврата равен SQL_PARAM_DATA_AVAILABLE, доступны потоковые выходные параметры. Приложение должно снова вызвать SQLParamData , чтобы получить маркер для потокового выходного параметра, как описано в первой строке этой таблицы. Если возвращаемый код SQL_SUCCESS, это означает, что либо существует результирующий набор для обработки, либо обработка завершена. Если код возврата SQL_SUCCESS_WITH_INFO, есть предупреждающие сообщения для обработки. |
После SQLExecute, SQLExecDirect или SQLMoreResults возвращает SQL_PARAM_DATA_AVAILABLE, произойдет ошибка последовательности функций, если приложение вызовет функцию, которая не находится в следующем списке:
SQLAllocHandle / SQLAllocHandleStd
SQLDataSources / SQLDrivers
SQLGetInfo / SQLGetFunctions
SQLGetConnectAttr / SQLGetEnvAttr / SQLGetDescField / SQLGetDescRec
SQLNumParams
SQLDescribeParam
SQLNativeSql
SQLParamData
SQLMoreResults
SQLGetDiagField / SQLGetDiagRec
SQLCancel
SQLCancelHandle (с дескриптором инструкций)
SQLFreeStmt (с параметром = SQL_CLOSE, SQL_DROP или SQL_UNBIND)
SQLCloseCursor
SQLDisconnect
SQLFreeHandle (где HandleType = SQL_HANDLE_STMT)
SQLGetStmtAttr
Приложения по-прежнему могут использовать SQLSetDescField или SQLSetDescRec для задания сведений о привязке. Сопоставление полей не изменится. Однако поля внутри дескриптора могут возвращать новые значения. Например, SQL_DESC_PARAMETER_TYPE может возвращать SQL_PARAM_INPUT_OUTPUT_STREAM или SQL_PARAM_OUTPUT_STREAM.
Сценарий использования: извлечение изображения по частям из результирующего набора
SQLGetData можно использовать для получения данных в частях, когда хранимая процедура возвращает результирующий набор, содержащий одну строку метаданных об изображении, и изображение возвращается в большом выходном параметре.
// CREATE PROCEDURE SP_TestOutputPara
// @ID_of_picture as int,
// @Picture as varbinary(max) out
// AS
// output the image data through streamed output parameter
// GO
BOOL displayPicture(SQLUINTEGER idOfPicture, SQLHSTMT hstmt) {
SQLLEN lengthOfPicture; // The actual length of the picture.
BYTE smallBuffer[100]; // A very small buffer.
SQLRETURN retcode, retcode2;
// Bind the first parameter (input parameter)
SQLBindParameter(
hstmt,
1, // The first parameter.
SQL_PARAM_INPUT, // Input parameter: The ID_of_picture.
SQL_C_ULONG, // The C Data Type.
SQL_INTEGER, // The SQL Data Type.
0, // ColumnSize is ignored for integer.
0, // DecimalDigits is ignored for integer.
&idOfPicture, // The Address of the buffer for the input parameter.
0, // BufferLength is ignored for integer.
NULL); // This is ignored for integer.
// Bind the streamed output parameter.
SQLBindParameter(
hstmt,
2, // The second parameter.
SQL_PARAM_OUTPUT_STREAM, // A streamed output parameter.
SQL_C_BINARY, // The C Data Type.
SQL_VARBINARY, // The SQL Data Type.
0, // ColumnSize: The maximum size of varbinary(max).
0, // DecimalDigits is ignored for binary type.
(SQLPOINTER)2, // ParameterValuePtr: An application-defined
// token (this will be returned from SQLParamData).
// In this example, we used the ordinal
// of the parameter.
0, // BufferLength is ignored for streamed output parameters.
&lengthOfPicture); // StrLen_or_IndPtr: The status variable returned.
retcode = SQLPrepare(hstmt, L"{call SP_TestOutputPara(?, ?)}", SQL_NTS);
if ( retcode == SQL_ERROR )
return FALSE;
retcode = SQLExecute(hstmt);
if ( retcode == SQL_ERROR )
return FALSE;
// Assume that the retrieved picture exists. Use SQLBindCol or SQLGetData to retrieve the result-set.
// Process the result set and move to the streamed output parameters.
retcode = SQLMoreResults( hstmt );
// SQLGetData retrieves and displays the picture in parts.
// The streamed output parameter is available.
while (retcode == SQL_PARAM_DATA_AVAILABLE) {
SQLPOINTER token; // Output by SQLParamData.
SQLLEN cbLeft; // #bytes remained
retcode = SQLParamData(hstmt, &token); // returned token is 2 (according to the binding)
if ( retcode == SQL_PARAM_DATA_AVAILABLE ) {
// A do-while loop retrieves the picture in parts.
do {
retcode2 = SQLGetData(
hstmt,
(UWORD) token, // the value of the token is the ordinal.
SQL_C_BINARY, // The C-type.
smallBuffer, // A small buffer.
sizeof(smallBuffer), // The size of the buffer.
&cbLeft); // How much data we can get.
}
while ( retcode2 == SQL_SUCCESS_WITH_INFO );
}
}
return TRUE;
}
Сценарий использования: отправка и получение большого объекта в виде потока входных и выходных параметров
SQLGetData можно использовать для получения и отправки данных в части, когда хранимая процедура передает большой объект в качестве входного или выходного параметра, потоковую передачу значения в базу данных и из нее. Вам не нужно хранить все данные в памяти.
// CREATE PROCEDURE SP_TestInOut
// @picture as varbinary(max) out
// AS
// output the image data through output parameter
// go
BOOL displaySimilarPicture(BYTE* image, ULONG lengthOfImage, SQLHSTMT hstmt) {
BYTE smallBuffer[100]; // A very small buffer.
SQLRETURN retcode, retcode2;
SQLLEN statusOfPicture;
// First bind the parameters, before preparing the statement that binds the output streamed parameter.
SQLBindParameter(
hstmt,
1, // The first parameter.
SQL_PARAM_INPUT_OUTPUT_STREAM, // I/O-streamed parameter: The Picture.
SQL_C_BINARY, // The C Data Type.
SQL_VARBINARY, // The SQL Data Type.
0, // ColumnSize: The maximum size of varbinary(max).
0, // DecimalDigits is ignored.
(SQLPOINTER)1, // An application defined token.
0, // BufferLength is ignored for streamed I/O parameters.
&statusOfPicture); // The status variable.
statusOfPicture = SQL_DATA_AT_EXEC; // Input data in parts (DAE parameter at input).
retcode = SQLPrepare(hstmt, L"{call SP_TestInOut(?) }", SQL_NTS);
if ( retcode == SQL_ERROR )
return FALSE;
// Execute the statement.
retcode = SQLExecute(hstmt);
if ( retcode == SQL_ERROR )
return FALSE;
if ( retcode == SQL_NEED_DATA ) {
// Use SQLParamData to loop through DAE input parameters. For
// each, use SQLPutData to send the data to database in parts.
// This example uses an I/O parameter with streamed output.
// Therefore, the last call to SQLParamData should return
// SQL_PARAM_DATA_AVAILABLE to indicate the end of the input phrase
// and report that a streamed output parameter is available.
// Assume retcode is set to the return value of the last call to
// SQLParamData, which is equal to SQL_PARAM_DATA_AVAILABLE.
}
// Start processing the streamed output parameters.
while ( retcode == SQL_PARAM_DATA_AVAILABLE ) {
SQLPOINTER token; // Output by SQLParamData.
SQLLEN cbLeft; // #bytes remained
retcode = SQLParamData(hstmt, &token);
if ( retcode == SQL_PARAM_DATA_AVAILABLE ) {
do {
retcode2 = SQLGetData(
hstmt,
(UWORD) token, // the value of the token is the ordinal.
SQL_C_BINARY, // The C-type.
smallBuffer, // A small buffer.
sizeof(smallBuffer), // The size of the buffer.
&cbLeft); // How much data we can get.
}
while ( retcode2 == SQL_SUCCESS_WITH_INFO );
}
}
return TRUE;
}