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としてバインドされ、ストアド プロシージャは結果セットを返しません (このトピックの後半では、より複雑なシナリオが見つかります)。

  1. 各パラメーターについて、InputOutputType を SQL_PARAM_OUTPUT_STREAM に設定し、ParameterValuePtr をトークンに設定して SQLBindParameter を呼び出します (パラメーター番号、データへのポインター、入力パラメーターのバインドにアプリが使用する構造体へのポインターなど)。 この例では、パラメーターの序数をトークンとして使用します。

  2. SQLExecDirect または SQLExecute を使用してクエリを実行します。 SQL_PARAM_DATA_AVAILABLE が返され、取得に使用できるストリーム出力パラメーターがあることを示します。

  3. SQLParamData を呼び出して、取得可能なパラメーターを取得します。 SQLParamData は、SQLBindParameter で設定されている最初の使用可能なパラメーターのトークンを使用してSQL_PARAM_DATA_AVAILABLEを返します (手順 1)。 トークンは、ValuePtrPtr が指すバッファーで返されます。

  4. 引数 Col_or_Param_Num をパラメーター序数に設定して SQLGetData を呼び出して、使用可能な最初のパラメーターのデータを取得します。 SQLGetData が SQL_SUCCESS_WITH_INFO と SQLState 01004 を返し (データが切り捨てられた)、型がクライアントとサーバーの両方で可変長である場合は、最初に使用可能なパラメーターから取得するデータが増えます。 SQLGetData は、別の SQLState で SQL_SUCCESS または SQL_SUCCESS_WITH_INFO を返すまで引き続き呼び出すことができます。

  5. 手順 3 と手順 4 を繰り返して、現在のパラメーターを取得します。

  6. SQLParamData をもう一度呼び出します。 SQL_PARAM_DATA_AVAILABLE を除く何かを返す場合、取得するストリーミング パラメーター データはこれ以上なく、戻りコードは実行される次のステートメントのリターン コードになります。

  7. 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 を呼び出した場合、残りの値と残りのすべてのパラメーターは破棄され、アプリは次のパラメーター セットの処理を続行できます。

アプリでは、SQLBindParameterSQLGetData の両方で C データ型を指定できることにご注意してください。 SQLGetData で指定された C データ型は、SQLGetData指定された C データ型がSQL_APD_TYPEされていない限り、SQLBindParameter指定された C データ型をオーバーライドします。

ストリーム出力パラメーターは、出力パラメーターのデータ型が BLOB 型の場合に便利ですが、この機能は任意のデータ型でも使用できます。 ストリーム出力パラメーターでサポートされるデータ型は、ドライバーで指定されます。

処理するパラメーター SQL_PARAM_INPUT_OUTPUT_STREAM がある場合、 SQLExecute または SQLExecDirect は最初に SQL_NEED_DATA を返します。 アプリは、SQLParamDataSQLPutData を呼び出して 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 SQLParamDataSQLGetData を使用して、ストリーム出力パラメーターを取得します。
データには、結果セットとストリーム出力パラメーターが含まれます SQL_SUCCESS SQLBindColSQLGetData を使用して結果セットを取得します。

SQLMoreResults を呼び出して、ストリーム出力パラメーターの処理を開始します。 SQL_PARAM_DATA_AVAILABLEを返す必要があります。

SQLParamDataSQLGetData を使用して、ストリーム出力パラメーターを取得します。
データには警告メッセージとストリーム出力パラメーターが含まれます SQL_SUCCESS_WITH_INFO 警告メッセージを処理するには、SQLGetDiagRecSQLGetDiagField を使用します。

SQLMoreResults を呼び出して、ストリーム出力パラメーターの処理を開始します。 SQL_PARAM_DATA_AVAILABLEを返す必要があります。

SQLParamDataSQLGetData を使用して、ストリーム出力パラメーターを取得します。
データには、警告メッセージ、結果セット、およびストリーム出力パラメーターが含まれます SQL_SUCCESS_WITH_INFO 警告メッセージを処理するには、SQLGetDiagRecSQLGetDiagField を使用します。 次に、SQLMoreResults を呼び出して、結果セットの処理を開始します。

SQLBindColSQLGetData を使用して結果セットを取得します。

SQLMoreResults を呼び出して、ストリーム出力パラメーターの処理を開始します。 SQLMoreResults は SQL_PARAM_DATA_AVAILABLE を返す必要があります。

SQLParamDataSQLGetData を使用して、ストリーム出力パラメーターを取得します。
DAE 入力パラメーターを使用したクエリ (ストリーム入力/出力 (DAE) パラメーターなど) SQL NEED_DATA SQLParamDataSQLPutData を呼び出して、DAE 入力パラメーター データを送信します。

すべての DAE 入力パラメーターが処理されると、SQLParamDataSQLExecuteSQLExecDirect が返すことができるすべてのリターン コードを返すことができます。 その後、この表のケースを適用できます。

戻りコードがSQL_PARAM_DATA_AVAILABLEされている場合は、ストリーム出力パラメーターを使用できます。 この表の最初の行で説明されているように、アプリは SQLParamData をもう一度呼び出して、ストリーム出力パラメーターのトークンを取得する必要があります。

戻りコードがSQL_SUCCESS場合は、処理する結果セットがあるか、処理が完了しています。

戻りコードがSQL_SUCCESS_WITH_INFOされている場合は、処理する警告メッセージがあります。

SQLExecuteSQLExecDirect、または 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;  
}  

参照

ステートメント パラメーター