繫結參數陣列
應用程式使用參數的陣列與 SQL 陳述式中的參數繫結。 兩種繫結方式:
繫結陣列與每個參數。 每個資料結構 (陣列) 都包含單一參數的所有資料。 這稱為資料行式繫結,因為陣列會繫結單一參數值的資料行。
定義結構保存整個參數集的參數資料,並繫結這些結構的陣列。 每個資料結構都包含單一 SQL 陳述式的資料。 這稱為資料列式繫結,因為陣列會繫結參數的資料列。
如同繫結單一變數與參數時,應用程式會呼叫 SQLBindParameter 繫結陣列與參數。 唯一的差異在於傳遞的位址是陣列位址,而不是單一變數位址。 應用程式會設定 SQL_ATTR_PARAM_BIND_TYPE 陳述式屬性,並指定屬性使用資料行式 (預設) 或資料列式繫結。 無論使用資料行式或資料列式繫結,重點都是應用程式喜好設定。 根據處理器存取記憶體的方式,資料列式繫結可能較快。 但差異可能不明顯,除非是非常大量的參數資料列。
資料行取向的繫結
使用資料行式繫結時,應用程式會繫結將一或兩個陣列與提供資料的每個參數。 第一個陣列會保存資料值,而第二個陣列保存長度/指標緩衝區。 每個陣列包含與參數值數量相同的元素。
預設是資料行式繫結。 您也可以設定 SQL_ATTR_PARAM_BIND_TYPE 陳述式屬性,將應用程式從資料列式繫結變更為資料行式繫結。 下圖顯示資料行式繫結的運作方式。
例如,下列程式碼會繫結 10 個元素陣列與組件識別碼、描述和價格資料行的參數,然後執行陳述式插入 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;
}
}
資料列取向的繫結
使用資料列式繫結時,應用程式會為每個參數集定義結構。 結構包含每個參數的一或兩個元素。 第一個元素會保存參數值,而第二個元素保存長度/指標緩衝區。 然後,應用程式會配置這些結構的陣列,包含與每個參數值數量相同的元素。
應用程式會使用 SQL_ATTR_PARAM_BIND_TYPE 陳述式屬性,向驅動程式宣告結構的大小。 應用程式會繫結陣列第一個結構中的參數位址。 因此,驅動程式可基於資料列從 1 到參數集大小的編號
Address = Bound Address + ((Row Number - 1) * Structure Size) + Offset
計算出特定資料列和資料行的資料位址。 位移 (若有定義) 是 SQL_ATTR_PARAM_BIND_OFFSET_PTR 陳述式屬性指向的值。 下圖顯示資料列式繫結的運作方式。 參數可以用任何順序放置於結構,但為求清楚明瞭,參數會以順序顯示。
下列程式碼會建立結構,並包含要儲存在組件識別碼、描述和價格資料行中的值元素。 然後,程式碼會配置這些結構的 10 個元素陣列,並使用資料列式繫結,繫結陣列與組件識別碼、描述和價格資料行的參數。 然後執行陳述式插入 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;
}