Associazione delle matrici di parametri
Le applicazioni che usano matrici di parametri associano le matrici ai parametri nell'istruzione SQL. Esistono due stili di associazione:
Associare una matrice a ogni parametro. Ogni struttura di dati (matrice) contiene tutti i dati di un singolo parametro. Questa operazione è denominata associazione a livello di colonna perché associa una colonna di valori per un singolo parametro.
Definire una struttura per contenere i dati dei parametri di un intero set di parametri e associare una matrice di queste strutture. Ogni struttura di dati contiene i dati di una singola istruzione SQL. Si tratta di un'associazione a livello di riga perché associa una riga di parametri.
Succede lo stesso quando l'applicazione associa singole variabili ai parametri e chiama SQLBindParameter per associare matrici ai parametri. L'unica differenza è che gli indirizzi passati sono indirizzi di matrice, non indirizzi di variabile singola. L'applicazione imposta l'attributo di istruzione SQL_ATTR_PARAM_BIND_TYPE per specificare se usa l'associazione a livello di colonna (impostazione predefinita) o di riga. L’utilizzo dell'associazione a livello di colonna o di riga è principalmente una questione di preferenze dell'applicazione. A seconda del modo in cui il processore accede alla memoria, l'associazione a livello di riga potrebbe essere più veloce. Tuttavia, è probabile che la differenza sia trascurabile, ad eccezione dei casi con un numero molto elevato di righe di parametri.
Associazione per colonna
Quando si usa l'associazione a livello di colonna, un'applicazione associa una o due matrici a ogni parametro per cui vengono specificati i dati. La prima matrice contiene i valori dei dati e la seconda matrice contiene buffer di lunghezza/indicatore. Ogni matrice contiene tanti elementi quanti sono i valori del parametro.
L'associazione per colonna è l'impostazione predefinita. L'applicazione può anche passare dall'associazione a livello di riga all'associazione a livello di colonna impostando l'attributo di istruzione SQL_ATTR_PARAM_BIND_TYPE. Nella figura seguente viene illustrato il funzionamento dell'associazione a livello di colonna.
Ad esempio, il codice seguente associa matrici a 10 elementi ai parametri delle colonne PartID, Description e Price ed esegue un'istruzione per inserire 10 righe. Utilizza un'associazione per colonna.
#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;
}
}
Associazione per riga
Quando si usa l'associazione a livello di riga, un'applicazione definisce una struttura per ogni set di parametri. La struttura contiene uno o due elementi per ogni parametro. Il primo elemento contiene il valore del parametro e il secondo elemento contiene il buffer di lunghezza/indicatore. L'applicazione alloca quindi una matrice di queste strutture, che contiene tanti elementi quanti sono i valori di ogni parametro.
L'applicazione dichiara le dimensioni della struttura nel driver con l'attributo di istruzione SQL_ATTR_PARAM_BIND_TYPE. L'applicazione associa gli indirizzi dei parametri nella prima struttura della matrice. Pertanto, il driver può calcolare l'indirizzo dei dati per una determinata riga e colonna
Address = Bound Address + ((Row Number - 1) * Structure Size) + Offset
dove le righe sono numerate da 1 alla dimensione del set di parametri. L'offset, se definito, è il valore indicato dall'attributo dell'istruzione SQL_ATTR_PARAM_BIND_OFFSET_PTR. Nella figura seguente viene illustrato il funzionamento dell'associazione a livello di riga. I parametri possono essere inseriti nella struttura in qualsiasi ordine, ma vengono visualizzati in ordine sequenziale per maggiore chiarezza.
Il codice seguente crea una struttura con alcuni elementi per i valori da archiviare nelle colonne PartID, Description e Price. Alloca quindi una matrice di 10 elementi di queste strutture e la associa ai parametri delle colonne PartID, Description e Price, usando l'associazione per riga. Esegue quindi un'istruzione per inserire 10 righe.
#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;
}