Binden von Parameterarrays

Anwendungen, die Parameterarrays verwenden, binden die Arrays an die Parameter in der SQL-Anweisung. Es gibt zwei Bindungsstile:

  • Binden Sie ein Array an jeden Parameter. Jede Datenstruktur (Array) enthält alle Daten für einen einzelnen Parameter. Dies wird als spaltenweise Bindung bezeichnet, da eine Spalte mit Werten für einen einzelnen Parameter gebunden wird.

  • Definieren Sie eine -Struktur, die die Parameterdaten für einen gesamten Parametersatz enthält, und binden Sie ein Array dieser Strukturen. Jede Datenstruktur enthält die Daten für eine einzelne SQL Anweisung. Dies wird als zeilenweise Bindung bezeichnet, da eine Zeile mit Parametern gebunden wird.

Wie beim Binden einzelner Variablen an Parameter ruft die Anwendung SQLBindParameter auf, um Arrays an Parameter zu binden. Der einzige Unterschied besteht darin, dass es sich bei den übergebenen Adressen um Arrayadressen handelt, nicht um Adressen mit nur einer Variablen. Die Anwendung legt das SQL_ATTR_PARAM_BIND_TYPE Anweisungsattribut fest, um anzugeben, ob spaltenweise (Standard) oder zeilenweise Bindung verwendet wird. Ob die spalten- oder zeilenweise Bindung verwendet werden soll, hängt größtenteils von der Anwendungspräferenz ab. Je nachdem, wie der Prozessor auf den Arbeitsspeicher zugreift, ist die zeilenweise Bindung möglicherweise schneller. Allerdings ist der Unterschied mit Ausnahme einer sehr großen Anzahl von Parameterzeilen wahrscheinlich vernachlässigbar.

Spaltenbezogenes Binden

Bei Verwendung der spaltenweisen Bindung bindet eine Anwendung ein oder zwei Arrays an jeden Parameter, für den Daten bereitgestellt werden sollen. Das erste Array enthält die Datenwerte, und das zweite Array enthält Längen-/Indikatorpuffer. Jedes Array enthält so viele Elemente, wie Werte für den Parameter vorhanden sind.

Die spaltenweise Bindung ist die Standardeinstellung. Die Anwendung kann auch von zeilenweiser Bindung zu spaltenweiser Bindung wechseln, indem das SQL_ATTR_PARAM_BIND_TYPE Anweisungsattribut festgelegt wird. Die folgende Abbildung zeigt, wie die spaltenweise Bindung funktioniert.

Shows how column-wise binding works

Der folgende Code bindet beispielsweise Arrays mit 10 Elementen an Parameter für die Spalten PartID, Description und Price und führt eine Anweisung aus, um 10 Zeilen einzufügen. Es wird spaltenweise Bindung verwendet.

#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;  
  
   }  
}  

Zeilenbezogenes Binden

Bei Verwendung der zeilenweisen Bindung definiert eine Anwendung eine Struktur für jeden Parametersatz. Die -Struktur enthält ein oder zwei Elemente für jeden Parameter. Das erste Element enthält den Parameterwert, und das zweite Element enthält den Längen-/Indikatorpuffer. Die Anwendung ordnet dann ein Array dieser Strukturen zu, das so viele Elemente enthält, wie Werte für jeden Parameter vorhanden sind.

Die Anwendung deklariert die Größe der Struktur dem Treiber mit dem SQL_ATTR_PARAM_BIND_TYPE Anweisungsattribut. Die Anwendung bindet die Adressen der Parameter in der ersten Struktur des Arrays. Daher kann der Treiber die Adresse der Daten für eine bestimmte Zeile und Spalte wie folgt berechnen:

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

, wobei Zeilen von 1 bis zur Größe des Parametersatzes nummeriert werden. Der Offset ist, sofern definiert, der Wert, auf den das SQL_ATTR_PARAM_BIND_OFFSET_PTR Anweisungsattribut zeigt. Die folgende Abbildung zeigt, wie zeilenweise Bindung funktioniert. Die Parameter können in der Struktur in beliebiger Reihenfolge platziert werden, werden jedoch aus Gründen der Übersichtlichkeit in sequenzieller Reihenfolge angezeigt.

Shows how row-wise binding works

Der folgende Code erstellt eine -Struktur mit -Elementen für die Werte, die in den Spalten PartID, Description und Price gespeichert werden sollen. Anschließend ordnet er ein Array mit 10 Elementen dieser Strukturen zu und bindet es mit zeilenweiser Bindung an Parameter für die Spalten PartID, Description und Price. Anschließend wird eine -Anweisung ausgeführt, um 10 Zeilen einzufügen.

#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;  
  
   }