다음을 통해 공유


SQLBindCol 사용

애플리케이션은 SQLBindCol을 호출하여 열을 바인딩합니다. 이 함수는 한 번에 하나의 열을 바인딩합니다. 이를 통해 애플리케이션은 다음을 지정합니다.

  • 열 번호입니다. 열 0은 책갈피 열입니다. 이 열은 일부 결과 집합에 포함되지 않습니다. 다른 모든 열은 숫자 1부터 번호가 매겨집니다. 결과 집합에 열이 있는 것보다 높은 번호의 열을 바인딩하는 것은 오류입니다. 결과 집합이 만들어질 때까지 이 오류를 검색할 수 없으므로 SQLBindCol이 아닌 SQLFetch에서 반환됩니다.

  • 열에 바인딩된 변수의 C 데이터 형식, 주소 및 바이트 길이입니다. 열의 SQL 데이터 형식을 변환할 수 없는 C 데이터 형식을 지정하는 것은 오류입니다. 이 오류는 결과 집합이 만들어질 때까지 검색되지 않을 수 있으므로 SQLBindCol이 아닌 SQLFetch에서 반환됩니다. 지원되는 변환 목록은 부록 D: 데이터 형식에서 SQL에서 C 데이터 형식으로 데이터 변환을 참조하세요. 바이트 길이에 대한 자세한 내용은 데이터 버퍼 길이를 참조 하세요.

  • 길이/표시기 버퍼의 주소입니다. 길이/표시기 버퍼는 선택 사항입니다. 이진 또는 문자 데이터의 바이트 길이를 반환하거나 데이터가 NULL인 경우 SQL_NULL_DATA 반환하는 데 사용됩니다. 자세한 내용은 길이/표시기 값 사용을 참조 하세요.

SQLBindCol이 호출되면 드라이버는 이 정보를 문과 연결합니다. 데이터의 각 행을 가져올 때는 이 정보를 사용하여 각 열에 대한 데이터를 바인딩된 애플리케이션 변수에 배치합니다.

예를 들어 다음 코드는 SalesPerson 및 CustID 열에 변수를 바인딩합니다. 열에 대한 데이터는 SalesPersonCustID에서 반환됩니다. SalesPerson은 문자 버퍼이므로 애플리케이션은 드라이버가 데이터를 잘라낼지 여부를 결정할 수 있도록 바이트 길이(11)를 지정합니다. 반환된 타이틀의 바이트 길이 또는 NULL인지 여부는 SalesPersonLenOrInd에서 반환됩니다.

CustID는 정수 변수이고 길이가 고정되어 있으므로 바이트 길이를 지정할 필요가 없습니다. 드라이버는 sizeof(SQLUINTEGER)라고 가정합니다. 반환된 고객 ID 데이터의 바이트 길이 또는 NULL인지 여부는 CustIDInd에서 반환됩니다. 바이트 길이는 항상 sizeof(SQLUINTEGER)이기 때문에 애플리케이션은 급여가 NULL인지 여부에만 관심이 있습니다.

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);  

다음 코드는 사용자가 입력한 SELECT 문을 실행하고 결과 집합의 각 데이터 행을 출력합니다. 애플리케이션은 SELECT 문에서 만든 결과 집합의 모양을 예측할 수 없으므로 이전 예제와 같이 하드 코딩된 변수를 결과 집합에 바인딩할 수 없습니다. 대신 애플리케이션은 데이터를 보유하는 버퍼와 해당 행의 각 열에 대한 길이/표시기 버퍼를 할당합니다. 각 열에 대해 열의 메모리 시작 부분까지의 오프셋을 계산하고 이 오프셋을 조정하여 열의 데이터 및 길이/표시기 버퍼가 맞춤 경계에서 시작되도록 합니다. 그런 다음 오프셋에서 시작하는 메모리를 열에 바인딩합니다. 드라이버의 관점에서 이 메모리의 주소는 이전 예제에 바인딩된 변수의 주소와 구별할 수 없습니다. 맞춤에 대한 자세한 내용은 맞춤을 참조 하세요.

// 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);