Bagikan melalui


Menggunakan SQLBindCol

Aplikasi mengikat kolom dengan memanggil SQLBindCol. Fungsi ini mengikat satu kolom pada satu waktu. Dengan itu, aplikasi menentukan hal-hal berikut:

  • Nomor kolom. Kolom 0 adalah kolom marka buku; kolom ini tidak disertakan dalam beberapa tataan hasil. Semua kolom lainnya diberi nomor dimulai dengan angka 1. Ini adalah kesalahan untuk mengikat kolom bernomor lebih tinggi daripada kolom dalam tataan hasil; kesalahan ini tidak dapat dideteksi sampai kumpulan hasil dibuat, sehingga dikembalikan oleh SQLFetch, bukan SQLBindCol.

  • Jenis data C, alamat, dan panjang byte variabel yang terikat ke kolom. Ini adalah kesalahan untuk menentukan jenis data C tempat tipe data SQL kolom tidak dapat dikonversi; kesalahan ini mungkin tidak terdeteksi sampai kumpulan hasil dibuat, sehingga dikembalikan oleh SQLFetch, bukan SQLBindCol. Untuk daftar konversi yang didukung, lihat Mengonversi Data dari SQL ke Jenis Data C di Lampiran D: Jenis Data. Untuk informasi tentang panjang byte, lihat Panjang Buffer Data.

  • Alamat buffer panjang/indikator. Buffer panjang/indikator bersifat opsional. Ini digunakan untuk mengembalikan panjang byte data biner atau karakter atau mengembalikan SQL_NULL_DATA jika data adalah NULL. Untuk informasi selengkapnya, lihat Menggunakan Nilai Panjang/Indikator.

Ketika SQLBindCol dipanggil, driver mengaitkan informasi ini dengan pernyataan . Ketika setiap baris data diambil, data menggunakan informasi untuk menempatkan data untuk setiap kolom dalam variabel aplikasi terikat.

Misalnya, kode berikut mengikat variabel ke kolom SalesPerson dan CustID. Data untuk kolom akan dikembalikan di SalesPerson dan CustID. Karena SalesPerson adalah buffer karakter, aplikasi menentukan panjang bytenya (11) sehingga driver dapat menentukan apakah akan memotong data. Panjang byte dari judul yang dikembalikan, atau apakah itu NULL, akan dikembalikan di SalesPersonLenOrInd.

Karena CustID adalah variabel bilangan bulat dan memiliki panjang tetap, tidak perlu menentukan panjang bytenya; driver menganggapnya adalah sizeof (SQLUINTEGER). Panjang byte dari data ID pelanggan yang dikembalikan, atau apakah itu NULL, akan dikembalikan di CustIDInd. Perhatikan bahwa aplikasi hanya tertarik pada apakah gaji adalah NULL, karena panjang byte selalu sizeof (SQLUINTEGER).

SQLCHAR       SalesPerson[11];  
SQLUINTEGER   CustID;  
SQLINTEGER    SalesPersonLenOrInd, CustIDInd;  
SQLRETURN     rc;  
SQLHSTMT      hstmt;  
  
// Bind SalesPerson to the SalesPerson column and CustID to the   
// CustID column.  
SQLBindCol(hstmt, 1, SQL_C_CHAR, SalesPerson, sizeof(SalesPerson),  
            &SalesPersonLenOrInd);  
SQLBindCol(hstmt, 2, SQL_C_ULONG, &CustID, 0, &CustIDInd);  
  
// Execute a statement to get the sales person/customer of all orders.  
SQLExecDirect(hstmt, "SELECT SalesPerson, CustID FROM Orders ORDER BY SalesPerson",  
               SQL_NTS);  
  
// Fetch and print the data. Print "NULL" if the data is NULL. Code to   
// check if rc equals SQL_ERROR or SQL_SUCCESS_WITH_INFO not shown.  
while ((rc = SQLFetch(hstmt)) != SQL_NO_DATA) {  
   if (SalesPersonLenOrInd == SQL_NULL_DATA)   
            printf("NULL                     ");  
   else   
            printf("%10s   ", SalesPerson);  
   if (CustIDInd == SQL_NULL_DATA)   
         printf("NULL\n");  
   else   
            printf("%d\n", CustID);  
}  
  
// Close the cursor.  
SQLCloseCursor(hstmt);  

Kode berikut menjalankan pernyataan SELECT yang dimasukkan oleh pengguna dan mencetak setiap baris data dalam tataan hasil. Karena aplikasi tidak dapat memprediksi bentuk kumpulan hasil yang dibuat oleh pernyataan SELECT , aplikasi tidak dapat mengikat variabel yang dikodekan secara permanen ke hasil yang ditetapkan seperti dalam contoh sebelumnya. Sebagai gantinya, aplikasi mengalokasikan buffer yang menyimpan data dan buffer panjang/indikator untuk setiap kolom di baris tersebut. Untuk setiap kolom, ini menghitung offset ke awal memori untuk kolom dan menyesuaikan offset ini sehingga data dan buffer panjang/indikator untuk kolom dimulai pada batas perataan. Kemudian mengikat memori yang dimulai pada offset ke kolom. Dari sudut pandang driver, alamat memori ini tidak dapat dibedakan dari alamat variabel yang terikat dalam contoh sebelumnya. Untuk informasi selengkapnya tentang perataan, lihat Perataan.

// This application allocates a buffer at run time. For each column, this   
// buffer contains memory for the column's data and length/indicator.   
// For example:  
//      column 1         column 2      column 3      column 4  
// <------------><---------------><-----><------------>  
//      db1   li1   db2   li2   db3   li3   db4   li4  
//      |      |      |      |      |      |      |         |  
//      _____V_____V________V_______V___V___V______V_____V_  
// |__________|__|_____________|__|___|__|__________|__|  
//  
// dbn = data buffer for column n  
// lin = length/indicator buffer for column n  
  
// Define a macro to increase the size of a buffer so that it is a   
// multiple of the alignment size. Thus, if a buffer starts on an   
// alignment boundary, it will end just before the next alignment   
// boundary. In this example, an alignment size of 4 is used because   
// this is the size of the largest data type used in the application's   
// buffer--the size of an SDWORD and of the largest default C data type   
// are both 4. If a larger data type (such as _int64) was used, it would   
// be necessary to align for that size.  
#define ALIGNSIZE 4  
#define ALIGNBUF(Length) Length % ALIGNSIZE ? \  
                  Length + ALIGNSIZE - (Length % ALIGNSIZE) : Length  
  
SQLCHAR        SelectStmt[100];  
SQLSMALLINT    NumCols, *CTypeArray, i;  
SQLINTEGER *   ColLenArray, *OffsetArray, SQLType, *DataPtr;  
SQLRETURN      rc;   
SQLHSTMT       hstmt;  
  
// Get a SELECT statement from the user and execute it.  
GetSelectStmt(SelectStmt, 100);  
SQLExecDirect(hstmt, SelectStmt, SQL_NTS);  
  
// Determine the number of result set columns. Allocate arrays to hold   
// the C type, byte length, and buffer offset to the data.  
SQLNumResultCols(hstmt, &NumCols);  
CTypeArray = (SQLSMALLINT *) malloc(NumCols * sizeof(SQLSMALLINT));  
ColLenArray = (SQLINTEGER *) malloc(NumCols * sizeof(SQLINTEGER));  
OffsetArray = (SQLINTEGER *) malloc(NumCols * sizeof(SQLINTEGER));  
  
OffsetArray[0] = 0;  
for (i = 0; i < NumCols; i++) {  
   // Determine the column's SQL type. GetDefaultCType contains a switch   
   // statement that returns the default C type for each SQL type.  
   SQLColAttribute(hstmt, ((SQLUSMALLINT) i) + 1, SQL_DESC_TYPE, NULL, 0, NULL, (SQLPOINTER) &SQLType);  
   CTypeArray[i] = GetDefaultCType(SQLType);  
  
   // Determine the column's byte length. Calculate the offset in the   
   // buffer to the data as the offset to the previous column, plus the   
   // byte length of the previous column, plus the byte length of the   
   // previous column's length/indicator buffer. Note that the byte   
   // length of the column and the length/indicator buffer are increased   
   // so that, assuming they start on an alignment boundary, they will  
   // end on the byte before the next alignment boundary. Although this   
   // might leave some holes in the buffer, it is a relatively   
   // inexpensive way to guarantee alignment.  
   SQLColAttribute(hstmt, ((SQLUSMALLINT) i)+1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &ColLenArray[i]);  
   ColLenArray[i] = ALIGNBUF(ColLenArray[i]);  
   if (i)  
      OffsetArray[i] = OffsetArray[i-1]+ColLenArray[i-1]+ALIGNBUF(sizeof(SQLINTEGER));  
}  
  
// Allocate the data buffer. The size of the buffer is equal to the   
// offset to the data buffer for the final column, plus the byte length   
// of the data buffer and length/indicator buffer for the last column.  
void *DataPtr = malloc(OffsetArray[NumCols - 1] +  
               ColLenArray[NumCols - 1] + ALIGNBUF(sizeof(SQLINTEGER)));  
  
// For each column, bind the address in the buffer at the start of the   
// memory allocated for that column's data and the address at the start   
// of the memory allocated for that column's length/indicator buffer.  
for (i = 0; i < NumCols; i++)  
   SQLBindCol(hstmt,  
            ((SQLUSMALLINT) i) + 1,  
            CTypeArray[i],  
            (SQLPOINTER)((SQLCHAR *)DataPtr + OffsetArray[i]),  
            ColLenArray[i],  
            (SQLINTEGER *)((SQLCHAR *)DataPtr + OffsetArray[i] + ColLenArray[i]));  
  
// Retrieve and print each row. PrintData accepts a pointer to the data,   
// its C type, and its byte length/indicator. It contains a switch   
// statement that casts and prints the data according to its type. Code   
// to check if rc equals SQL_ERROR or SQL_SUCCESS_WITH_INFO not shown.  
while ((rc = SQLFetch(hstmt)) != SQL_NO_DATA) {  
   for (i = 0; i < NumCols; i++) {  
      PrintData((SQLCHAR *)DataPtr[OffsetArray[i]], CTypeArray[i],  
               (SQLINTEGER *)((SQLCHAR *)DataPtr[OffsetArray[i] + ColLenArray[i]]));  
   }  
}  
  
// Close the cursor.  
SQLCloseCursor(hstmt);