Binden von Parameterarrays

Anwendungen, die Arrays von Parametern verwenden, binden die Arrays an die Parameter in der SQL-Anweisung. Es gibt zwei Bindungsformate:

  • 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 von Werten für einen einzelnen Parameter gebunden wird.

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

Wie beim Binden einzelner Variablen an Parameter wird SQLBindParameter aufgerufen, um Arrays an Parameter zu binden. Der einzige Unterschied besteht darin, dass die übergebenen Adressen Arrayadressen sind, nicht einzelne variable Adressen. Die Anwendung legt das SQL_ATTR_PARAM_BIND_TYPE-Anweisungsattribute fest, um anzugeben, ob sie spaltenweise (standard) oder zeilenweise Bindung verwendet. Ob spaltenweise oder zeilenweise Bindung verwendet werden soll, ist weitgehend eine Frage der Anwendungseinstellung. Je nachdem, wie der Prozessor auf den Arbeitsspeicher zugreift, kann die zeilenweise Bindung schneller sein. Der Unterschied ist jedoch wahrscheinlich unbedeutlich, außer für sehr große Anzahl von Zeilen von Parametern.

Spaltenbezogenes Binden

Wenn Sie spaltenweise Bindung verwenden, 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.

Spaltenweise Bindung ist die Standardeinstellung. Die Anwendung kann auch von zeilenweiser Bindung zu spaltenweiser Bindung wechseln, indem Sie das SQL_ATTR_PARAM_BIND_TYPE-Anweisungsattribute festlegen. Die folgende Abbildung zeigt, wie spaltenweise Bindung funktioniert.

Zeigt, wie spaltenweise Bindung funktioniert

Der folgende Code bindet z. B. 10-Elementarrays an Parameter für die Spalten "PartID", "Beschreibung" und "Preis", und führt eine Anweisung aus, um 10 Zeilen einzufügen. Sie verwendet spaltenweise Bindung.

#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

Wenn Sie zeilenweise Bindung verwenden, definiert eine Anwendung eine Struktur für jede Reihe von Parametern. Die Struktur enthält mindestens 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 weist dann ein Array dieser Strukturen zu, das so viele Elemente enthält, wie für jeden Parameter Werte vorhanden sind.

Die Anwendung deklariert die Größe der Struktur an den Treiber mit dem SQL_ATTR_PARAM_BIND_TYPE-Anweisungsattribute. Die Anwendung bindet die Adressen der Parameter in der ersten Struktur des Arrays. Damit kann der Treiber die Adresse der Daten für eine bestimmte Zeile und Spalte berechnen wie

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

wobei Zeilen zwischen 1 und der Größe des Parametersatzes nummeriert werden. Der Offset, wenn definiert, ist der Wert, der durch das SQL_ATTR_PARAM_BIND_OFFSET_PTR-Anweisungsattribute verweist. In der folgenden Abbildung wird gezeigt, wie die Zeilenbindung funktioniert. Die Parameter können in beliebiger Reihenfolge in der Struktur platziert werden, werden jedoch in sequenzieller Reihenfolge für Klarheit angezeigt.

Zeigt, wie zeilenweise Bindung funktioniert

Der folgende Code erstellt eine Struktur mit Elementen für die Werte, die in den Spalten "PartID", "Beschreibung" und "Preis" gespeichert werden sollen. Anschließend wird ein 10-Element-Array dieser Strukturen zugewiesen und an Parameter für die PartID- und Beschreibungs- und Preisspalten mit zeilenweiser Bindung gebunden. 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;  
  
   }