/**********************************************************************
* FILENAME :        ListDataTypes.c
*
* DESCRIPTION :
*       Example allows user to select a data source and displays the
*       information available on the data types associated with it.
*
* ODBC USAGE :
*       Calls selectDSN() to ask user to select Data Source
*       Connects to Data Source selected
*       Uses SQLGetTypeInfo() with SQL_ALL_TYPES
*       Binds data for 3 columns for name, type and size
*       Uses SQLFetch() to return data types result set
*       Displays results in tabular form
*/

#include <stdio.h>
#include <stdlib.h>
#include <sql.h>
#include <sqlext.h>
#include <string.h>

#include "util.c"

/*
Possible Data Types

//#define SQL_UNKNOWN_TYPE        0
//#define SQL_CHAR                1
//#define SQL_NUMERIC             2
//#define SQL_DECIMAL             3
//#define SQL_INTEGER             4
//#define SQL_SMALLINT            5
//#define SQL_FLOAT               6
//#define SQL_REAL                7
//#define SQL_DOUBLE              8
//#define SQL_DATETIME            9      ODBCVER >= 0x0300
//#define SQL_DATE                9
//#define SQL_INTERVAL            10     ODBCVER >= 0x0300
//#define SQL_TIME                10
//#define SQL_TIMESTAMP           11
//#define SQL_VARCHAR             12

//#define SQL_TYPE_DATE           91     ODBCVER >= 0x0300
//#define SQL_TYPE_TIME           92     ODBCVER >= 0x0300
//#define SQL_TYPE_TIMESTAMP      93     ODBCVER >= 0x0300

//#define SQL_LONGVARCHAR         (-1)
//#define SQL_BINARY              (-2)
//#define SQL_VARBINARY           (-3)
//#define SQL_LONGVARBINARY       (-4)
//#define SQL_BIGINT              (-5)
//#define SQL_TINYINT             (-6)
//#define SQL_BIT                 (-7)
//#define SQL_WCHAR               (-8)
//#define SQL_WVARCHAR            (-9)
//#define SQL_WLONGVARCHAR        (-10)
//#define SQL_GUID		  (-11)  ODBCVER >= 0x0350
//#define SQL_SS_VARIANT          (-150) SQL Server 2008
//#define SQL_SS_UDT              (-151) SQL Server 2008
//#define SQL_SS_XML              (-152) SQL Server 2008
//#define SQL_SS_TABLE            (-153) SQL Server 2008
//#define SQL_SS_TIME2            (-154) SQL Server 2008
//#define SQL_SS_TIMESTAMPOFFSET  (-155) SQL Server 2008

*/
#define DTSIZE 35

// SQL Data Type Structure
typedef struct {
    char name [32];     // SQL data type name
    int  value;         // SQL data type numeric value
} dataTypes;

// Array of SQL Data Types
dataTypes dtList[DTSIZE] = {
    "SQL_UNKNOWN_TYPE",0,
    "SQL_CHAR",1,
    "SQL_NUMERIC",2,
    "SQL_DECIMAL",3,
    "SQL_INTEGER",4,
    "SQL_SMALLINT",5,
    "SQL_FLOAT",6,
    "SQL_REAL",7,
    "SQL_DOUBLE",8,
    "SQL_DATETIME",9,
    "SQL_DATE",9,
    "SQL_INTERVAL",10,
    "SQL_TIME",10,
    "SQL_TIMESTAMP",11,
    "SQL_VARCHAR",12,
    "SQL_TYPE_DATE",91,
    "SQL_TYPE_TIME",92,
    "SQL_TYPE_TIMESTAMP",93,
    "SQL_LONGVARCHAR",-1,
    "SQL_BINARY",-2,
    "SQL_VARBINARY",-3,
    "SQL_LONGVARBINARY",-4,
    "SQL_BIGINT",-5,
    "SQL_TINYINT",-6,
    "SQL_BIT",-7,
    "SQL_WCHAR",-8,
    "SQL_WVARCHAR",-9,
    "SQL_WLONGVARCHAR",-10,
    "SQL_GUID",-11,
    "SQL_SS_VARIANT",-150,
    "SQL_SS_UDT",-151,
    "SQL_SS_XML",-152,
    "SQL_SS_TABLE",-153,
    "SQL_SS_TIME2",-154,
    "SQL_SS_TIMESTAMPOFFSET",-155
};

// Returns name of data type, unknown if not found
char * SQLType (int dataType) {

    int i;

    for (i=0;i<DTSIZE;i++) {
        if (dataType==dtList[i].value)
        break;
    }

    if (i<DTSIZE) {
        return (dtList[i].name);
    } else {
        return (dtList[0].name);
    }
}

int main () {

    // For formatting output
    char padding[] = "                         ";
    int max=strlen(padding);

    char * val;

    SQLCHAR typeName[128];
    SQLSMALLINT dataType;
    SQLINTEGER columnSize;

    SQLLEN typeName_ind, dataType_ind, columnSize_ind;

    SQLHENV  henv  = SQL_NULL_HENV;   	// Environment
    SQLHDBC  hdbc  = SQL_NULL_HDBC;   	// Connection handle
    SQLHSTMT hstmt = SQL_NULL_HSTMT;  	// Statement handle
    SQLRETURN retcode;			// Return status

    char dsn[MAXDSNLEN];

    // Create environment handle
    retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
    CHECK_ERROR(retcode, "SQLAllocHandle(ENV)", henv, SQL_HANDLE_ENV);

    // Set ODBC 3 behaviour
    retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                                        (SQLCHAR *)(void*)SQL_OV_ODBC3, -1);
    CHECK_ERROR(retcode, "SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)",
                henv, SQL_HANDLE_ENV);

    // Which data source?
    retcode = selectDSN (henv, dsn, "Select DSN : ");
    if (retcode != SQL_SUCCESS) {
        printf ("DSN not selected, exiting.");
        goto exit;
    }

    retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
    CHECK_ERROR(retcode, "SQLAllocHandle(DBC)",
                hdbc, SQL_HANDLE_DBC);

    retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)10, 0);
    CHECK_ERROR(retcode, "SQLSetConnectAttr(SQL_LOGIN_TIMEOUT)",
                hdbc, SQL_HANDLE_DBC);

    retcode = SQLConnect(hdbc, (SQLCHAR*) dsn, SQL_NTS,
                                            (SQLCHAR*) NULL, 0, NULL, 0);
    CHECK_ERROR(retcode, "SQLConnect",
                hdbc, SQL_HANDLE_DBC);

    retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
    CHECK_ERROR(retcode, "SQLAllocHandle(STMT)",
                hstmt, SQL_HANDLE_STMT);

    retcode = SQLGetTypeInfo(hstmt, SQL_ALL_TYPES);
    CHECK_ERROR(retcode, "SQLGetTypeInfo",
                hstmt, SQL_HANDLE_STMT);

    retcode = SQLBindCol(hstmt, 1, SQL_C_CHAR,
                         (SQLPOINTER) typeName,
                         (SQLLEN) sizeof(typeName), &typeName_ind);
    CHECK_ERROR(retcode, "SQLBindCol(1)", hstmt, SQL_HANDLE_STMT);

    retcode = SQLBindCol(hstmt, 2, SQL_C_SHORT,
                         (SQLPOINTER) &dataType,
                         (SQLLEN) sizeof(dataType), &dataType_ind);
    CHECK_ERROR(retcode, "SQLBindCol(2)", hstmt, SQL_HANDLE_STMT);

    retcode = SQLBindCol(hstmt, 3, SQL_C_ULONG,
                         (SQLPOINTER) &columnSize,
                         (SQLLEN) sizeof(columnSize), &columnSize_ind);
    CHECK_ERROR(retcode, "SQLBindCol(2)", hstmt, SQL_HANDLE_STMT);

    printf("SQL Data Type             Type Name                 Value"
                                                                "Max Size\n");
    printf("------------------------- ------------------------- -------"
                                                                "--------\n");

    // Fetch each row, and display
    while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) {
        padOut(SQLType (dataType), padding, max);
        printf("%s,%s", SQLType (dataType), padding);

        padOut(typeName, padding, max);
        printf("%s,%s", (char *) typeName, padding);

        val = itoa(dataType);
        padOut(val, padding, max-18);
        printf("%i,%s", (int) dataType, padding);

        padOut("", padding, max);
        printf ("%i\n", (int) columnSize);
    }

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