/**********************************************************************
* FILENAME :        ListStatistics.c
*
* DESCRIPTION :
*       Example finds tables starting with 'TestTBL' and for each one
*       outputs table statistics.
*
* ODBC USAGE :
* 		SQLGetInfo    - with SQL_DATABASE_NAME info type - to get name
*                       of the current database in use. e.g msdb
* 		SQLGetInfo    - with SQL_USER_NAME info type - to get the name
*                       used in a particular database. e.g. dbo
*       Creates a catalogue table with 5 elements table details, namely
*                       TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE
*                       and IndexName (see MSDN SQLTables).
*       SQLBindCol    - to bind the columns from the catalogue table before
*                       calling SQLTables
*       SQLTables     - with database, user and TABLE to initiate retrieval
*                       of tables from msdb/dbo
*       SQLFetch      - loops until all all tables returned, saviing ones
*                       starting with 'TestTBL' for later
*       SQLStatistics - called for each table which returns two types of
*                       information:
*
*       Statistics information for the table (if it is available):
*           when the TYPE column of the result set described below is set
*           to SQL_TABLE_STAT, we get the number of rows in the table and
*           the number of pages used to store the table. When the TYPE column
*           of the result set indicates an index, we get the number of unique
*           values in the index, and the number of pages used to store the
*           indexes.
*
*       Information about each index, where each index column is represented
*           by one row of the result set. The result set columns are given
*           in Columns returned by SQLStatistics in the order shown; the
*           rows in the result set are ordered by NON_UNIQUE, TYPE,
*           INDEX_QUALIFIER, INDEX_NAME and KEY_SEQ.
*/

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

#include "util.c"

#define STR_LEN 128 + 1
#define REM_LEN 254 + 1

// Arbitary sizes for number of tables and
#define MAX_TABLES 100

// Declare buffers for result set data
SQLCHAR strCatalog[STR_LEN];
SQLCHAR strSchema[STR_LEN];
SQLCHAR strTableName[STR_LEN];
SQLCHAR strIndexQualifier[STR_LEN];
SQLCHAR strIndexName[REM_LEN];
SQLCHAR strColumnName[STR_LEN];
SQLCHAR strAscDesc[STR_LEN];
SQLCHAR strFilterCond[STR_LEN];
SQLINTEGER  Cardinality;
SQLINTEGER  Pages;
SQLSMALLINT NonUnique;
SQLSMALLINT Type;
SQLSMALLINT OrdinalPosn;

SQLHSTMT hstmt = NULL;

// Declare buffers for bytes available to return
SQLLEN lenCatalog;
SQLLEN lenSchema;
SQLLEN lenTableName;
SQLLEN lenIndexQualifier;
SQLLEN lenIndexName;
SQLLEN lenColumnName;
SQLLEN lenAscDesc;
SQLLEN lenFilterCond;
SQLLEN lenCardinality;
SQLLEN lenPages;
SQLLEN lenNonUnique;
SQLLEN lenType;
SQLLEN lenOrdinalPosn;

struct DataBinding {
   SQLSMALLINT TargetType;
   SQLPOINTER TargetValuePtr;
   SQLINTEGER BufferLength;
   SQLLEN StrLen_or_Ind;
};

void Cleanup(SQLHSTMT henv, SQLHSTMT hdbc, SQLHSTMT hstmt) {

    if (hstmt != SQL_NULL_HSTMT)
        SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

    if (hdbc != SQL_NULL_HDBC) {
        SQLDisconnect(hdbc);
        SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
    }

    if (henv != SQL_NULL_HENV)
        SQLFreeHandle(SQL_HANDLE_ENV, henv);

    return;
}

// Gets list of tables based on iTableStrPtr
int getTheseTables (char *pTableName, SQLCHAR *tableNames[]) {

    int bufferSize = 1024, i, j, count = 1, numCols = 5;
    SQLCHAR * dbName = (SQLCHAR *)malloc( sizeof(SQLCHAR)*bufferSize );
    SQLCHAR * userName = (SQLCHAR *)malloc( sizeof(SQLCHAR)*bufferSize );
    SQLCHAR connStrbuffer[1024];
    SQLSMALLINT connStrBufferLen, bufferLen;

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

    struct DataBinding* catalogResult = (struct DataBinding*)
                        malloc( numCols * sizeof(struct DataBinding) );
    SQLCHAR* selectAllQuery = (SQLCHAR *)malloc( sizeof(SQLCHAR) * bufferSize );

    // Connect to database
    retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
    CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_ENV)",
                henv, SQL_HANDLE_ENV);

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

    retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
    CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_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*) "DATASOURCE", SQL_NTS,
                                                (SQLCHAR*) NULL, 0, NULL, 0);
    CHECK_ERROR(retcode, "SQLConnect(DATASOURCE)",
                hdbc, SQL_HANDLE_DBC);

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

    // Display the database information
    retcode = SQLGetInfo(hdbc, SQL_DATABASE_NAME, dbName,
                         (SQLSMALLINT)bufferSize, (SQLSMALLINT *)&bufferLen);
    CHECK_ERROR(retcode, "SQLGetInfo(SQL_DATABASE_NAME)",
                hdbc, SQL_HANDLE_DBC);

    retcode = SQLGetInfo(hdbc, SQL_USER_NAME, userName,
                         (SQLSMALLINT)bufferSize, &bufferLen);
    CHECK_ERROR(retcode, "SQLGetInfo(SQL_USER_NAME)",
                hdbc, SQL_HANDLE_DBC);

    printf ("Current DB Name : %s\n", dbName);
    printf ("Current User Name : %s\n", userName);

    for ( i = 0 ; i < numCols ; i++ ) {
        catalogResult[i].TargetType = SQL_C_CHAR;
        catalogResult[i].BufferLength = (bufferSize + 1);
        catalogResult[i].TargetValuePtr =
                malloc( sizeof(unsigned char)*catalogResult[i].BufferLength );
    }

    // Set up the binding.
    for ( i = 0 ; i < numCols ; i++ ) {
        //printf ("Binding Column %i\n", i+1);
        retcode = SQLBindCol(hstmt,
                             (SQLUSMALLINT) i+1,
                             catalogResult[i].TargetType,
                             catalogResult[i].TargetValuePtr,
                             catalogResult[i].BufferLength,
                             &(catalogResult[i].StrLen_or_Ind));
        CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_ENV)",
                    hstmt, SQL_HANDLE_STMT);
    }

    retcode = SQLTables( hstmt, dbName, SQL_NTS, userName, SQL_NTS, "%",
                                        SQL_NTS, "TABLE", SQL_NTS );
    CHECK_ERROR(retcode, "SQLTables(dbName)", hstmt, SQL_HANDLE_STMT);

    // Create array of my tables starting with 'TestTBL'
    i=0;
    for ( retcode = SQLFetch(hstmt) ;
          retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO ;
          retcode = SQLFetch(hstmt), ++count ) {
        if ( strstr (catalogResult[2].TargetValuePtr, pTableName) != 0 ) {
            tableNames[i]=(char *)
              malloc((strlen(catalogResult[2].TargetValuePtr)+1)*sizeof(char));
            strcpy (tableNames[i], catalogResult[2].TargetValuePtr);
            printf( "Found Table %s\n", tableNames[i++] );
        }
    }
exit:
    Cleanup(henv, hdbc, hstmt);
    return i;
}

int main () {

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

    SQLCHAR *tableNames[MAX_TABLES];
    SQLINTEGER tableCount, i;

    retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
    CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_ENV)",
                henv, SQL_HANDLE_ENV);

    retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                                        (SQLPOINTER*)SQL_OV_ODBC3, 0);
    CHECK_ERROR(retcode, "SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)",
                henv, SQL_HANDLE_ENV);

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

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

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

    tableCount=getTheseTables ("TestTBL", tableNames);
    for (i=0; i<tableCount; i++) {
        printf ("\nTable : %s\n", tableNames[i]);

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

        retcode = SQLStatistics(hstmt, NULL, 0, NULL, 0,
                                    (SQLCHAR*)tableNames[i], SQL_NTS,
                                    SQL_INDEX_ALL, SQL_QUICK);

        if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
            // Clean buffers
            memset (strCatalog, ' ', STR_LEN);
            memset (strSchema, ' ', STR_LEN);
            memset (strTableName, ' ', STR_LEN);
            NonUnique=0;
            memset (strIndexQualifier, ' ', STR_LEN);
            memset (strIndexName, ' ', STR_LEN);
            Type=0;
            OrdinalPosn=0;
            memset (strColumnName, ' ', STR_LEN);
            memset (strAscDesc, ' ', STR_LEN);
            Cardinality=0;
            Pages=0;
            memset (strFilterCond, ' ', STR_LEN);

            // Bind columns in result set to buffers
            SQLBindCol(hstmt, 1,  SQL_C_CHAR,
                                  strCatalog, STR_LEN, &lenCatalog);
            SQLBindCol(hstmt, 2,  SQL_C_CHAR,
                                  strSchema, STR_LEN, &lenSchema);
            SQLBindCol(hstmt, 3,  SQL_C_CHAR,
                                  strTableName, STR_LEN,&lenTableName);
            SQLBindCol(hstmt, 4,  SQL_C_SSHORT,
                                  &NonUnique, 0, &lenNonUnique);
            SQLBindCol(hstmt, 5,  SQL_C_CHAR,
                                  strIndexQualifier, STR_LEN, &lenIndexQualifier);
            SQLBindCol(hstmt, 6,  SQL_C_CHAR,
                                  strIndexName, REM_LEN, &lenIndexName);
            SQLBindCol(hstmt, 7,  SQL_C_SSHORT,
                                  &Type, 0, &lenType);
            SQLBindCol(hstmt, 8,  SQL_C_SSHORT,
                                  &OrdinalPosn, 0, &lenOrdinalPosn);
            SQLBindCol(hstmt, 9,  SQL_C_CHAR,
                                  strColumnName, STR_LEN, &lenColumnName);
            SQLBindCol(hstmt, 10, SQL_C_CHAR,
                                  strAscDesc, STR_LEN, &lenAscDesc);
            SQLBindCol(hstmt, 11, SQL_C_SLONG,
                                  &Cardinality, 0, &lenCardinality);
            SQLBindCol(hstmt, 12, SQL_C_SLONG,
                                  &Pages, 0, &lenPages);
            SQLBindCol(hstmt, 13, SQL_C_CHAR,
                                  strFilterCond, STR_LEN, &lenFilterCond);

            while (retcode == SQL_SUCCESS) {
                retcode = SQLFetch(hstmt);

                CHECK_ERROR(retcode, "SQLFetch(SQLStatistics)",
                            hstmt, SQL_HANDLE_STMT);

                printf ("\nCatalog %s\n",     rtrim(strCatalog, ' '));
                printf ("Schema %s\n",        rtrim(strSchema, ' '));
                printf ("TableName %s\n",     rtrim(strTableName, ' '));
                printf ("NonUnique %i\n",     NonUnique);
                printf ("IndexQualifier %s\n",rtrim(strIndexQualifier, ' '));
                printf ("IndexName %s\n",     rtrim(strIndexName, ' '));
                printf ("Type %i\n",          Type);
                printf ("OrdinalPosn %i\n",   OrdinalPosn);
                printf ("ColumnName %s\n",    rtrim(strColumnName, ' '));
                printf ("AscDesc %s\n",       rtrim(strAscDesc, ' '));
                printf ("Cardinality %i\n",   Cardinality);
                printf ("Pages %i\n",         Pages);
                printf ("FilterCond %s\n",    rtrim(strFilterCond, ' '));
            }
        } else {
            CHECK_ERROR(retcode, "SQLStatistics()", hstmt, SQL_HANDLE_STMT);
        }
        SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
    }

exit:
    printf ("\nComplete.\n");

    // Free statement, connection and environment handle
    Cleanup(henv, hdbc, hstmt);

    return 0;
}

Further information