/**********************************************************************
* FILENAME : DescribeColumn.c
*
* DESCRIPTION :
* Example illustrates use of SQLDescribeCol and SQLColAttribute to
* obtain column information from a prepared statement and then use
* that information to bind parameters in the prepared statement
* before executing it.
*
* ODBC USAGE :
* SQLPrepare - prepare basic 'SELECT * FROM' statement
* SQLNumResultCols- get number of columns
* SQLDescribeCol - obtain column information (name, type, etc) and
* save
* SQLColAttribute - obtain column max size information
* SQLBindCol - binds the column data saved by SQLDescribeCol
* to the statement
* SQLExecute - execute the 'SELECT * FROM'
* SQLFetch - return the records until SQL_NO_DATA returned
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <sql.h>
#include <sqlext.h>
#include <string.h>
#include "util.c"
#define PERSONID_LEN 2
#define LASTNAME_LEN 255
#define FIRSTNAME_LEN 255
#define ADDRESS_LEN 255
#define CITY_LEN 255
#define MAXCOLS 10
#define TRUE 1
SQLHENV henv = SQL_NULL_HENV; // Environment
SQLHDBC hdbc = SQL_NULL_HDBC; // Connection handle
SQLHSTMT hstmt = SQL_NULL_HSTMT; // Statement handle
SQLRETURN retcode;
SQLRETURN display_results(SQLHSTMT hstmt)
{
SQLCHAR colname[32]; // column name
SQLSMALLINT coltype; // column type
SQLSMALLINT colnamelen; // length of column name
SQLSMALLINT nullable; // whether column can have NULL value
SQLLEN collen[MAXCOLS]; // array of column lengths
SQLSMALLINT decimaldigits; // no of digits if column is numeric
SQLLEN outlen[MAXCOLS]; // lengths of column values returned
SQLCHAR * data[MAXCOLS]; // buffers for retrieving column values
SQLRETURN retcode; // general return code
SQLLEN displaysize; // drivers column display size
SQLINTEGER i,j;
SQLSMALLINT columns;
// Initialise data array
for (i=0;i<MAXCOLS;i++) {
data[i]=NULL;
}
// Get number of columns from prepared statement
retcode=SQLNumResultCols(hstmt, &columns);
CHECK_ERROR(retcode, "SQLNumResultCols()",
hstmt, SQL_HANDLE_STMT);
printf ("Number of columns is %i\n", (int) columns);
printf ("Use SQLDescribeCol to obtain column details\n");
for (i = 0; i < columns; i++)
{
// for each column from the prepared statement in hstmt, get the
// column name, type, column size, decimal digits, and nullability
retcode = SQLDescribeCol (hstmt,
(SQLUSMALLINT)i+1,
colname,
sizeof (colname),
&colnamelen,
&coltype,
&collen[i],
&decimaldigits,
&nullable);
CHECK_ERROR(retcode, "SQLDescribeCol()",
hstmt, SQL_HANDLE_STMT);
displaysize=0;
// get Maximum number of characters required to display data
// from the column.
retcode = SQLColAttribute (hstmt,
(SQLUSMALLINT)i+1,
SQL_COLUMN_DISPLAY_SIZE,
NULL, 0, NULL, &displaysize);
CHECK_ERROR(retcode, "SQLColAttribute()",
hstmt, SQL_HANDLE_STMT);
/* set column length to max of display length, and column name
length. Plus one byte for null terminator */
if (collen[i] > displaysize) {
collen[i]=displaysize+1;
} else {
collen[i]=collen[i]+1;
}
// allocate memory to bind column
data[i] = (SQLCHAR *) malloc (collen[i]);
}
//Bind columns to data array
printf ("Bind columns to statement\n");
for (i = 0; i < columns; i++) {
outlen[i]=0;
retcode = SQLBindCol (hstmt,
(SQLUSMALLINT)i+1,
SQL_C_CHAR,
(SQLPOINTER) data[i],
collen[i],
&outlen[i]);
CHECK_ERROR(retcode, "SQLBindCol()", hstmt, SQL_HANDLE_STMT);
}
/* execute the now fully prepared statement */
printf ("Execute Statement\n");
retcode=SQLExecute(hstmt);
CHECK_ERROR(retcode, "SQLExecute()", hstmt, SQL_HANDLE_STMT);
printf ("Fetch Results\n");
/* display the result rows */
for (i=0; ; i++) {
retcode = SQLFetch(hstmt);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
printf("Record %i : ", i+1);
for (j=0;j<columns;j++) {
printf ("%s", rtrim(data[j], ' '));
if (j!=columns-1) {printf (", ");}
}
printf ("\n");
} else {
if (retcode != SQL_NO_DATA) {
CHECK_ERROR(retcode, "SQLFetch()",
hstmt, SQL_HANDLE_STMT);
}
break;
}
}
exit:
/* free data buffers */
for (i = 0; i < columns; i++)
{
if (data[i]!=NULL) free (data[i]);
}
return;
}
int main () {
SQLSMALLINT sCustID;
char sqlstr[] = "SELECT * from TestTBL1Copy order by PersonID";
// Allocate the ODBC environment and save handle.
retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_ENV)",
henv, SQL_HANDLE_ENV);
// Notify ODBC that this is an ODBC 3.0 app.
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
(SQLPOINTER) SQL_OV_ODBC3, 0);
CHECK_ERROR(retcode, "SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)",
henv, SQL_HANDLE_ENV);
// Allocate ODBC connection handle and connect.
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_DBC)",
hdbc, SQL_HANDLE_DBC);
// Connect to the DSN
retcode=SQLDriverConnect(hdbc, NULL, "DSN=DATASOURCE;", SQL_NTS,
NULL, 0, NULL, SQL_DRIVER_COMPLETE);
CHECK_ERROR(retcode, "SQLDriverConnect(DATASOURCE 0)",
hdbc, SQL_HANDLE_DBC);
// Allocate statement handle.
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_STMT)",
hstmt, SQL_HANDLE_STMT);
// Prepare the statement
retcode = SQLPrepare(hstmt, (SQLCHAR*) sqlstr, SQL_NTS);
CHECK_ERROR(retcode, "SQLPrepare(SQL_HANDLE_STMT)",
hstmt, SQL_HANDLE_STMT);
retcode = display_results(hstmt);
exit:
printf ("\nComplete.\n");
// Free handles
// Statement
if (hstmt != SQL_NULL_HSTMT)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
// Connection
if (hdbc != SQL_NULL_HDBC) {
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
// Environment
if (henv != SQL_NULL_HENV)
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}
Further information