Привязка массивов параметров
Приложения, использующие массивы параметров, привязывают массивы к параметрам в инструкции SQL. Существует два стиля привязки:
Привязка массива к каждому параметру. Каждая структура данных (массив) содержит все данные для одного параметра. Это называется привязкой со столбцами, так как она привязывает столбец значений для одного параметра.
Определите структуру для хранения данных параметров для всего набора параметров и привязки массива этих структур. Каждая структура данных содержит данные для одной инструкции SQL. Это называется строковой привязкой , так как она привязывает строку параметров.
Когда приложение привязывает отдельные переменные к параметрам, он вызывает SQLBindParameter для привязки массивов к параметрам. Единственное различие заключается в том, что переданные адреса — это адреса массива, а не адреса с одной переменной. Приложение задает атрибут инструкции SQL_ATTR_PARAM_BIND_TYPE, чтобы указать, используется ли она с помощью столбцов (по умолчанию) или привязки по строкам. Независимо от того, следует ли использовать привязку со столбцами или строками, в значительной степени является вопросом предпочтения приложения. В зависимости от того, как процессор обращается к памяти, может быть быстрее привязка по строкам. Однако разница, скорее всего, будет незначительной, за исключением очень большого количества строк параметров.
Привязка на уровне столбца
При использовании привязки со столбцами приложение привязывает один или два массива к каждому параметру, для которого должны быть предоставлены данные. Первый массив содержит значения данных, а второй массив содержит буферы длины или индикатора. Каждый массив содержит столько элементов, сколько значений для параметра.
Привязка по умолчанию — это привязка по умолчанию. Приложение также может измениться с привязки по строкам на привязку со столбцами, задав атрибут инструкции SQL_ATTR_PARAM_BIND_TYPE. На следующем рисунке показано, как работает привязка со столбцами.
Например, следующий код привязывает массивы 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;
}
}
Привязка на уровне строки
При использовании привязки по строкам приложение определяет структуру для каждого набора параметров. Структура содержит один или два элемента для каждого параметра. Первый элемент содержит значение параметра, а второй элемент содержит буфер длины или индикатора. Затем приложение выделяет массив этих структур, который содержит столько элементов, сколько значений для каждого параметра.
Приложение объявляет размер структуры драйверу с атрибутом оператора SQL_ATTR_PARAM_BIND_TYPE. Приложение привязывает адреса параметров в первой структуре массива. Таким образом, драйвер может вычислить адрес данных для определенной строки и столбца как
Address = Bound Address + ((Row Number - 1) * Structure Size) + Offset
Где строки нумеруются от 1 до размера набора параметров. Смещение, если определено, — это значение, указываемое атрибутом оператора SQL_ATTR_PARAM_BIND_OFFSET_PTR. На следующем рисунке показано, как работает привязка по строкам. Параметры можно поместить в структуру в любом порядке, но отображаются в последовательном порядке для ясности.
Следующий код создает структуру со элементами для значений, которые будут храниться в столбцах 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;
}