Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
До 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;
}