パラメーターのバインディング配列

パラメーターの配列を使用するアプリケーションは、SQL ステートメントのパラメーターに配列をバインドします。 次の 2 つのバインド スタイルがあります。

  • 配列を各パラメーターにバインドします。 各データ構造 (配列) には、1 つのパラメーターのすべてのデータが含まれています。 これは、1 つのパラメーターの値の列をバインドするため、列ごとのバインドと呼ばれます。

  • パラメーターのセット全体のパラメーター データを保持し、これらの構造体の配列をバインドする構造体を定義します。 各データ構造には、1 つの SQL ステートメントのデータが含まれています。 これは、パラメーターの行をバインドするため、行ごとのバインドと呼ばれます。

アプリケーションは、単一の変数をパラメーターにバインドするときと同様に、SQLBindParameter を呼び出して配列をパラメーターにバインドします。 唯一の違いは、渡されるアドレスが配列アドレスであり、単一変数のアドレスではないことです。 アプリケーションは、SQL_ATTR_PARAM_BIND_TYPE ステートメント属性を設定して、列方向 (既定) または行方向のバインディングのどちらを使用するかを指定します。 列方向バインディングと行方向バインディングのどちらを使用するかは、主にアプリケーションの優先の問題です。 プロセッサがメモリにアクセスする方法によっては、行方向のバインドが高速になる場合があります。 ただし、パラメーターの行数が非常に多い場合を除き、差はごくわずかである可能性があります。

列方向のバインド

列方向のバインドを使用する場合、アプリケーションはデータを提供する各パラメーターに 1 つまたは 2 つの配列をバインドします。 最初の配列はデータ値を保持し、2 番目の配列は長さ/インジケーター バッファーを保持します。 各配列には、パラメーターの値と同じ数の要素が含まれています。

既定では、列方向のバインドが使用されます。 また、SQL_ATTR_PARAM_BIND_TYPE ステートメント属性を設定することで、アプリケーションを行方向のバインドから列方向のバインドに変更することもできます。 次の図は、列方向のバインドのしくみを示しています。

Shows how column-wise binding works

たとえば、次のコードでは、10 個の要素配列を PartID、Description、Price 列のパラメーターにバインドし、ステートメントを実行して 10 行を挿入します。 列方向のバインドを使用します。

#define DESC_LEN 51  
#define ARRAY_SIZE 10  
  
SQLCHAR *      Statement = "INSERT INTO Parts (PartID, Description,  Price) "  
                                                "VALUES (?, ?, ?)";  
SQLUINTEGER    PartIDArray[ARRAY_SIZE];  
SQLCHAR        DescArray[ARRAY_SIZE][DESC_LEN];  
SQLREAL        PriceArray[ARRAY_SIZE];  
SQLINTEGER     PartIDIndArray[ARRAY_SIZE], DescLenOrIndArray[ARRAY_SIZE],  
               PriceIndArray[ARRAY_SIZE];  
SQLUSMALLINT   i, ParamStatusArray[ARRAY_SIZE];  
SQLULEN ParamsProcessed;  
  
memset(DescLenOrIndArray, 0, sizeof(DescLenOrIndArray));  
memset(PartIDIndArray, 0, sizeof(PartIDIndArray));  
memset(PriceIndArray, 0, sizeof(PriceIndArray));  
  
// Set the SQL_ATTR_PARAM_BIND_TYPE statement attribute to use  
// column-wise binding.  
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, 0);  
  
// Specify the number of elements in each parameter array.  
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMSET_SIZE, ARRAY_SIZE, 0);  
  
// Specify an array in which to return the status of each set of  
// parameters.  
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAM_STATUS_PTR, ParamStatusArray, 0);  
  
// Specify an SQLUINTEGER value in which to return the number of sets of  
// parameters processed.  
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &ParamsProcessed, 0);  
  
// Bind the parameters in column-wise fashion.  
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0,  
                  PartIDArray, 0, PartIDIndArray);  
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, DESC_LEN - 1, 0,  
                  DescArray, DESC_LEN, DescLenOrIndArray);  
SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_REAL, 7, 0,  
                  PriceArray, 0, PriceIndArray);  
  
// Set part ID, description, and price.  
for (i = 0; i < ARRAY_SIZE; i++) {  
   GetNewValues(&PartIDArray[i], DescArray[i], &PriceArray[i]);  
   PartIDIndArray[i] = 0;  
   DescLenOrIndArray[i] = SQL_NTS;  
   PriceIndArray[i] = 0;  
}  
  
// Execute the statement.  
SQLExecDirect(hstmt, Statement, SQL_NTS);  
  
// Check to see which sets of parameters were processed successfully.  
for (i = 0; i < ParamsProcessed; i++) {  
   printf("Parameter Set  Status\n");  
   printf("-------------  -------------\n");  
   switch (ParamStatusArray[i]) {  
      case SQL_PARAM_SUCCESS:  
      case SQL_PARAM_SUCCESS_WITH_INFO:  
         printf("%13d  Success\n", i);  
         break;  
  
      case SQL_PARAM_ERROR:  
         printf("%13d  Error\n", i);  
         break;  
  
      case SQL_PARAM_UNUSED:  
         printf("%13d  Not processed\n", i);  
         break;  
  
      case SQL_PARAM_DIAG_UNAVAILABLE:  
         printf("%13d  Unknown\n", i);  
         break;  
  
   }  
}  

行方向のバインド

行方向のバインドを使用する場合、アプリケーションはパラメーターのセットごとに構造体を定義します。 構造体には、各パラメーターの 1 つまたは 2 つの要素が含まれています。 最初の要素はパラメーター値を保持し、2 番目の要素は長さ/インジケーター バッファーを保持します。 その後、アプリケーションは、各パラメーターの値と同じ数の要素を含む、これらの構造体の配列を割り当てます。

アプリケーションは、SQL_ATTR_PARAM_BIND_TYPE ステートメント属性を使用して、ドライバーに構造体のサイズを宣言します。 アプリケーションは、配列の最初の構造体のパラメーターのアドレスをバインドします。 したがって、ドライバーは、特定の行と列のデータのアドレスを次のように計算できます。

Address = Bound Address + ((Row Number - 1) * Structure Size) + Offset  

行の番号は 1 からパラメーター セットのサイズまでです。 オフセット (定義されている場合) は、SQL_ATTR_PARAM_BIND_OFFSET_PTR ステートメント属性によって指される値です。 次の図は、行方向のバインドのしくみを示しています。 パラメーターは任意の順序で構造体に配置できますが、わかりやすくするために順番に表示されます。

Shows how row-wise binding works

次のコードでは、PartID、Description、Price 列に格納する値の要素を含む構造体を作成します。 次に、これらの構造体の 10 要素配列を割り当て、行方向のバインドを使用して、PartID、Description、Price 列のパラメーターにバインドします。 次に、ステートメントを実行して 10 行を挿入します。

#define DESC_LEN 51  
#define ARRAY_SIZE 10  
  
typedef tagPartStruct {  
   SQLREAL       Price;  
   SQLUINTEGER   PartID;  
   SQLCHAR       Desc[DESC_LEN];  
   SQLINTEGER    PriceInd;  
   SQLINTEGER    PartIDInd;  
   SQLINTEGER    DescLenOrInd;  
} PartStruct;  
  
PartStruct PartArray[ARRAY_SIZE];  
SQLCHAR *      Statement = "INSERT INTO Parts (PartID, Description,  
                Price) "  
               "VALUES (?, ?, ?)";  
SQLUSMALLINT   i, ParamStatusArray[ARRAY_SIZE];  
SQLULEN ParamsProcessed;  
  
// Set the SQL_ATTR_PARAM_BIND_TYPE statement attribute to use  
// column-wise binding.  
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAM_BIND_TYPE, sizeof(PartStruct), 0);  
  
// Specify the number of elements in each parameter array.  
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMSET_SIZE, ARRAY_SIZE, 0);  
  
// Specify an array in which to return the status of each set of  
// parameters.  
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAM_STATUS_PTR, ParamStatusArray, 0);  
  
// Specify an SQLUINTEGER value in which to return the number of sets of  
// parameters processed.  
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &ParamsProcessed, 0);  
  
// Bind the parameters in row-wise fashion.  
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0,  
                  &PartArray[0].PartID, 0, &PartArray[0].PartIDInd);  
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, DESC_LEN - 1, 0,  
                  PartArray[0].Desc, DESC_LEN, &PartArray[0].DescLenOrInd);  
SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_REAL, 7, 0,  
                  &PartArray[0].Price, 0, &PartArray[0].PriceInd);  
  
// Set part ID, description, and price.  
for (i = 0; i < ARRAY_SIZE; i++) {  
   GetNewValues(&PartArray[i].PartID, PartArray[i].Desc, &PartArray[i].Price);  
   PartArray[0].PartIDInd = 0;  
   PartArray[0].DescLenOrInd = SQL_NTS;  
   PartArray[0].PriceInd = 0;  
}  
  
// Execute the statement.  
SQLExecDirect(hstmt, Statement, SQL_NTS);  
  
// Check to see which sets of parameters were processed successfully.  
for (i = 0; i < ParamsProcessed; i++) {  
   printf("Parameter Set  Status\n");  
   printf("-------------  -------------\n");  
   switch (ParamStatusArray[i]) {  
      case SQL_PARAM_SUCCESS:  
      case SQL_PARAM_SUCCESS_WITH_INFO:  
         printf("%13d  Success\n", i);  
         break;  
  
      case SQL_PARAM_ERROR:  
         printf("%13d  Error\n", i);  
         break;  
  
      case SQL_PARAM_UNUSED:  
         printf("%13d  Not processed\n", i);  
         break;  
  
      case SQL_PARAM_DIAG_UNAVAILABLE:  
         printf("%13d  Unknown\n", i);  
         break;  
  
   }