SQLGetData を使用した出力パラメーターの取得
ODBC 3.8 より前のバージョンでは、アプリはバインドされた出力バッファーを持つクエリの出力パラメーターのみを取得できました。 ただし、パラメーター値のサイズが非常に大きい場合 (たとえば、大きな画像) では、非常に大きなバッファーを割り当てることは困難です。 ODBC 3.8 では、パーツ内の出力パラメーターを取得する新しい方法が導入されています。 アプリから小さなバッファーで SQLGetData を複数回呼び出すれば、大きなパラメーター値を取得できます。 これは、大きな列データを取得するのと似ています。
部分で取得する出力パラメーターまたは入力/出力パラメーターをバインドするには、InputOutputType 引数を SQL_PARAM_OUTPUT_STREAM または SQL_PARAM_INPUT_OUTPUT_STREAM に設定して SQLBindParameter を呼び出します。 SQL_PARAM_INPUT_OUTPUT_STREAMでは、アプリは SQLPutData を使用してパラメーターにデータを入力し、SQLGetData を使用して出力パラメーターを取得できます。 入力データは、事前に割り当てられたバッファーにバインドするのではなく、SQLPutData を使用して、実行時データ (DAE) 形式である必要があります。
この機能は、ODBC 3.8 アプリまたは再コンパイルされた ODBC 3.x および ODBC 2.x アプリで使用できます。これらのアプリには、SQLGetData と ODBC 3.8 ドライバー マネージャーを使用した出力パラメーターの取得をサポートする ODBC 3.8 ドライバーが必要です。 前のアプリで新しい ODBC 機能を使用できるようにする方法については、「互換性マトリックス」を参照してください。
使用例
たとえば、ストアド プロシージャ {CALL sp_f(?,?)} を実行すると、両方のパラメーターがSQL_PARAM_OUTPUT_STREAMとしてバインドされ、ストアド プロシージャは結果セットを返しません (このトピックの後半では、より複雑なシナリオが見つかります)。
各パラメーターについて、InputOutputType を SQL_PARAM_OUTPUT_STREAM に設定し、ParameterValuePtr をトークンに設定して SQLBindParameter を呼び出します (パラメーター番号、データへのポインター、入力パラメーターのバインドにアプリが使用する構造体へのポインターなど)。 この例では、パラメーターの序数をトークンとして使用します。
SQLExecDirect または SQLExecute を使用してクエリを実行します。 SQL_PARAM_DATA_AVAILABLE が返され、取得に使用できるストリーム出力パラメーターがあることを示します。
SQLParamData を呼び出して、取得可能なパラメーターを取得します。 SQLParamData は、SQLBindParameter で設定されている最初の使用可能なパラメーターのトークンを使用してSQL_PARAM_DATA_AVAILABLEを返します (手順 1)。 トークンは、ValuePtrPtr が指すバッファーで返されます。
引数 Col_or_Param_Num をパラメーター序数に設定して SQLGetData を呼び出して、使用可能な最初のパラメーターのデータを取得します。 SQLGetData が SQL_SUCCESS_WITH_INFO と SQLState 01004 を返し (データが切り捨てられた)、型がクライアントとサーバーの両方で可変長である場合は、最初に使用可能なパラメーターから取得するデータが増えます。 SQLGetData は、別の SQLState で SQL_SUCCESS または SQL_SUCCESS_WITH_INFO を返すまで引き続き呼び出すことができます。
手順 3 と手順 4 を繰り返して、現在のパラメーターを取得します。
SQLParamData をもう一度呼び出します。 SQL_PARAM_DATA_AVAILABLE を除く何かを返す場合、取得するストリーミング パラメーター データはこれ以上なく、戻りコードは実行される次のステートメントのリターン コードになります。
SQLMoreResults を呼び出して、SQL_NO_DATAを返すまで、次のパラメーター セットを処理します。 ステートメント属性 SQL_ATTR_PARAMSET_SIZE が 1 に設定されている場合、SQLMoreResults は例の SQL_NO_DATA を返します。 それ以外の場合、 SQLMoreResults はSQL_PARAM_DATA_AVAILABLEを返して、次に取得するパラメーターのセットで使用できるストリーム出力パラメーターがあることを示します。
DAE 入力パラメーターと同様に、SQLBindParameter (手順 1) の引数 ParameterValuePtr で使用されるトークンは、パラメーターの序数と、必要に応じてより多くのアプリ固有の情報を含むアプリのデータ構造を指すポインターにすることができます。
返されるストリーム出力または入力/出力パラメーターの順序はドライバー固有であり、クエリで指定された順序と常に同じとは限りません。
手順 4 でアプリが SQLGetData を呼び出さない場合、パラメーター値は破棄されます。 同様に、すべてのパラメーター値が SQLGetData によって読み取られた前にアプリが SQLParamData を呼び出した場合、値の残りの部分は破棄され、アプリは次のパラメーターを処理できます。
すべてのストリーム出力パラメーターが処理される前にアプリが SQLMoreResults を呼び出した場合 (SQLParamData は引き続き SQL_PARAM_DATA_AVAILABLE を返します)、残りのパラメーターはすべて破棄されます。 同様に、すべてのパラメーター値が SQLGetData によって読み取られた前にアプリが SQLMoreResults を呼び出した場合、残りの値と残りのすべてのパラメーターは破棄され、アプリは次のパラメーター セットの処理を続行できます。
アプリでは、SQLBindParameter と SQLGetData の両方で C データ型を指定できることにご注意してください。 SQLGetData で指定された C データ型は、SQLGetData で指定された C データ型がSQL_APD_TYPEされていない限り、SQLBindParameter で指定された C データ型をオーバーライドします。
ストリーム出力パラメーターは、出力パラメーターのデータ型が BLOB 型の場合に便利ですが、この機能は任意のデータ型でも使用できます。 ストリーム出力パラメーターでサポートされるデータ型は、ドライバーで指定されます。
処理するパラメーター SQL_PARAM_INPUT_OUTPUT_STREAM がある場合、 SQLExecute または SQLExecDirect は最初に SQL_NEED_DATA を返します。 アプリは、SQLParamData と SQLPutData を呼び出して DAE パラメーター データを送信できます。 すべての DAE 入力パラメーターが処理されると、 SQLParamData はストリーム出力パラメーターが使用可能であることを示す SQL_PARAM_DATA_AVAILABLE を返します。
ストリーム出力パラメーターとバインドされた出力パラメーターが処理される場合、ドライバーは出力パラメーターの処理順序を決定します。 そのため、出力パラメーターがバッファーにバインドされている場合 (SQLBindParameter パラメーター InputOutputType が SQL_PARAM_INPUT_OUTPUT または SQL_PARAM_OUTPUT に設定されている場合)、SQLParamData がSQL_SUCCESSまたはSQL_SUCCESS_WITH_INFOを返すまで、バッファーに値が設定されない可能性があります。 アプリは、SQLParamData がすべてのストリーミング出力パラメーターの処理後に SQL_SUCCESS または SQL_SUCCESS_WITH_INFO を返した後にのみ、バインドされたバッファーを読み取る必要があります。
データ ソースは、ストリーム出力パラメーターに加えて、警告と結果セットを返すことができます。 一般に、警告と結果セットは、SQLMoreResults を呼び出すれば、ストリーム出力パラメーターとは別に処理されます。 ストリーム出力パラメーターを処理する前に、警告と結果セットを処理します。
次の表では、サーバーに送信される 1 つのコマンドのさまざまなシナリオと、アプリの動作方法について説明します。
シナリオ | 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 を使用すると、ストアド プロシージャがイメージに関する 1 行のメタデータを含む結果セットを返し、イメージが大きな出力パラメーターで返される場合に、一部のデータを取得できます。
// 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;
}