SQLDescribeCol() - Describe column attributes

SQLDescribeCol() returns commonly used descriptor information about a column in a result set that a query generates. Before you call this function, you must call either SQLPrepare() or SQLExecDirect().

ODBC specifications for SQLDescribeCol()

Table 1. SQLDescribeCol() specifications
ODBC specification level In X/Open CLI CAE specification? In ISO CLI specification?
1.0 Yes Yes

Syntax

For 31-bit applications, use the following syntax:

SQLRETURN   SQLDescribeCol   (SQLHSTMT          hstmt,
                              SQLUSMALLINT      icol,
                              SQLCHAR     FAR   *szColName,
                              SQLSMALLINT       cbColNameMax,
                              SQLSMALLINT FAR   *pcbColName,
                              SQLSMALLINT FAR   *pfSqlType,
                              SQLUINTEGER FAR   *pcbColDef,
                              SQLSMALLINT FAR   *pibScale,
                              SQLSMALLINT FAR   *pfNullable);

For 64-bit applications, use the following syntax:

SQLRETURN   SQLDescribeCol   (SQLHSTMT          hstmt,
                              SQLUSMALLINT      icol,
                              SQLCHAR     FAR   *szColName,
                              SQLSMALLINT       cbColNameMax,
                              SQLSMALLINT FAR   *pcbColName,
                              SQLSMALLINT FAR   *pfSqlType,
                              SQLULEN     FAR   *pcbColDef,
                              SQLSMALLINT FAR   *pibScale,
                              SQLSMALLINT FAR   *pfNullable);

Function arguments

The following table lists the data type, use, and description for each argument in this function.

Table 2. SQLDescribeCol() arguments
Data type Argument Use Description
SQLHSTMT hstmt input Specifies a statement handle.
SQLUSMALLINT icol input Specifies the column number to be described. Columns are numbered sequentially from left to right, starting at 1.
SQLCHAR * szColName output Specifies the pointer to the buffer that is to hold the name of the column. Set this to a null pointer if you do not need to receive the name of the column.
SQLSMALLINT cbColNameMax input Specifies the size of the buffer to which the szColName argument points.
SQLSMALLINT * pcbColName output Returns the number of bytes that the complete column name requires. Truncation of column name (szColName) to cbColNameMax - 1 bytes occurs if pcbColName is greater than or equal to cbColNameMax.
SQLSMALLINT * pfSqlType output Returns the base SQL data type of column. To determine if a distinct type is associated with the column, call SQLColAttribute() with fDescType set to SQL_COLUMN_DISTINCT_TYPE.
SQLUINTEGER *(31-bit) or SQLULEN * (64-bit) 1 pcbColDef output Returns the precision of the column as defined in the database.
SQLSMALLINT * pibScale output Scale of column as defined in the database (applies only to SQL_DECIMAL, SQL_NUMERIC, SQL_TYPE_TIMESTAMP, and SQL_TYPE_TIMESTAMP_WITH_TIMEZONE).
SQLSMALLINT * pfNullable output Indicates whether null values are allowed for the column with the following values:
  • SQL_NO_NULLS
  • SQL_NULLABLE
Notes:
  1. For 64-bit applications, the data type SQLUINTEGER, which was used in previous versions of Db2, is still valid. However, for maximum application portability, using SQLULEN is recommended.

Usage

If you need only one attribute of the descriptor information (column name, type, precision, scale, nullability), or if you need an attribute that SQLDescribeCol() does not return, use SQLColAttribute() in place of SQLDescribeCol().

Usually, you call this function (or the SQLColAttribute() function) before you bind a column to an application variable.

Columns are identified by a number, are numbered sequentially from left to right starting with 1, and can be described in any order.

If a null pointer is specified for any of the pointer arguments, Db2 ODBC assumes that the information is not needed by the application, and nothing is returned.

If the column is a distinct type, SQLDescribeCol() returns only the built-in type in the pfSqlType argument. Call SQLColAttribute() with the fDescType argument set to SQL_COLUMN_DISTINCT_TYPE to obtain the distinct type.

Return codes

After you call SQLDescribeCol(), it returns one of the following values:
  • SQL_SUCCESS
  • SQL_SUCCESS_WITH_INFO
  • SQL_ERROR
  • SQL_INVALID_HANDLE

Diagnostics

If SQLDescribeCol() returns either SQL_ERROR or SQL_SUCCESS_WITH_INFO, you can call SQLGetDiagRec() to obtain one of the SQLSTATEs that are listed in the following table.

Table 3. SQLDescribeCol() SQLSTATEs
SQLSTATE Description Explanation
01004 Data truncated. The column name that is returned in the szColName argument is longer than the specified value in the cbColNameMax argument. The argument pcbColName contains the length, in bytes, of the full column name. (SQLDescribeCol() returns SQL_SUCCESS_WITH_INFO for this SQLSTATE)
07005 The statement did not return a result set. The statement that is associated with the statement handle did not return a result set. No columns exist to describe. (Call SQLNumResultCols() first to determine if any rows are in the result set.)
08S01 Communication link failure. The communication link between the application and data source fails before the function completes.
58004 Unexpected system failure. Unrecoverable system error.
HY001 Memory allocation failure. Db2 ODBC is not able to allocate the required memory to support the execution or the completion of the function.
HY010 Function sequence error. This SQLSTATE is returned for one or more of the following reasons:
  • The function is called prior to SQLPrepare() or SQLExecDirect() on the statement handle.
  • The function is called during a data-at-execute operation. (That is, the function is called during a procedure that uses the SQLParamData() or SQLPutData() functions.)
HY013 Unexpected memory handling error. Db2 ODBC is not able to access the memory that is required to support execution or completion of the function.
HY090 Invalid string or buffer length. The length that is specified in the cbColNameMax argument is less than 1.
HYC00 Driver not capable. Db2 ODBC does not recognize the SQL data type of column that the icol argument specifies.
HY002 Invalid column number. The value that the icol argument specifies is less than 1, or it is greater than the number of columns in the result set.

Example

The following example shows an application that uses SQLDescribeCol() to retrieve descriptor information about table columns.
Figure 1. An application that retrieves column descriptor information
/* ... */
/*******************************************************************
** process_stmt
** - allocates a statement handle
** - executes the statement
** - determines the type of statement
**   - if no result columns exist, therefore non-select statement
**      - if rowcount > 0, assume statement was UPDATE, INSERT, DELETE
**     else
**      - assume a DDL, or Grant/Revoke statement
**     else
**      - must be a select statement.
**      - display results
** - frees the statement handle
*******************************************************************/
int
process_stmt(SQLHENV henv,
             SQLHDBC hdbc,
             SQLCHAR * sqlstr)
{
    SQLHSTMT        hstmt;
    SQLSMALLINT     nresultcols;
    SQLINTEGER      rowcount;
    SQLRETURN       rc;
    /* Allocate a statement handle */
    SQLAllocHandle( SQL_ HANDLE_STMT, hdbc, &hstmt);
    /* Execute the SQL statement in "sqlstr"    */
    rc = SQLExecDirect(hstmt, sqlstr, SQL_NTS);
    if (rc != SQL_SUCCESS)
        if (rc == SQL_NO_DATA_FOUND) {
            printf("\nStatement executed without error, however,\n");
            printf("no data was found or modified\n");
            return (SQL_SUCCESS);
        } else
            CHECK_HANDLE( SQL_HANDLE_STMT, hstmt, rc);
    rc = SQLNumResultCols(hstmt, &nresultcols);
    /* Determine statement type */
    if (nresultcols == 0) {     /* statement is not a select statement */
        rc = SQLRowCount(hstmt, &rowcount);
        if (rowcount > 0) {     /* assume statement is UPDATE, INSERT, DELETE */
            printf("Statement executed, %ld rows affected\n", rowcount);
        } else {                /* assume statement is GRANT, REVOKE or a DLL
                                 * statement */
            printf("Statement completed successful\n");
        }
    } else {                    /* display the result set */
        display_results(hstmt, nresultcols);
    }                           /* end determine statement type */
    rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); /* Free statement handle */
    return (0);
}                               /* end process_stmt */
/*******************************************************************
** display_results
**  - for each column
**      - get column name
**      - bind column
**  - display column headings
**  - fetch each row
**      - if value truncated, build error message
**      - if column null, set value to "NULL"
**      - display row
**      - print truncation message
**  - free local storage
*******************************************************************/
display_results(SQLHSTMT hstmt,
                SQLSMALLINT nresultcols)
{
    SQLCHAR         colname[32];
    SQLSMALLINT     coltype;
    SQLSMALLINT     colnamelen;
    SQLSMALLINT     nullable;
    SQLINTEGER      collen[MAXCOLS];
    SQLUINTEGER     precision;
    SQLSMALLINT     scale;
    SQLINTEGER      outlen[MAXCOLS];
    SQLCHAR        *data[MAXCOLS];
    SQLCHAR         errmsg[256];
    SQLRETURN       rc;
    SQLINTEGER      i;
    SQLINTEGER      x;
    SQLINTEGER      displaysize;
    for (i = 0; i < nresultcols; i++) {
        SQLDescribeCol(hstmt, i + 1, colname, sizeof(colname),
                       &colnamelen, &coltype, &precision, &scale, NULL);
        collen[i] = precision; /* Note, assignment of unsigned int to signed */
        /* Get display length for column */
        SQLColAttribute(hstmt, i + 1, SQL_COLUMN_DISPLAY_SIZE, NULL, 0,
                         NULL, &displaysize);
        /*
         * Set column length to max of display length, and column name
         * length. Plus one byte for null terminator
         */
        collen[i] = max(displaysize, strlen((char *) colname)) + 1;
        printf("%-*.*s", collen[i], collen[i], colname);
        /* Allocate memory to bind column                             */
        data[i] = (SQLCHAR *) malloc(collen[i]);
        /* Bind columns to program vars, converting all types to CHAR */
        rc = SQLBindCol(hstmt, i + 1, SQL_C_CHAR, data[i], collen[i], &outlen[i]);
    }
    printf("\n");
    /* Display result rows                                            */
    while ((rc = SQLFetch(hstmt)) != SQL_NO_DATA_FOUND) {
        errmsg[0] = '\0';
        for (i = 0; i < nresultcols; i++) {
            /* Build a truncation message for any columns truncated */
            if (outlen[i] >= collen[i]) {
                sprintf((char *) errmsg + strlen((char *) errmsg),
                        "%ld chars truncated, col %d\n",
                        outlen[i] - collen[i] + 1, i + 1);
                sprintf((char *) errmsg + strlen((char *) errmsg),
                        "Bytes to return = %ld size of buffer\n",
                        outlen[i], collen[i]);
            }
            if (outlen[i] == SQL_NULL_DATA)
                printf("%-*.*s", collen[i], collen[i], "NULL");
            else
                printf("%-*.*s", collen[i], collen[i], data[i]);
        }                       /* for all columns in this row  */
        printf("\n%s", errmsg); /* print any truncation messages */
    }                           /* while rows to fetch */
    /* Free data buffers                                              */
    for (i = 0; i < nresultcols; i++) {
        free(data[i]);
    }
}                               /* end display_results */
/* ... */