/*********************************************************************
 *
 * This is based on code created by Peter Harvey,
 * (pharvey@codebydesign.com).
 *
 * Modified and extended by Nick Gorham
 * (nick@easysoft.com).
 *
 * Any bugs or problems should be considered the fault of Nick and not
 * Peter.
 *
 * copyright (c) 1999 Nick Gorham
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 **********************************************************************
 *
 * $Id: __info.c,v 1.2 1999/12/10 01:50:38 harvey Exp $
 *
 * $Log: __info.c,v $
 * Revision 1.2  1999/12/10 01:50:38  harvey
 * Updated with current sources from unixODBC cvs.
 *
 * Revision 1.15  1999/12/04 17:01:23  ngorham
 *
 * Remove C++ comments from the Postgres code
 *
 * Revision 1.14  1999/12/01 09:20:07  ngorham
 *
 * Fix some threading problems
 *
 * Revision 1.13  1999/11/17 21:08:58  ngorham
 *
 * Fix Bug with the ODBC 3 error handling
 *
 * Revision 1.12  1999/11/13 23:41:01  ngorham
 *
 * Alter the way DM logging works
 * Upgrade the Postgres driver to 6.4.6
 *
 * Revision 1.11  1999/11/10 22:15:48  ngorham
 *
 * Fix some bugs with the DM and error reporting.
 *
 * Revision 1.10  1999/11/10 03:51:34  ngorham
 *
 * Update the error reporting in the DM to enable ODBC 3 and 2 calls to
 * work at the same time
 *
 * Revision 1.9  1999/10/24 23:54:19  ngorham
 *
 * First part of the changes to the error reporting
 *
 * Revision 1.8  1999/10/03 23:05:16  ngorham
 *
 * First public outing of the cursor lib
 *
 * Revision 1.7  1999/09/19 22:24:34  ngorham
 *
 * Added support for the cursor library
 *
 * Revision 1.6  1999/08/03 21:47:39  shandyb
 * Moving to automake: changed files in DriverManager
 *
 * Revision 1.5  1999/07/10 21:10:17  ngorham
 *
 * Adjust error sqlstate from driver manager, depending on requested
 * version (ODBC2/3)
 *
 * Revision 1.4  1999/07/05 19:54:05  ngorham
 *
 * Fix a problem where a long string could crash the DM
 *
 * Revision 1.3  1999/07/04 21:05:08  ngorham
 *
 * Add LGPL Headers to code
 *
 * Revision 1.2  1999/06/19 17:51:41  ngorham
 *
 * Applied assorted minor bug fixes
 *
 * Revision 1.1.1.1  1999/05/29 13:41:09  sShandyb
 * first go at it
 *
 * Revision 1.2  1999/06/03 22:20:25  ngorham
 *
 * Finished off the ODBC3-2 mapping
 *
 * Revision 1.1.1.1  1999/05/27 18:23:18  pharvey
 * Imported sources
 *
 *
 *
 **********************************************************************/

#include "drivermanager.h"

static char const rcsid[]= "$RCSfile: __info.c,v $ $Revision: 1.2 $";

/*
 * display a SQLGetTypeInfo type as a astring
 */

char * __type_as_string( SQLCHAR *s, SQLSMALLINT type )
{
    switch( type )
    {
      case SQL_DOUBLE:
        sprintf( s, "SQL_DOUBLE" );
        break;

      case SQL_FLOAT:
        sprintf( s, "SQL_FLOAT" );
        break;

      case SQL_REAL:
        sprintf( s, "SQL_REAL" );
        break;

      case SQL_BIT:
        sprintf( s, "SQL_BIT" );
        break;

      case SQL_CHAR:
        sprintf( s, "SQL_CHAR" );
        break;

      case SQL_VARCHAR:
        sprintf( s, "SQL_VARCHAR" );
        break;

      case SQL_LONGVARCHAR:
        sprintf( s, "SQL_LONGVARCHAR" );
        break;

      case SQL_BINARY:
        sprintf( s, "SQL_BINARY" );
        break;

      case SQL_VARBINARY:
        sprintf( s, "SQL_VARBINARY" );
        break;

      case SQL_LONGVARBINARY:
        sprintf( s, "SQL_LONGVARBINARY" );
        break;

      case SQL_DECIMAL:
        sprintf( s, "SQL_DECIMAL" );
        break;

      case SQL_NUMERIC:
        sprintf( s, "SQL_NUMERIC" );
        break;

      case SQL_BIGINT:
        sprintf( s, "SQL_BIGINT" );
        break;

      case SQL_INTEGER:
        sprintf( s, "SQL_INTEGER" );
        break;

      case SQL_SMALLINT:
        sprintf( s, "SQL_SMALLINT" );
        break;

      case SQL_TINYINT:
        sprintf( s, "SQL_TINYINT" );
        break;

      case SQL_TYPE_DATE:
        sprintf( s, "SQL_TYPE_DATE" );
        break;

      case SQL_TYPE_TIME:
        sprintf( s, "SQL_TYPE_TIME" );
        break;

      case SQL_TYPE_TIMESTAMP:
        sprintf( s, "SQL_TYPE_TIMESTAMP" );
        break;

      case SQL_DATE:
        sprintf( s, "SQL_DATE" );
        break;

      case SQL_TIME:
        sprintf( s, "SQL_TIME" );
        break;

      case SQL_TIMESTAMP:
        sprintf( s, "SQL_TIMESTAMP" );
        break;

      case SQL_INTERVAL_YEAR:
        sprintf( s, "SQL_INTERVAL_YEAR" );
        break;

      case SQL_INTERVAL_YEAR_TO_MONTH:
        sprintf( s, "SQL_INTERVAL_YEAR_TO_MONTH" );
        break;

      case SQL_INTERVAL_MONTH:
        sprintf( s, "SQL_INTERVAL_MONTH" );
        break;

      case SQL_INTERVAL_DAY_TO_SECOND:
        sprintf( s, "SQL_INTERVAL_DAY_TO_SECOND" );
        break;

      case SQL_INTERVAL_DAY_TO_MINUTE:
        sprintf( s, "SQL_INTERVAL_DAY_TO_MINUTE" );
        break;

      case SQL_INTERVAL_DAY:
        sprintf( s, "SQL_INTERVAL_DAY" );
        break;

      case SQL_INTERVAL_HOUR_TO_SECOND:
        sprintf( s, "SQL_INTERVAL_HOUR_TO_SECOND" );
        break;

      case SQL_INTERVAL_HOUR_TO_MINUTE:
        sprintf( s, "SQL_INTERVAL_HOUR_TO_MINUTE" );
        break;

      case SQL_INTERVAL_HOUR:
        sprintf( s, "SQL_INTERVAL_HOUR" );
        break;

      case SQL_INTERVAL_MINUTE_TO_SECOND:
        sprintf( s, "SQL_INTERVAL_MINUTE_TO_SECOND" );
        break;

      case SQL_INTERVAL_MINUTE:
        sprintf( s, "SQL_INTERVAL_MINUTE" );
        break;

      case SQL_INTERVAL_SECOND:
        sprintf( s, "SQL_INTERVAL_SECOND" );
        break;

      case SQL_ALL_TYPES:
        sprintf( s, "SQL_ALL_TYPES" );
        break;

      default:
        sprintf( s, "Unknown(%d)", (int)type );
        break;
    }

    return s;
}

/*
 * display a data field as a string
 */

char * __sdata_as_string( SQLCHAR *s, SQLINTEGER type, 
        SQLSMALLINT *ptr, SQLPOINTER buf )
{
    SQLINTEGER iptr;

    if ( ptr )
    {
        iptr = *ptr;
        return __data_as_string( s, type, &iptr, buf );
    }
    else
    {
        return __data_as_string( s, type, NULL, buf );
    }

    return s;
}

char * __data_as_string( SQLCHAR *s, SQLINTEGER type, 
        SQLINTEGER *ptr, SQLPOINTER buf )
{
    if ( ptr && *ptr == SQL_NULL_DATA )
    {
        sprintf( s, "SQL_NULL_DATA" );
    }
    else if ( ptr && *ptr < 0 )
    {
        sprintf( s, "Indicator = %d", (int)*ptr );
    } 
    else if ( !buf )
    {
        sprintf( s, "[NULLPTR]" );
    }
    else
    {
        switch ( type )
        {
          case SQL_INTEGER:
            {
                SQLINTEGER val;

                memcpy( &val, buf, sizeof( SQLINTEGER ));
                sprintf( s, "[%d]", (int)val );
            }
            break;

          case SQL_CHAR:
          case SQL_VARCHAR:
            sprintf( s, "[%.64s]", (char*)buf );
            break;

          case SQL_DOUBLE:
            {
                double val;

                memcpy( &val, buf, sizeof( double ));
                sprintf( s, "[%g]", val );
            }
            break;

          case SQL_FLOAT:
          case SQL_REAL:
            {
                float val;

                memcpy( &val, buf, sizeof( float ));
                sprintf( s, "[%g]", val );
            }
            break;

          case SQL_BIT:
            {
                SQLCHAR val;

                memcpy( &val, buf, sizeof( SQLCHAR ));
                sprintf( s, "[%d]", (int)val );
            }
            break;

          case SQL_LONGVARCHAR:
            sprintf( s, "[LONGVARCHARDATA...]" );
            break;

          case SQL_BINARY:
            sprintf( s, "[BINARYDATA...]" );
            break;

          case SQL_VARBINARY:
            sprintf( s, "[VARBINARYDATA...]" );
            break;

          case SQL_LONGVARBINARY:
            sprintf( s, "[LONGVARBINARYDATA...]" );
            break;

          case SQL_DECIMAL:
            sprintf( s, "[DECIMAL...]" );
            break;

          case SQL_NUMERIC:
            sprintf( s, "[NUMERIC...]" );
            break;

          case SQL_BIGINT:
            sprintf( s, "[BIGINT...]" );
            break;

          case SQL_SMALLINT:
            {
                short val;

                memcpy( &val, buf, sizeof( short ));
                sprintf( s, "[%d]", (int)val );
            }
            break;

          case SQL_TINYINT:
            {
                char val;

                memcpy( &val, buf, sizeof( char ));
                sprintf( s, "[%d]", (int)val );
            }
            break;

          case SQL_TYPE_DATE:
          case SQL_DATE:
            sprintf( s, "[DATE...]" );
            break;

          case SQL_TYPE_TIME:
          case SQL_TIME:
            sprintf( s, "[TIME...]" );
            break;

          case SQL_TYPE_TIMESTAMP:
          case SQL_TIMESTAMP:
            sprintf( s, "[TIMESTAMP...]" );
            break;

          case SQL_INTERVAL_YEAR:
          case SQL_INTERVAL_YEAR_TO_MONTH:
          case SQL_INTERVAL_MONTH:
          case SQL_INTERVAL_DAY_TO_SECOND:
          case SQL_INTERVAL_DAY_TO_MINUTE:
          case SQL_INTERVAL_DAY:
          case SQL_INTERVAL_HOUR_TO_SECOND:
          case SQL_INTERVAL_HOUR_TO_MINUTE:
          case SQL_INTERVAL_HOUR:
          case SQL_INTERVAL_MINUTE_TO_SECOND:
          case SQL_INTERVAL_MINUTE:
          case SQL_INTERVAL_SECOND:
            sprintf( s, "[INTERVAL...]" );
            break;

          default:
            sprintf( s, "[Data...]" );
            break;
        }
    }

    return s;
}

/*
 * display a pointer to a int
 */

char * __ptr_as_string( SQLCHAR *s, SQLINTEGER *ptr )
{
    if ( ptr )
    {
        sprintf( s, "%p -> %d", (void*)ptr, (int)*ptr );
    }
    else
    {
        sprintf( s, "NULLPTR" );
    }

    return s;
}

/*
 * display a pointer to a int
 */

char * __sptr_as_string( SQLCHAR *s, SQLSMALLINT *ptr )
{
    if ( ptr )
    {
        sprintf( s, "%p -> %d", (void*)ptr, (int)*ptr );
    }
    else
    {
        sprintf( s, "NULLPTR" );
    }

    return s;
}

/*
 * convert a function id to a string
 */

char * __fid_as_string( SQLCHAR *s, SQLINTEGER type )
{
    switch( type )
    {
      case SQL_API_SQLALLOCCONNECT:
        sprintf( s, "SQLAllocConnect" );
        break;

     case SQL_API_SQLALLOCENV:
        sprintf( s, "SQLAllocEnv" );
        break;

      case SQL_API_SQLALLOCHANDLE:
        sprintf( s, "SQLAllocHandle" );
        break;

      case SQL_API_SQLALLOCSTMT:
        sprintf( s, "SQLAllocStmt" );
        break;

      case SQL_API_SQLALLOCHANDLESTD:
        sprintf( s, "SQLAllochandleStd" );
        break;

      case SQL_API_SQLBINDCOL:
        sprintf( s, "SQLBindCol" );
        break;

      case SQL_API_SQLBINDPARAM:
        sprintf( s, "SQLBindParam" );
        break;

      case SQL_API_SQLBINDPARAMETER:
        sprintf( s, "SQLBindParameter" );
        break;

      case SQL_API_SQLBROWSECONNECT:
        sprintf( s, "SQLBrowseConnect" );
        break;

      case SQL_API_SQLBULKOPERATIONS:
        sprintf( s, "SQLBulkOperations" );
        break;

      case SQL_API_SQLCANCEL:
        sprintf( s, "SQLCancel" );
        break;

      case SQL_API_SQLCLOSECURSOR:
        sprintf( s, "SQLCloseCursor" );
        break;

      case SQL_API_SQLCOLATTRIBUTES:
        sprintf( s, "SQLColAttribute(s)" );
        break;

      case SQL_API_SQLCOLUMNPRIVILEGES:
        sprintf( s, "SQLColumnPrivileges" );
        break;

      case SQL_API_SQLCOLUMNS:
        sprintf( s, "SQLColumns" );
        break;

      case SQL_API_SQLCONNECT:
        sprintf( s, "SQLConnect" );
        break;

      case SQL_API_SQLCOPYDESC:
        sprintf( s, "SQLCopyDesc" );
        break;

      case SQL_API_SQLDATASOURCES:
        sprintf( s, "SQLDataSources" );
        break;

      case SQL_API_SQLDESCRIBECOL:
        sprintf( s, "SQLDescribeCol" );
        break;

      case SQL_API_SQLDESCRIBEPARAM:
        sprintf( s, "SQLDescribeParam" );
        break;

      case SQL_API_SQLDISCONNECT:
        sprintf( s, "SQLDisconnect" );
        break;

      case SQL_API_SQLDRIVERCONNECT:
        sprintf( s, "SQLDriverConnect" );
        break;

      case SQL_API_SQLDRIVERS:
        sprintf( s, "SQLDrivers" );
        break;

      case SQL_API_SQLENDTRAN:
        sprintf( s, "SQLEndTran" );
        break;

      case SQL_API_SQLERROR:
        sprintf( s, "SQLError" );
        break;

      case SQL_API_SQLEXECDIRECT:
        sprintf( s, "SQLExecDirect" );
        break;

      case SQL_API_SQLEXECUTE:
        sprintf( s, "SQLExecute" );
        break;

      case SQL_API_SQLEXTENDEDFETCH:
        sprintf( s, "SQLExtendedFetch" );
        break;

      case SQL_API_SQLFETCH:
        sprintf( s, "SQLFetch" );
        break;

      case SQL_API_SQLFETCHSCROLL:
        sprintf( s, "SQLFetchScroll" );
        break;

      case SQL_API_SQLFOREIGNKEYS:
        sprintf( s, "SQLForeignKeys" );
        break;

      case SQL_API_SQLFREEENV:
        sprintf( s, "SQLFreeEnv" );
        break;

      case SQL_API_SQLFREEHANDLE:
        sprintf( s, "SQLFreeHandle" );
        break;

      case SQL_API_SQLFREESTMT:
        sprintf( s, "SQLFreeStmt" );
        break;

      case SQL_API_SQLFREECONNECT:
        sprintf( s, "SQLFreeConnect" );
        break;

       case SQL_API_SQLGETCONNECTATTR:
        sprintf( s, "SQLGetConnectAttr" );
        break;

      case SQL_API_SQLGETCONNECTOPTION:
        sprintf( s, "SQLGetConnectOption" );
        break;

      case SQL_API_SQLGETCURSORNAME:
        sprintf( s, "SQLGetCursorName" );
        break;

      case SQL_API_SQLGETDATA:
        sprintf( s, "SQLGetData" );
        break;

      case SQL_API_SQLGETDESCFIELD:
        sprintf( s, "SQLGetDescField" );
        break;

      case SQL_API_SQLGETDESCREC:
        sprintf( s, "SQLGetDescRec" );
        break;

      case SQL_API_SQLGETDIAGFIELD:
        sprintf( s, "SQLGetDiagField" );
        break;

      case SQL_API_SQLGETENVATTR:
        sprintf( s, "SQLGetEnvAttr" );
        break;

      case SQL_API_SQLGETFUNCTIONS:
        sprintf( s, "SQLGetFunctions" );
        break;

      case SQL_API_SQLGETINFO:
        sprintf( s, "SQLGetInfo" );
        break;

      case SQL_API_SQLGETSTMTATTR:
        sprintf( s, "SQLGetStmtAttr" );
        break;

      case SQL_API_SQLGETSTMTOPTION:
        sprintf( s, "SQLGetStmtOption" );
        break;

      case SQL_API_SQLGETTYPEINFO:
        sprintf( s, "SQLGetTypeInfo" );
        break;

      case SQL_API_SQLMORERESULTS:
        sprintf( s, "SQLMoreResults" );
        break;

      case SQL_API_SQLNATIVESQL:
        sprintf( s, "SQLNativeSql" );
        break;

      case SQL_API_SQLNUMPARAMS:
        sprintf( s, "SQLNumParams" );
        break;

      case SQL_API_SQLNUMRESULTCOLS:
        sprintf( s, "SQLNumResultCols" );
        break;

      case SQL_API_SQLPARAMDATA:
        sprintf( s, "SQLParamData" );
        break;

      case SQL_API_SQLPARAMOPTIONS:
        sprintf( s, "SQLParamOptions" );
        break;

      case SQL_API_SQLPREPARE:
        sprintf( s, "SQLPrepare" );
        break;

      case SQL_API_SQLPRIMARYKEYS:
        sprintf( s, "SQLPrimaryKeys" );
        break;

      case SQL_API_SQLPROCEDURECOLUMNS:
        sprintf( s, "SQLProcedureColumns" );
        break;

      case SQL_API_SQLPROCEDURES:
        sprintf( s, "SQLProcedures" );
        break;

      case SQL_API_SQLPUTDATA:
        sprintf( s, "SQLPutData" );
        break;

      case SQL_API_SQLROWCOUNT:
        sprintf( s, "SQLRowCount" );
        break;

      case SQL_API_SQLSETCONNECTATTR:
        sprintf( s, "SQLSetConnectAttr" );
        break;

      case SQL_API_SQLSETCONNECTOPTION:
        sprintf( s, "SQLSetConnectOption" );
        break;

      case SQL_API_SQLSETCURSORNAME:
        sprintf( s, "SQLSetCursorName" );
        break;

      case SQL_API_SQLSETDESCFIELD:
        sprintf( s, "SQLSetDescField" );
        break;

      case SQL_API_SQLSETDESCREC:
        sprintf( s, "SQLSetDescRec" );
        break;

      case SQL_API_SQLSETENVATTR:
        sprintf( s, "SQLSetEnvAttr" );
        break;

      case SQL_API_SQLSETPARAM:
        sprintf( s, "SQLSetParam" );
        break;

      case SQL_API_SQLSETPOS:
        sprintf( s, "SQLSetPos" );
        break;

      case SQL_API_SQLSETSCROLLOPTIONS:
        sprintf( s, "SQLSetScrollOptions" );
        break;

      case SQL_API_SQLSETSTMTATTR:
        sprintf( s, "SQLSetStmtAttr" );
        break;

      case SQL_API_SQLSETSTMTOPTION:
        sprintf( s, "SQLSetStmtOption" );
        break;

      case SQL_API_SQLSPECIALCOLUMNS:
        sprintf( s, "SQLSpecialColumns" );
        break;

      case SQL_API_SQLSTATISTICS:
        sprintf( s, "SQLStatistics" );
        break;

      case SQL_API_SQLTABLEPRIVILEGES:
        sprintf( s, "SQLTablePrivileges" );
        break;

      case SQL_API_SQLTABLES:
        sprintf( s, "SQLTables" );
        break;

      case SQL_API_SQLTRANSACT:
        sprintf( s, "SQLTransact" );
        break;

      case SQL_API_SQLGETDIAGREC:
        sprintf( s, "SQLGetDiagRec" );
        break;

      default:
        sprintf( s, "%d", (int)type );
    }

    return s;
}

/*
 * convert a column attribute to a string
 */

char * __col_attr_as_string( SQLCHAR *s, SQLINTEGER type )
{
    switch( type )
    {
      case SQL_DESC_AUTO_UNIQUE_VALUE:
        sprintf( s, "SQL_DESC_AUTO_UNIQUE_VALUE" );
        break;

      case SQL_DESC_BASE_COLUMN_NAME:
        sprintf( s, "SQL_DESC_BASE_COLUMN_NAME" );
        break;

      case SQL_DESC_BASE_TABLE_NAME:
        sprintf( s, "SQL_DESC_BASE_TABLE_NAME" );
        break;

      case SQL_DESC_CASE_SENSITIVE:
        sprintf( s, "SQL_DESC_CASE_SENSITIVE" );
        break;

      case SQL_DESC_CATALOG_NAME:
        sprintf( s, "SQL_DESC_CATALOG_NAME" );
        break;

      case SQL_DESC_CONCISE_TYPE:
        sprintf( s, "SQL_DESC_CONCISE_TYPE" );
        break;

      case SQL_DESC_DISPLAY_SIZE:
        sprintf( s, "SQL_DESC_DISPLAY_SIZE" );
        break;

      case SQL_DESC_FIXED_PREC_SCALE:
        sprintf( s, "SQL_DESC_FIXED_PREC_SCALE" );
        break;

      case SQL_DESC_LABEL:
        sprintf( s, "SQL_DESC_LABEL" );
        break;

      case SQL_COLUMN_NAME:
        sprintf( s, "SQL_COLUMN_NAME" );
        break;

      case SQL_DESC_LENGTH:
        sprintf( s, "SQL_DESC_LENGTH" );
        break;

      case SQL_COLUMN_LENGTH:
        sprintf( s, "SQL_COLUMN_LENGTH" );
        break;

      case SQL_DESC_LITERAL_PREFIX:
        sprintf( s, "SQL_DESC_LITERAL_PREFIX" );
        break;

      case SQL_DESC_LITERAL_SUFFIX:
        sprintf( s, "SQL_DESC_LITERAL_SUFFIX" );
        break;

      case SQL_DESC_LOCAL_TYPE_NAME:
        sprintf( s, "SQL_DESC_LOCAL_TYPE_NAME" );
        break;

      case SQL_DESC_NAME:
        sprintf( s, "SQL_DESC_NAME" );
        break;

      case SQL_DESC_NULLABLE:
        sprintf( s, "SQL_DESC_NULLABLE" );
        break;

      case SQL_COLUMN_NULLABLE:
        sprintf( s, "SQL_COLUMN_NULLABLE" );
        break;

      case SQL_DESC_NUM_PREC_RADIX:
        sprintf( s, "SQL_DESC_NUM_PREC_RADIX" );
        break;

      case SQL_DESC_OCTET_LENGTH:
        sprintf( s, "SQL_DESC_OCTET_LENGTH" );
        break;

      case SQL_DESC_PRECISION:
        sprintf( s, "SQL_DESC_PRECISION" );
        break;

      case SQL_COLUMN_PRECISION:
        sprintf( s, "SQL_COLUMN_PRECISION" );
        break;

      case SQL_DESC_SCALE:
        sprintf( s, "SQL_DESC_SCALE" );
        break;

      case SQL_COLUMN_SCALE:
        sprintf( s, "SQL_COLUMN_SCALE" );
        break;

      case SQL_DESC_SCHEMA_NAME:
        sprintf( s, "SQL_DESC_SCHEMA_NAME" );
        break;

      case SQL_DESC_SEARCHABLE:
        sprintf( s, "SQL_DESC_SEARCHABLE" );
        break;

      case SQL_DESC_TABLE_NAME:
        sprintf( s, "SQL_DESC_TABLE_NAME" );
        break;

      case SQL_DESC_TYPE:
        sprintf( s, "SQL_DESC_TYPE" );
        break;

      case SQL_DESC_TYPE_NAME:
        sprintf( s, "SQL_DESC_TYPE_NAME" );
        break;

      case SQL_DESC_UNNAMED:
        sprintf( s, "SQL_DESC_UNNAMED" );
        break;

      case SQL_DESC_UNSIGNED:
        sprintf( s, "SQL_DESC_UNSIGNED" );
        break;

      case SQL_DESC_UPDATABLE:
        sprintf( s, "SQL_DESC_UPDATABLE" );
        break;

      default:
        sprintf( s, "%d", (int)type );
    }

    return s;
}

/*
 * convert a connect attribute to a string
 */

char * __env_attr_as_string( SQLCHAR *s, SQLINTEGER type )
{
    switch( type )
    {
      case SQL_ATTR_CONNECTION_POOLING:
        sprintf( s, "SQL_ATTR_CONNECTION_POOLING" );
        break;

      case SQL_ATTR_CP_MATCH:
        sprintf( s, "SQL_ATTR_CP_MATCH" );
        break;

      case SQL_ATTR_ODBC_VERSION:
        sprintf( s, "SQL_ATTR_ODBC_VERSION" );
        break;

      case SQL_ATTR_OUTPUT_NTS:
        sprintf( s, "SQL_ATTR_OUTPUT_NTS" );
        break;

      default:
        sprintf( s, "%d", (int)type );
    }

    return s;
}

/*
 * convert a connect attribute to a string
 */

char * __con_attr_as_string( SQLCHAR *s, SQLINTEGER type )
{
    switch( type )
    {
      case SQL_ATTR_ACCESS_MODE:
        sprintf( s, "SQL_ATTR_ACCESS_MODE" );
        break;

      case SQL_ATTR_ASYNC_ENABLE:
        sprintf( s, "SQL_ATTR_ASYNC_ENABLE" );
        break;

      case SQL_ATTR_AUTO_IPD:
        sprintf( s, "SQL_ATTR_AUTO_IPD" );
        break;

      case SQL_ATTR_AUTOCOMMIT:
        sprintf( s, "SQL_ATTR_AUTOCOMMIT" );
        break;

      case SQL_ATTR_CONNECTION_TIMEOUT:
        sprintf( s, "SQL_ATTR_CONNECTION_TIMEOUT" );
        break;

      case SQL_ATTR_CURRENT_CATALOG:
        sprintf( s, "SQL_ATTR_CURRENT_CATALOG" );
        break;

      case SQL_ATTR_LOGIN_TIMEOUT:
        sprintf( s, "SQL_ATTR_LOGIN_TIMEOUT" );
        break;

      case SQL_ATTR_METADATA_ID:
        sprintf( s, "SQL_ATTR_METADATA_ID" );
        break;

      case SQL_ATTR_ODBC_CURSORS:
        sprintf( s, "SQL_ATTR_ODBC_CURSORS" );
        break;

      case SQL_ATTR_PACKET_SIZE:
        sprintf( s, "SQL_ATTR_PACKET_SIZE" );
        break;

      case SQL_ATTR_QUIET_MODE:
        sprintf( s, "SQL_ATTR_QUIET_MODE" );
        break;

      case SQL_ATTR_TRACE:
        sprintf( s, "SQL_ATTR_TRACE" );
        break;

      case SQL_ATTR_TRACEFILE:
        sprintf( s, "SQL_ATTR_TRACEFILE" );
        break;

      case SQL_ATTR_TRANSLATE_LIB:
        sprintf( s, "SQL_ATTR_TRANSLATE_LIB" );
        break;

      case SQL_ATTR_TRANSLATE_OPTION:
        sprintf( s, "SQL_ATTR_TRANSLATE_OPTION" );
        break;

      case SQL_ATTR_TXN_ISOLATION:
        sprintf( s, "SQL_ATTR_TXN_ISOLATION" );
        break;

      default:
        sprintf( s, "%d", (int)type );
    }

    return s;
}

/*
 * convert a diagnostic attribute to a string
 */

char * __diag_attr_as_string( SQLCHAR *s, SQLINTEGER type )
{
    switch( type )
    {
      case SQL_DIAG_CURSOR_ROW_COUNT:
        sprintf( s, "SQL_DIAG_CURSOR_ROW_COUNT" );
        break;

      case SQL_DIAG_DYNAMIC_FUNCTION:
        sprintf( s, "SQL_DIAG_DYNAMIC_FUNCTION" );
        break;

      case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
        sprintf( s, "SQL_DIAG_DYNAMIC_FUNCTION_CODE" );
        break;

      case SQL_DIAG_NUMBER:
        sprintf( s, "SQL_DIAG_NUMBER" );
        break;

      case SQL_DIAG_RETURNCODE:
        sprintf( s, "SQL_DIAG_RETURNCODE" );
        break;

      case SQL_DIAG_ROW_COUNT:
        sprintf( s, "SQL_DIAG_ROW_COUNT" );
        break;

      case SQL_DIAG_CLASS_ORIGIN:
        sprintf( s, "SQL_DIAG_CLASS_ORIGIN" );
        break;

      case SQL_DIAG_COLUMN_NUMBER:
        sprintf( s, "SQL_DIAG_COLUMN_NUMBER" );
        break;

      case SQL_DIAG_CONNECTION_NAME:
        sprintf( s, "SQL_DIAG_CONNECTION_NAME" );
        break;

      case SQL_DIAG_MESSAGE_TEXT:
        sprintf( s, "SQL_DIAG_MESSAGE_TEXT" );
        break;

      case SQL_DIAG_NATIVE:
        sprintf( s, "SQL_DIAG_NATIVE" );
        break;

      case SQL_DIAG_ROW_NUMBER:
        sprintf( s, "SQL_DIAG_ROW_NUMBER" );
        break;

      case SQL_DIAG_SERVER_NAME:
        sprintf( s, "SQL_DIAG_SERVER_NAME" );
        break;

      case SQL_DIAG_SQLSTATE:
        sprintf( s, "SQL_DIAG_SQLSTATE" );
        break;

      case SQL_DIAG_SUBCLASS_ORIGIN:
        sprintf( s, "SQL_DIAG_SUBCLASS_ORIGIN" );
        break;

      default:
        sprintf( s, "%d", (int)type );
    }

    return s;
}

/*
 * convert a descriptor attribute to a string
 */

char * __desc_attr_as_string( SQLCHAR *s, SQLINTEGER type )
{
    switch( type )
    {
      case SQL_DESC_ALLOC_TYPE:
        sprintf( s, "SQL_DESC_ALLOC_TYPE" );
        break;

      case SQL_DESC_ARRAY_SIZE:
        sprintf( s, "SQL_DESC_ARRAY_SIZE" );
        break;

      case SQL_DESC_ARRAY_STATUS_PTR:
        sprintf( s, "SQL_DESC_ARRAY_STATUS_PTR" );
        break;

      case SQL_DESC_BIND_OFFSET_PTR:
        sprintf( s, "SQL_DESC_BIND_OFFSET_PTR" );
        break;

      case SQL_DESC_BIND_TYPE:
        sprintf( s, "SQL_DESC_BIND_TYPE" );
        break;

      case SQL_DESC_COUNT:
        sprintf( s, "SQL_DESC_COUNT" );
        break;

      case SQL_DESC_ROWS_PROCESSED_PTR:
        sprintf( s, "SQL_DESC_ROWS_PROCESSED_PTR" );
        break;

      case SQL_DESC_AUTO_UNIQUE_VALUE:
        sprintf( s, "SQL_DESC_AUTO_UNIQUE_VALUE" );
        break;

      case SQL_DESC_BASE_COLUMN_NAME:
        sprintf( s, "SQL_DESC_BASE_COLUMN_NAME" );
        break;

      case SQL_DESC_BASE_TABLE_NAME:
        sprintf( s, "SQL_DESC_BASE_TABLE_NAME" );
        break;

      case SQL_DESC_CASE_SENSITIVE:
        sprintf( s, "SQL_DESC_CASE_SENSITIVE" );
        break;

      case SQL_DESC_CATALOG_NAME:
        sprintf( s, "SQL_DESC_CATALOG_NAME" );
        break;

      case SQL_DESC_CONCISE_TYPE:
        sprintf( s, "SQL_DESC_CONCISE_TYPE" );
        break;

      case SQL_DESC_DATA_PTR:
        sprintf( s, "SQL_DESC_DATA_PTR" );
        break;

      case SQL_DESC_DATETIME_INTERVAL_CODE:
        sprintf( s, "SQL_DESC_DATETIME_INTERVAL_CODE" );
        break;

      case SQL_DESC_DATETIME_INTERVAL_PRECISION:
        sprintf( s, "SQL_DESC_DATETIME_INTERVAL_PRECISION" );
        break;

      case SQL_DESC_DISPLAY_SIZE:
        sprintf( s, "SQL_DESC_DISPLAY_SIZE" );
        break;

      case SQL_DESC_FIXED_PREC_SCALE:
        sprintf( s, "SQL_DESC_FIXED_PREC_SCALE" );
        break;

      case SQL_DESC_INDICATOR_PTR:
        sprintf( s, "SQL_DESC_INDICATOR_PTR" );
        break;

      case SQL_DESC_LABEL:
        sprintf( s, "SQL_DESC_LABEL" );
        break;

      case SQL_DESC_LENGTH:
        sprintf( s, "SQL_DESC_LENGTH" );
        break;

      case SQL_DESC_LITERAL_PREFIX:
        sprintf( s, "SQL_DESC_LITERAL_PREFIX" );
        break;

      case SQL_DESC_LITERAL_SUFFIX:
        sprintf( s, "SQL_DESC_LITERAL_SUFFIX" );
        break;

      case SQL_DESC_LOCAL_TYPE_NAME:
        sprintf( s, "SQL_DESC_LOCAL_TYPE_NAME" );
        break;

      case SQL_DESC_NAME:
        sprintf( s, "SQL_DESC_NAME" );
        break;

      case SQL_DESC_NULLABLE:
        sprintf( s, "SQL_DESC_NULLABLE" );
        break;

      case SQL_DESC_NUM_PREC_RADIX:
        sprintf( s, "SQL_DESC_NUM_PREC_RADIX" );
        break;

      case SQL_DESC_OCTET_LENGTH:
        sprintf( s, "SQL_DESC_OCTET_LENGTH" );
        break;

      case SQL_DESC_OCTET_LENGTH_PTR:
        sprintf( s, "SQL_DESC_OCTET_LENGTH_PTR" );
        break;

      case SQL_DESC_PARAMETER_TYPE:
        sprintf( s, "SQL_DESC_PARAMETER_TYPE" );
        break;

      case SQL_DESC_PRECISION:
        sprintf( s, "SQL_DESC_PRECISION" );
        break;

      case SQL_DESC_SCALE:
        sprintf( s, "SQL_DESC_SCALE" );
        break;

      case SQL_DESC_SCHEMA_NAME:
        sprintf( s, "SQL_DESC_SCHEMA_NAME" );
        break;

      case SQL_DESC_SEARCHABLE:
        sprintf( s, "SQL_DESC_SEARCHABLE" );
        break;

      case SQL_DESC_TABLE_NAME:
        sprintf( s, "SQL_DESC_TABLE_NAME" );
        break;

      case SQL_DESC_TYPE:
        sprintf( s, "SQL_DESC_TYPE" );
        break;

      case SQL_DESC_TYPE_NAME:
        sprintf( s, "SQL_DESC_TYPE_NAME" );
        break;

      case SQL_DESC_UNNAMED:
        sprintf( s, "SQL_DESC_UNNAMED" );
        break;

      case SQL_DESC_UNSIGNED:
        sprintf( s, "SQL_DESC_UNSIGNED" );
        break;

      case SQL_DESC_UPDATABLE:
        sprintf( s, "SQL_DESC_UPDATABLE" );
        break;

      default:
        sprintf( s, "%d", (int)type );
    }

    return s;
}

/*
 * convert a statement attribute to a string
 */

char * __stmt_attr_as_string( SQLCHAR *s, SQLINTEGER type )
{
    switch( type )
    {
      case SQL_ATTR_APP_PARAM_DESC:
        sprintf( s, "SQL_ATTR_APP_PARAM_DESC" );
        break;

      case SQL_ATTR_APP_ROW_DESC:
        sprintf( s, "SQL_ATTR_APP_ROW_DESC" );
        break;

      case SQL_ATTR_ASYNC_ENABLE:
        sprintf( s, "SQL_ATTR_ASYNC_ENABLE" );
        break;

      case SQL_ATTR_CONCURRENCY:
        sprintf( s, "SQL_ATTR_CONCURRENCY" );
        break;

      case SQL_ATTR_CURSOR_SCROLLABLE:
        sprintf( s, "SQL_ATTR_CURSOR_SCROLLABLE" );
        break;

      case SQL_ATTR_CURSOR_SENSITIVITY:
        sprintf( s, "SQL_ATTR_CURSOR_SENSITIVITY" );
        break;

      case SQL_ATTR_CURSOR_TYPE:
        sprintf( s, "SQL_ATTR_CURSOR_TYPE" );
        break;

      case SQL_ATTR_ENABLE_AUTO_IPD:
        sprintf( s, "SQL_ATTR_ENABLE_AUTO_IPD" );
        break;

      case SQL_ATTR_FETCH_BOOKMARK_PTR:
        sprintf( s, "SQL_ATTR_FETCH_BOOKMARK_PTR" );
        break;

      case SQL_ATTR_IMP_PARAM_DESC:
        sprintf( s, "SQL_ATTR_IMP_PARAM_DESC" );
        break;

      case SQL_ATTR_IMP_ROW_DESC:
        sprintf( s, "SQL_ATTR_IMP_ROW_DESC" );
        break;

      case SQL_ATTR_KEYSET_SIZE:
        sprintf( s, "SQL_ATTR_KEYSET_SIZE" );
        break;

      case SQL_ATTR_MAX_LENGTH:
        sprintf( s, "SQL_ATTR_MAX_LENGTH" );
        break;

      case SQL_ATTR_MAX_ROWS:
        sprintf( s, "SQL_ATTR_MAX_ROWS" );
        break;

      case SQL_ATTR_METADATA_ID:
        sprintf( s, "SQL_ATTR_METADATA_ID" );
        break;

      case SQL_ATTR_NOSCAN:
        sprintf( s, "SQL_ATTR_NOSCAN" );
        break;

      case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
        sprintf( s, "SQL_ATTR_PARAM_BIND_OFFSET_PTR" );
        break;

      case SQL_ATTR_PARAM_BIND_TYPE:
        sprintf( s, "SQL_ATTR_PARAM_BIND_TYPE" );
        break;

      case SQL_ATTR_PARAM_OPERATION_PTR:
        sprintf( s, "SQL_ATTR_PARAM_OPERATION_PTR" );
        break;

      case SQL_ATTR_PARAM_STATUS_PTR:
        sprintf( s, "SQL_ATTR_PARAM_STATUS_PTR" );
        break;

      case SQL_ATTR_PARAMS_PROCESSED_PTR:
        sprintf( s, "SQL_ATTR_PARAMS_PROCESSED_PTR" );
        break;

      case SQL_ATTR_PARAMSET_SIZE:
        sprintf( s, "SQL_ATTR_PARAMSET_SIZE" );
        break;

      case SQL_ATTR_QUERY_TIMEOUT:
        sprintf( s, "SQL_ATTR_QUERY_TIMEOUT" );
        break;

      case SQL_ATTR_RETRIEVE_DATA:
        sprintf( s, "SQL_ATTR_RETRIEVE_DATA" );
        break;

      case SQL_ROWSET_SIZE:
        sprintf( s, "SQL_ROWSET_SIZE" );
        break;

      case SQL_ATTR_ROW_ARRAY_SIZE:
        sprintf( s, "SQL_ATTR_ROW_ARRAY_SIZE" );
        break;

      case SQL_ATTR_ROW_BIND_OFFSET_PTR:
        sprintf( s, "SQL_ATTR_ROW_BIND_OFFSET_PTR" );
        break;

      case SQL_ATTR_ROW_BIND_TYPE:
        sprintf( s, "SQL_ATTR_ROW_BIND_TYPE" );
        break;

      case SQL_ATTR_ROW_NUMBER:
        sprintf( s, "SQL_ATTR_ROW_NUMBER" );
        break;

      case SQL_ATTR_ROW_OPERATION_PTR:
        sprintf( s, "SQL_ATTR_ROW_OPERATION_PTR" );
        break;

      case SQL_ATTR_ROW_STATUS_PTR:
        sprintf( s, "SQL_ATTR_ROW_STATUS_PTR" );
        break;

      case SQL_ATTR_ROWS_FETCHED_PTR:
        sprintf( s, "SQL_ATTR_ROWS_FETCHED_PTR" );
        break;

      case SQL_ATTR_SIMULATE_CURSOR:
        sprintf( s, "SQL_ATTR_SIMULATE_CURSOR" );
        break;

      case SQL_ATTR_USE_BOOKMARKS:
        sprintf( s, "SQL_ATTR_USE_BOOKMARKS" );
        break;

      default:
        sprintf( s, "%d", (int)type );
    }

    return s;
}

/*
 * return a SQLGetInfo type as a string
 */

char * __info_as_string( SQLCHAR *s, SQLINTEGER type )
{
    switch( type )
    {
      case SQL_ACCESSIBLE_PROCEDURES:
        sprintf( s, "SQL_ACCESSIBLE_PROCEDURES" );
        break;

      case SQL_ACCESSIBLE_TABLES:
        sprintf( s, "SQL_ACCESSIBLE_TABLES" );
        break;

      case SQL_ACTIVE_ENVIRONMENTS:
        sprintf( s, "SQL_ACTIVE_ENVIRONMENTS" );
        break;

      case SQL_AGGREGATE_FUNCTIONS:
        sprintf( s, "SQL_AGGREGATE_FUNCTIONS" );
        break;

      case SQL_ALTER_DOMAIN:
        sprintf( s, "SQL_ALTER_DOMAIN" );
        break;

      case SQL_ALTER_TABLE:
        sprintf( s, "SQL_ALTER_TABLE" );
        break;

      case SQL_ASYNC_MODE:
        sprintf( s, "SQL_ASYNC_MODE" );
        break;

      case SQL_BATCH_ROW_COUNT:
        sprintf( s, "SQL_BATCH_ROW_COUNT" );
        break;

      case SQL_BATCH_SUPPORT:
        sprintf( s, "SQL_BATCH_SUPPORT" );
        break;

      case SQL_BOOKMARK_PERSISTENCE:
        sprintf( s, "SQL_BOOKMARK_PERSISTENCE" );
        break;

      case SQL_CATALOG_LOCATION:
        sprintf( s, "SQL_CATALOG_LOCATION" );
        break;
    
      case SQL_CATALOG_NAME:
        sprintf( s, "SQL_CATALOG_NAME" );
        break;
    
      case SQL_CATALOG_NAME_SEPARATOR:
        sprintf( s, "SQL_CATALOG_NAME_SEPARATOR" );
        break;

      case SQL_CATALOG_TERM:
        sprintf( s, "SQL_CATALOG_TERM" );
        break;

      case SQL_CATALOG_USAGE:
        sprintf( s, "SQL_CATALOG_USAGE" );
        break;

      case SQL_COLLATION_SEQ:
        sprintf( s, "SQL_COLLATION_SEQ" );
        break;

      case SQL_COLUMN_ALIAS:
        sprintf( s, "SQL_COLUMN_ALIAS" );
        break;
    
      case SQL_CONCAT_NULL_BEHAVIOR:    
        sprintf( s, "SQL_CONCAT_NULL_BEHAVIOR" );
        break;

      case SQL_CONVERT_BIGINT:
        sprintf( s, "SQL_CONVERT_BIGINT" );
        break;

      case SQL_CONVERT_BINARY:
        sprintf( s, "SQL_CONVERT_BINARY" );
        break;

      case SQL_CONVERT_BIT:
        sprintf( s, "SQL_CONVERT_BIT" );
        break;

      case SQL_CONVERT_CHAR:
        sprintf( s, "SQL_CONVERT_CHAR" );
        break;

      case SQL_CONVERT_DATE:
        sprintf( s, "SQL_CONVERT_DATE" );
        break;

      case SQL_CONVERT_DECIMAL:
        sprintf( s, "SQL_CONVERT_DECIMAL" );
        break;

      case SQL_CONVERT_DOUBLE:
        sprintf( s, "SQL_CONVERT_DOUBLE" );
        break;

      case SQL_CONVERT_FLOAT:
        sprintf( s, "SQL_CONVERT_FLOAT" );
        break;

      case SQL_CONVERT_INTEGER:
        sprintf( s, "SQL_CONVERT_INTEGER" );
        break;

      case SQL_CONVERT_INTERVAL_YEAR_MONTH:
        sprintf( s, "SQL_CONVERT_INTERVAL_YEAR_MONTH" );
        break;

      case SQL_CONVERT_INTERVAL_DAY_TIME:
        sprintf( s, "SQL_CONVERT_INTERVAL_DAY_TIME" );
        break;

      case SQL_CONVERT_LONGVARBINARY:
        sprintf( s, "SQL_CONVERT_LONGVARBINARY" );
        break;

      case SQL_CONVERT_LONGVARCHAR:
        sprintf( s, "SQL_CONVERT_LONGVARCHAR" );
        break;

      case SQL_CONVERT_NUMERIC:
        sprintf( s, "SQL_CONVERT_NUMERIC" );
        break;

      case SQL_CONVERT_REAL:
        sprintf( s, "SQL_CONVERT_REAL" );
        break;

      case SQL_CONVERT_SMALLINT:
        sprintf( s, "SQL_CONVERT_SMALLINT" );
        break;

      case SQL_CONVERT_TIME:
        sprintf( s, "SQL_CONVERT_TIME" );
        break;

      case SQL_CONVERT_TIMESTAMP:
        sprintf( s, "SQL_CONVERT_TIMESTAMP" );
        break;

      case SQL_CONVERT_TINYINT:
        sprintf( s, "SQL_CONVERT_TINYINT" );
        break;

      case SQL_CONVERT_VARBINARY:
        sprintf( s, "SQL_CONVERT_VARBINARY" );
        break;

      case SQL_CONVERT_VARCHAR:
        sprintf( s, "SQL_CONVERT_VARCHAR" );
        break;

      case SQL_CONVERT_FUNCTIONS:
        sprintf( s, "SQL_CONVERT_FUNCTIONS" );
        break;

      case SQL_CORRELATION_NAME:
        sprintf( s, "SQL_CORRELATION_NAME" );
        break;

      case SQL_CREATE_ASSERTION:
        sprintf( s, "SQL_CREATE_ASSERTION" );
        break;

      case SQL_CREATE_CHARACTER_SET:
        sprintf( s, "SQL_CREATE_CHARACTER_SET" );
        break;

      case SQL_CREATE_COLLATION:
        sprintf( s, "SQL_CREATE_COLLATION" );
        break;

      case SQL_CREATE_DOMAIN:
        sprintf( s, "SQL_CREATE_DOMAIN" );
        break;

      case SQL_CREATE_SCHEMA:
        sprintf( s, "SQL_CREATE_SCHEMA" );
        break;

      case SQL_CREATE_TABLE:
        sprintf( s, "SQL_CREATE_TABLE" );
        break;

      case SQL_CREATE_TRANSLATION:
        sprintf( s, "SQL_CREATE_TRANSLATION" );
        break;

      case SQL_CREATE_VIEW:
        sprintf( s, "SQL_CREATE_VIEW" );
        break;

      case SQL_CURSOR_COMMIT_BEHAVIOR:
        sprintf( s, "SQL_CURSOR_COMMIT_BEHAVIOR" );
        break;

      case SQL_CURSOR_ROLLBACK_BEHAVIOR:
        sprintf( s, "SQL_CURSOR_ROLLBACK_BEHAVIOR" );
        break;

      case SQL_CURSOR_SENSITIVITY:
        sprintf( s, "SQL_CURSOR_SENSITIVITY" );
        break;

      case SQL_DATA_SOURCE_NAME:
        sprintf( s, "SQL_DATA_SOURCE_NAME" );
        break;

      case SQL_DATA_SOURCE_READ_ONLY:
        sprintf( s, "SQL_DATA_SOURCE_READ_ONLY" );
        break;

      case SQL_DATABASE_NAME:
        sprintf( s, "SQL_DATABASE_NAME" );
        break;

      case SQL_DATETIME_LITERALS:
        sprintf( s, "SQL_DATETIME_LITERALS" );
        break;

      case SQL_DBMS_NAME:
        sprintf( s, "SQL_DBMS_NAME" );
        break;

      case SQL_DBMS_VER:
        sprintf( s, "SQL_DBMS_VER" );
        break;

      case SQL_DDL_INDEX:
        sprintf( s, "SQL_DDL_INDEX" );
        break;

      case SQL_DEFAULT_TXN_ISOLATION:
        sprintf( s, "SQL_DEFAULT_TXN_ISOLATION" );
        break;

      case SQL_DESCRIBE_PARAMETER:
        sprintf( s, "SQL_DESCRIBE_PARAMETER" );
        break;

      case SQL_DRIVER_NAME:
        sprintf( s, "SQL_DRIVER_NAME" );
        break;

      case SQL_DRIVER_HLIB:
        sprintf( s, "SQL_DRIVER_HLIB" );
        break;

      case SQL_DRIVER_HSTMT:
        sprintf( s, "SQL_DRIVER_HSTMT" );
        break;

      case SQL_DRIVER_ODBC_VER:
        sprintf( s, "SQL_DRIVER_ODBC_VER" );
        break;

      case SQL_DRIVER_VER:
        sprintf( s, "SQL_DRIVER_VER" );
        break;

      case SQL_ODBC_VER:
        sprintf( s, "SQL_ODBC_VER" );
        break;
  
      case SQL_DROP_ASSERTION:
        sprintf( s, "SQL_DROP_ASSERTION" );
        break;

      case SQL_DROP_CHARACTER_SET:
        sprintf( s, "SQL_DROP_CHARACTER_SET" );
        break;

      case SQL_DROP_COLLATION:
        sprintf( s, "SQL_DROP_COLLATION" );
        break;

      case SQL_DROP_DOMAIN:
        sprintf( s, "SQL_DROP_DOMAIN" );
        break;

      case SQL_DROP_SCHEMA:
        sprintf( s, "SQL_DROP_SCHEMA" );
        break;

      case SQL_DROP_TABLE:
        sprintf( s, "SQL_DROP_TABLE" );
        break;

      case SQL_DROP_TRANSLATION:
        sprintf( s, "SQL_DROP_TRANSLATION" );
        break;

      case SQL_DROP_VIEW:
        sprintf( s, "SQL_DROP_VIEW" );
        break;

      case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
        sprintf( s, "SQL_DYNAMIC_CURSOR_ATTRIBUTES1" );
        break;
    
      case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
        sprintf( s, "SQL_EXPRESSIONS_IN_ORDERBY" );
        break;

      case SQL_EXPRESSIONS_IN_ORDERBY:
        sprintf( s, "SQL_EXPRESSIONS_IN_ORDERBY" );
        break;

      case SQL_FILE_USAGE:
        sprintf( s, "SQL_FILE_USAGE" );
        break;

      case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
        sprintf( s, "SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1" );
        break;

      case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
        sprintf( s, "SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2" );
        break;

      case SQL_GETDATA_EXTENSIONS:
        sprintf( s, "SQL_GETDATA_EXTENSIONS" );
        break;

      case SQL_GROUP_BY:
        sprintf( s, "SQL_GROUP_BY" );
        break;

      case SQL_IDENTIFIER_CASE:
        sprintf( s, "SQL_IDENTIFIER_CASE" );
        break;

      case SQL_IDENTIFIER_QUOTE_CHAR:
        sprintf( s, "SQL_IDENTIFIER_QUOTE_CHAR" );
        break;

      case SQL_INDEX_KEYWORDS:
        sprintf( s, "SQL_INDEX_KEYWORDS" );
        break;

      case SQL_INFO_SCHEMA_VIEWS:
        sprintf( s, "SQL_INFO_SCHEMA_VIEWS" );
        break;

      case SQL_INSERT_STATEMENT:
        sprintf( s, "SQL_INSERT_STATEMENT" );
        break;

      case SQL_INTEGRITY:    
        sprintf( s, "SQL_INTEGRITY" );
        break;

      case SQL_KEYSET_CURSOR_ATTRIBUTES1:
        sprintf( s, "SQL_KEYSET_CURSOR_ATTRIBUTES1" );
        break;

      case SQL_KEYSET_CURSOR_ATTRIBUTES2:
        sprintf( s, "SQL_KEYSET_CURSOR_ATTRIBUTES2" );
        break;

      case SQL_KEYWORDS:
        sprintf( s, "SQL_KEYWORDS" );
        break;

      case SQL_LIKE_ESCAPE_CLAUSE:
        sprintf( s, "SQL_LIKE_ESCAPE_CLAUSE" );
        break;

      case SQL_MAX_ASYNC_CONCURRENT_STATEMENTS:
        sprintf( s, "SQL_MAX_ASYNC_CONCURRENT_STATEMENTS" );
        break;

      case SQL_MAX_BINARY_LITERAL_LEN:
        sprintf( s, "SQL_MAX_BINARY_LITERAL_LEN" );
        break;

      case SQL_MAX_CATALOG_NAME_LEN:
        sprintf( s, "SQL_MAX_CATALOG_NAME_LEN" );
        break;
    
      case SQL_MAX_CHAR_LITERAL_LEN:
        sprintf( s, "SQL_MAX_CHAR_LITERAL_LEN" );
        break;

      case SQL_MAX_COLUMN_NAME_LEN:
        sprintf( s, "SQL_MAX_COLUMN_NAME_LEN" );
        break;

      case SQL_MAX_COLUMNS_IN_GROUP_BY:    
        sprintf( s, "SQL_MAX_COLUMNS_IN_GROUP_BY" );
        break;

      case SQL_MAX_COLUMNS_IN_INDEX:
        sprintf( s, "SQL_MAX_COLUMNS_IN_INDEX" );
        break;

      case SQL_MAX_COLUMNS_IN_SELECT:
        sprintf( s, "SQL_MAX_COLUMNS_IN_SELECT" );
        break;

      case SQL_MAX_COLUMNS_IN_ORDER_BY:
        sprintf( s, "SQL_MAX_COLUMNS_IN_ORDER_BY" );
        break;

      case SQL_MAX_COLUMNS_IN_TABLE:
        sprintf( s, "SQL_MAX_COLUMNS_IN_TABLE" );
        break;

      case SQL_MAX_CONCURRENT_ACTIVITIES:
        sprintf( s, "SQL_MAX_CONCURRENT_ACTIVITIES" );
        break;

      case SQL_MAX_CURSOR_NAME_LEN:    
        sprintf( s, "SQL_MAX_CURSOR_NAME_LEN" );
        break;

      case SQL_MAX_DRIVER_CONNECTIONS:    
        sprintf( s, "SQL_MAX_DRIVER_CONNECTIONS" );
        break;

      case SQL_MAX_IDENTIFIER_LEN:    
        sprintf( s, "SQL_MAX_IDENTIFIER_LEN" );
        break;

      case SQL_MAX_INDEX_SIZE:    
        sprintf( s, "SQL_MAX_INDEX_SIZE" );
        break;

      case SQL_MAX_PROCEDURE_NAME_LEN:
        sprintf( s, "SQL_MAX_PROCEDURE_NAME_LEN" );
        break;

      case SQL_MAX_ROW_SIZE:    
        sprintf( s, "SQL_MAX_ROW_SIZE" );
        break;
    
      case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
        sprintf( s, "SQL_MAX_ROW_SIZE_INCLUDES_LONG" );
        break;

      case SQL_MAX_SCHEMA_NAME_LEN:
        sprintf( s, "SQL_MAX_SCHEMA_NAME_LEN" );
        break;

      case SQL_MAX_STATEMENT_LEN:
        sprintf( s, "SQL_MAX_STATEMENT_LEN" );
        break;

      case SQL_MAX_TABLE_NAME_LEN:    
        sprintf( s, "SQL_MAX_TABLE_NAME_LEN" );
        break;

      case SQL_MAX_TABLES_IN_SELECT:
        sprintf( s, "SQL_MAX_TABLES_IN_SELECT" );
        break;

      case SQL_MAX_USER_NAME_LEN:
        sprintf( s, "SQL_MAX_USER_NAME_LEN" );
        break;

      case SQL_MULT_RESULT_SETS:
        sprintf( s, "SQL_MULT_RESULT_SETS" );
        break;

      case SQL_MULTIPLE_ACTIVE_TXN:
        sprintf( s, "SQL_MULTIPLE_ACTIVE_TXN" );
        break;

      case SQL_NEED_LONG_DATA_LEN:
        sprintf( s, "SQL_NEED_LONG_DATA_LEN" );
        break;

      case SQL_NON_NULLABLE_COLUMNS:
        sprintf( s, "SQL_NON_NULLABLE_COLUMNS" );
        break;

      case SQL_NULL_COLLATION:
        sprintf( s, "SQL_NULL_COLLATION" );
        break;

      case SQL_NUMERIC_FUNCTIONS:        
        sprintf( s, "SQL_NUMERIC_FUNCTIONS" );
        break;

      case SQL_ODBC_INTERFACE_CONFORMANCE:
        sprintf( s, "SQL_ODBC_INTERFACE_CONFORMANCE" );
        break;

      case SQL_OJ_CAPABILITIES:
        sprintf( s, "SQL_OJ_CAPABILITIES" );
        break;

      case SQL_ORDER_BY_COLUMNS_IN_SELECT:
        sprintf( s, "SQL_ORDER_BY_COLUMNS_IN_SELECT" );
        break;

      case SQL_PARAM_ARRAY_ROW_COUNTS:
        sprintf( s, "SQL_PARAM_ARRAY_ROW_COUNTS" );
        break;

      case SQL_PARAM_ARRAY_SELECTS:
        sprintf( s, "SQL_PARAM_ARRAY_SELECTS" );
        break;

      case SQL_PROCEDURE_TERM:
        sprintf( s, "SQL_PROCEDURE_TERM" );
        break;

      case SQL_PROCEDURES:
        sprintf( s, "SQL_PROCEDURES" );
        break;

      case SQL_QUOTED_IDENTIFIER_CASE:
        sprintf( s, "SQL_QUOTED_IDENTIFIER_CASE" );
        break;

      case SQL_ROW_UPDATES:
        sprintf( s, "SQL_ROW_UPDATES" );
        break;

      case SQL_SCHEMA_TERM:
        sprintf( s, "SQL_SCHEMA_TERM" );
        break;

      case SQL_SCHEMA_USAGE:
        sprintf( s, "SQL_SCHEMA_USAGE" );
        break;

      case SQL_SCROLL_OPTIONS:
        sprintf( s, "SQL_SCROLL_OPTIONS" );
        break;

      case SQL_SEARCH_PATTERN_ESCAPE:
        sprintf( s, "SQL_SEARCH_PATTERN_ESCAPE" );
        break;

      case SQL_SERVER_NAME:
        sprintf( s, "SQL_SERVER_NAME" );
        break;

      case SQL_SPECIAL_CHARACTERS:
        sprintf( s, "SQL_SPECIAL_CHARACTERS" );
        break;

      case SQL_SQL_CONFORMANCE:
        sprintf( s, "SQL_SQL_CONFORMANCE" );
        break;

      case SQL_SQL92_DATETIME_FUNCTIONS:
        sprintf( s, "SQL_SQL92_DATETIME_FUNCTIONS" );
        break;

      case SQL_SQL92_FOREIGN_KEY_DELETE_RULE:
        sprintf( s, "SQL_SQL92_FOREIGN_KEY_DELETE_RULE" );
        break;

      case SQL_SQL92_FOREIGN_KEY_UPDATE_RULE:
        sprintf( s, "SQL_SQL92_FOREIGN_KEY_UPDATE_RULE" );
        break;

      case SQL_SQL92_GRANT:
        sprintf( s, "SQL_SQL92_GRANT" );
        break;

      case SQL_SQL92_NUMERIC_VALUE_FUNCTIONS:
        sprintf( s, "SQL_SQL92_NUMERIC_VALUE_FUNCTIONS" );
        break;

      case SQL_SQL92_PREDICATES:
        sprintf( s, "SQL_SQL92_PREDICATES" );
        break;

      case SQL_SQL92_RELATIONAL_JOIN_OPERATORS:
        sprintf( s, "SQL_SQL92_RELATIONAL_JOIN_OPERATORS" );
        break;

      case SQL_SQL92_REVOKE:
        sprintf( s, "SQL_SQL92_REVOKE" );
        break;

      case SQL_SQL92_ROW_VALUE_CONSTRUCTOR:
        sprintf( s, "SQL_SQL92_ROW_VALUE_CONSTRUCTOR" );
        break;

      case SQL_SQL92_STRING_FUNCTIONS:
        sprintf( s, "SQL_SQL92_STRING_EXPRESSIONS" );
        break;

      case SQL_SQL92_VALUE_EXPRESSIONS:
        sprintf( s, "SQL_SQL92_VALUE_EXPRESSIONS" );
        break;

      case SQL_STANDARD_CLI_CONFORMANCE:
        sprintf( s, "SQL_STANDARD_CLI_CONFORMANCE" );
        break;

      case SQL_STATIC_CURSOR_ATTRIBUTES1:
        sprintf( s, "SQL_STATIC_CURSOR_ATTRIBUTES1" );
        break;

      case SQL_STATIC_CURSOR_ATTRIBUTES2:
        sprintf( s, "SQL_STATIC_CURSOR_ATTRIBUTES2" );
        break;

      case SQL_STRING_FUNCTIONS:
        sprintf( s, "SQL_STRING_FUNCTIONS" );
        break;

      case SQL_SUBQUERIES:
        sprintf( s, "SQL_SUBQUERIES" );
        break;

      case SQL_SYSTEM_FUNCTIONS:
        sprintf( s, "SQL_SYSTEM_FUNCTIONS" );
        break;

      case SQL_TABLE_TERM:
        sprintf( s, "SQL_TABLE_TERM" );
        break;

      case SQL_TIMEDATE_ADD_INTERVALS:
        sprintf( s, "SQL_TIMEDATE_ADD_INTERVALS" );
        break;

      case SQL_TIMEDATE_DIFF_INTERVALS:
        sprintf( s, "SQL_TIMEDATE_DIFF_INTERVALS" );
        break;

      case SQL_TIMEDATE_FUNCTIONS:
        sprintf( s, "SQL_TIMEDATE_FUNCTIONS" );
        break;

      case SQL_TXN_CAPABLE:
        sprintf( s, "SQL_TXN_CAPABLE" );
        break;

      case SQL_TXN_ISOLATION_OPTION:
        sprintf( s, "SQL_TXN_ISOLATION_OPTION" );
        break;

      case SQL_UNION:
        sprintf( s, "SQL_UNION" );
        break;

      case SQL_USER_NAME:
        sprintf( s, "SQL_XOPEN_CLI_YEAR" );
        break;

      case SQL_XOPEN_CLI_YEAR:
        sprintf( s, "SQL_XOPEN_CLI_YEAR" );
        break;

      case SQL_FETCH_DIRECTION:
        sprintf( s, "SQL_FETCH_DIRECTION" );
        break;

      case SQL_LOCK_TYPES:
        sprintf( s, "SQL_LOCK_TYPES" );
        break;

      case SQL_ODBC_API_CONFORMANCE:
        sprintf( s, "SQL_ODBC_API_CONFORMANCE" );
        break;

      case SQL_ODBC_SQL_CONFORMANCE:
        sprintf( s, "SQL_ODBC_SQL_CONFORMANCE" );
        break;

      case SQL_POS_OPERATIONS:
        sprintf( s, "SQL_POS_OPERATIONS" );
        break;

      case SQL_POSITIONED_STATEMENTS:
        sprintf( s, "SQL_POSITIONED_STATEMENTS" );
        break;

      case SQL_SCROLL_CONCURRENCY:
        sprintf( s, "SQL_SCROLL_CONCURRENCY" );
        break;

      case SQL_STATIC_SENSITIVITY:
        sprintf( s, "SQL_STATIC_SENSITIVITY" );
        break;

      case SQL_OUTER_JOINS:
        sprintf( s, "SQL_OUTER_JOINS" );
        break;

      default:
        sprintf( s, "%d", (int)type );
    }

    return s;
}

/*
 * return the process id as a string
 */

char * __get_pid( SQLCHAR * str )
{
    sprintf( str, "%d", getpid());

    return str;
}

/*
 * take a SQL string and its length indicator and format it for
 * display
 */

char * __string_with_length( SQLCHAR *ostr, SQLCHAR *instr, SQLINTEGER len )
{
    if ( instr == NULL )
    {
        sprintf( ostr, "[NULL]" );
    }
    else if ( len == SQL_NTS )
    {
        if ( strlen( instr ) > 64 )
        {
            sprintf( ostr, "[%.64s...][length = %d (SQL_NTS)]",
                instr, strlen( instr ));
        }
        else
        {
            sprintf( ostr, "[%s][length = %d (SQL_NTS)]",
                instr, strlen( instr ));
        }

    }
    else
    {
        if ( len < 64 )
            sprintf( ostr, "[%.*s][length = %d]", len, instr, (int)len );
        else
            sprintf( ostr, "[%.64s...][length = %d]", instr, (int)len );
    }

    return ostr;
}

/*
 * display a C type as a string
 */
 
char * __c_as_text( SQLINTEGER type )
{
    switch( type )
    {
      default:
        return "";
    }
}

/*
 * display a SQL type as a string
 */
 
char * __sql_as_text( SQLINTEGER type )
{
    switch( type )
    {
      case SQL_INTEGER:
        return "SQL_INTEGER";

      case SQL_CHAR:
        return "SQL_CHAR";

      default:
        return "";
    }
}

/*
 * convert a return type as a string
 */

char * __get_return_status( SQLRETURN ret )
{
    switch ( ret )
    {
      case SQL_SUCCESS:
        return "SQL_SUCCESS";

      case SQL_ERROR:
        return "SQL_ERROR";

      case SQL_SUCCESS_WITH_INFO:
        return "SQL_SUCCESS_WITH_INFO";

      case SQL_NO_DATA:
        return "SQL_NO_DATA";

      case SQL_STILL_EXECUTING:
        return "SQL_STILL_EXECUTING";

      case SQL_INVALID_HANDLE:
        return "SQL_INVALID_HANDLE";

      default:
        return "UNKNOWN";
    }
}

void __post_internal_error_ex( EHEAD *error_header,
        SQLCHAR *sqlstate,
        SQLINTEGER native_error,
        SQLCHAR *message_text )
{
    /*
     * create a error block and add to the lists
     */

    ERROR *e1, *e2;

    e1 = malloc( sizeof( ERROR ));
    e2 = malloc( sizeof( ERROR ));

    e1 -> native_error = native_error;
    e2 -> native_error = native_error;
    strcpy( e1 -> sqlstate, sqlstate );
    strcpy( e2 -> sqlstate, sqlstate );
    e1 -> msg = strdup( message_text );
    e2 -> msg = strdup( message_text );
    e1 -> return_val = SQL_ERROR;
    e2 -> return_val = SQL_ERROR;

    /*
     * the list for SQLError puts both local and driver 
     * errors in the same list
     */

    error_header -> sql_error_head.error_count ++;

    if ( error_header -> sql_error_head.error_list_head )
    {
        e1 -> next = NULL;
        e1 -> prev = error_header -> sql_error_head.error_list_tail;
        e1 -> prev -> next = e1;
        error_header -> sql_error_head.error_list_tail = e1;
    }
    else
    {
        e1 -> next = e1 -> prev = NULL;
        error_header -> sql_error_head.error_list_tail = e1;
        error_header -> sql_error_head.error_list_head = e1;
    }

    error_header -> sql_diag_head.internal_count ++;

    if ( error_header -> sql_diag_head.internal_list_head )
    {
        e2 -> next = NULL;
        e2 -> prev = error_header -> sql_diag_head.internal_list_tail;
        e2 -> prev -> next = e2;
        error_header -> sql_diag_head.internal_list_tail = e2;
    }
    else
    {
        e2 -> next = e2 -> prev = NULL;
        error_header -> sql_diag_head.internal_list_tail = e2;
        error_header -> sql_diag_head.internal_list_head = e2;
    }
}

/*
 * initialise a error header and take note what it belongs to
 */

void setup_error_head( EHEAD *error_header, void *handle, int type )
{
    memset( error_header, 0, sizeof( error_header ));

    error_header -> owning_handle = handle;
    error_header -> handle_type = type;
}

/*
 * free any resources used but the error headers
 */

void clear_error_head( EHEAD *error_header )
{
    ERROR *cur, *prev;

    prev = NULL;
    cur = error_header -> sql_error_head.error_list_head;

    while( cur )
    {
        prev = cur;

        free( prev -> msg );
        cur = prev -> next;
        free( prev );
    }

    error_header -> sql_error_head.error_list_head = NULL;
    error_header -> sql_error_head.error_list_tail = NULL;

    prev = NULL;
    cur = error_header -> sql_diag_head.error_list_head;

    while( cur )
    {
        prev = cur;

        free( prev -> msg );
        cur = prev -> next;
        free( prev );
    }

    error_header -> sql_diag_head.error_list_head = NULL;
    error_header -> sql_diag_head.error_list_tail = NULL;

    prev = NULL;
    cur = error_header -> sql_diag_head.internal_list_head;

    while( cur )
    {
        prev = cur;

        free( prev -> msg );
        cur = prev -> next;
        free( prev );
    }

    error_header -> sql_diag_head.internal_list_head = NULL;
    error_header -> sql_diag_head.internal_list_tail = NULL;
}

/*
 * get the error values from the handle
 */

static void extract_diag_error( int htype,
                            SQLHANDLE handle,
                            DMHDBC connection,
                            EHEAD *head,
                            int return_code )
{
    SQLRETURN ret;
    SQLCHAR msg[ SQL_MAX_MESSAGE_LENGTH ];
    SQLCHAR sqlstate[ 6 ];
    SQLINTEGER native, len;
    SQLINTEGER rec_number;

    head -> return_code = return_code;

    rec_number = 1;
    do
    {
        ret = SQLGETDIAGREC( connection,
                head -> handle_type,
                handle,
                rec_number,
                sqlstate,
                &native,
                msg,
                sizeof( msg ),
                &len );

        if ( SQL_SUCCEEDED( ret ))
        {
            ERROR *e = malloc( sizeof( ERROR ));

            rec_number ++;
            
            /*
             * add to the SQLError list
             */

            e -> native_error = native;
            strcpy( e -> sqlstate, sqlstate );
            e -> msg = strdup( msg );
            e -> return_val = return_code;

            head -> sql_error_head.error_count ++;

            if ( head -> sql_error_head.error_list_head )
            {
                e -> next = NULL;
                e -> prev = head -> sql_error_head.error_list_tail;
                e -> prev -> next = e;
                head -> sql_error_head.error_list_tail = e;
            }
            else
            {
                e -> next = e -> prev = NULL;
                head -> sql_error_head.error_list_tail = e;
                head -> sql_error_head.error_list_head = e;
            }

            /*
             * we dont have to add to the diag_list as
             * reading is not destructive
             */

            head -> sql_diag_head.error_count ++;
        }
    }
    while( SQL_SUCCEEDED( ret ));
}

static void extract_sql_error( SQLHANDLE henv,
                            SQLHANDLE hdbc,
                            SQLHANDLE hstmt,
                            DMHDBC connection,
                            EHEAD *head, 
                            int return_code )
{
    SQLRETURN ret;
    SQLCHAR msg[ SQL_MAX_MESSAGE_LENGTH ];
    SQLCHAR sqlstate[ 6 ];
    SQLINTEGER native, len;

    head -> return_code = return_code;

    do
    {
        ret = SQLERROR( connection,
                henv, 
                hdbc,
                hstmt,
                sqlstate,
                &native,
                msg,
                sizeof( msg ),
                &len );

        if ( SQL_SUCCEEDED( ret ))
        {
            /*
             * add to the lists, SQLError list first
             */

            ERROR *e = malloc( sizeof( ERROR ));

            e -> native_error = native;
            strcpy( e -> sqlstate, sqlstate );
            e -> msg = strdup( msg );
            e -> return_val = return_code;

            head -> sql_error_head.error_count ++;

            if ( head -> sql_error_head.error_list_head )
            {
                e -> next = NULL;
                e -> prev = head -> sql_error_head.error_list_tail;
                e -> prev -> next = e;
                head -> sql_error_head.error_list_tail = e;
            }
            else
            {
                e -> next = e -> prev = NULL;
                head -> sql_error_head.error_list_tail = e;
                head -> sql_error_head.error_list_head = e;
            }

            /*
             * SQLGetDiagRec list next
             */

            e = malloc( sizeof( ERROR ));
            e -> native_error = native;
            strcpy( e -> sqlstate, sqlstate );
            e -> msg = strdup( msg );
            e -> return_val = return_code;

            head -> sql_diag_head.error_count ++;

            if ( head -> sql_diag_head.error_list_head )
            {
                e -> next = NULL;
                e -> prev = head -> sql_diag_head.error_list_tail;
                e -> prev -> next = e;
                head -> sql_diag_head.error_list_tail = e;
            }
            else
            {
                e -> next = e -> prev = NULL;
                head -> sql_diag_head.error_list_tail = e;
                head -> sql_diag_head.error_list_head = e;
            }
        }
    }
    while( SQL_SUCCEEDED( ret ));
}

/*
 * capture function returns and check error's if necessary
 */

int function_return( void * handle, int ret_code )
{
    DMHENV henv;
    DMHDBC hdbc;
    DMHSTMT hstmt;
    DMHDESC hdesc;

    if ( ret_code == SQL_ERROR ||
            ret_code == SQL_SUCCESS_WITH_INFO )
    {
        /*
         * find what type of handle it is
         */

        henv = handle;

        switch ( henv -> type )
        {
          case HENV_MAGIC:
            {
                /*
                 * do nothing, it must be local
                 */
            }
            break;

          case HDBC_MAGIC:
            {
                hdbc = handle;

                /*
                 * are we connected ?
                 */

                if ( hdbc -> state == STATE_C4 )
                {
                    if ( CHECK_SQLGETDIAGFIELD( hdbc ) &&
                            CHECK_SQLGETDIAGREC( hdbc ))
                    {
                        extract_diag_error( SQL_HANDLE_DBC,
                                hdbc -> driver_dbc,
                                hdbc,
                                &hdbc -> error,
                                ret_code );
                    }
                    else
                    {
                        extract_sql_error( SQL_NULL_HENV, 
                                hdbc -> driver_dbc, 
                                SQL_NULL_HSTMT, 
                                hdbc,
                                &hdbc -> error, 
                                ret_code );
                    }
                }
            }
            break;

          case HSTMT_MAGIC:
            {
                hstmt = handle;

                /*
                 * how are we to get the error
                 */

                if ( CHECK_SQLGETDIAGFIELD( hstmt -> connection ) &&
                        CHECK_SQLGETDIAGREC( hstmt -> connection ))
                {
                    extract_diag_error( SQL_HANDLE_STMT,
                            hstmt -> driver_stmt,
                            hstmt -> connection,
                            &hstmt -> error,
                            ret_code );
                }
                else
                {
                    extract_sql_error( SQL_NULL_HENV, 
                            SQL_NULL_HDBC, 
                            hstmt -> driver_stmt, 
                            hstmt -> connection,
                            &hstmt -> error, 
                            ret_code );
                }
            }
            break;

          case HDESC_MAGIC:
            {
                hdesc = handle;

                /*
                 * we can only get these error via the ODBC 3 calls
                 * and we can only report them also via ODBC 3 so there
                 * is no point saving them
                 */
            }
            break;
        }
    }

    return ret_code;
}

/*
 * clear errors down at the start of a new statement
 * only clear for the ODBC lists, the rest stay
 */

void function_entry( void *handle )
{
    ERROR *cur, *prev;
    EHEAD *error_header;
    DMHENV henv;
    DMHDBC hdbc;
    DMHSTMT hstmt;
    DMHDESC hdesc;

    /*
     * find what the handle is
     */

    henv = handle;
    switch( henv -> type )
    {
      case HENV_MAGIC:
        error_header = &henv -> error;
        break;

      case HDBC_MAGIC:
        hdbc = handle;
        error_header = &hdbc -> error;
        break;

      case HSTMT_MAGIC:
        hstmt = handle;
        error_header = &hstmt -> error;
        break;

      case HDESC_MAGIC:
        hdesc = handle;
        error_header = &hdesc -> error;
        break;
    }

    prev = NULL;
    cur = error_header -> sql_diag_head.error_list_head;

    while( cur )
    {
        prev = cur;

        free( prev -> msg );
        cur = prev -> next;
        free( prev );
    }

    error_header -> sql_diag_head.error_list_head = NULL;
    error_header -> sql_diag_head.error_list_tail = NULL;
    error_header -> sql_diag_head.error_count = 0;

    prev = NULL;
    cur = error_header -> sql_diag_head.internal_list_head;

    while( cur )
    {
        prev = cur;

        free( prev -> msg );
        cur = prev -> next;
        free( prev );
    }

    error_header -> sql_diag_head.internal_list_head = NULL;
    error_header -> sql_diag_head.internal_list_tail = NULL;
    error_header -> sql_diag_head.internal_count = 0;
}

void __post_internal_error( EHEAD *error_handle,
        error_id id, char *txt, int connection_mode )
{
    char sqlstate[ 6 ];
    char *message;

    switch( id )
    {
      case ERROR_01000:
        strcpy( sqlstate, "01000" );
        message = "General warning";
        break;

      case ERROR_01004:
        strcpy( sqlstate, "01004" );
        message = "String data, right truncated";
        break;

      case ERROR_01S02:
        strcpy( sqlstate, "01S02" );
        message = "Option value changed";
        break;

      case ERROR_01S06:
        strcpy( sqlstate, "01S06" );
        message = "Attempt to fetch before the result set returned the first rowset";
        break;

      case ERROR_07005:
        strcpy( sqlstate, "07005" );
        message = "Prepared statement not a cursor-specification";
        break;

      case ERROR_07009:
        strcpy( sqlstate, "07009" );
        message = "Invalid descriptor index";
        break;

      case ERROR_08002:
        strcpy( sqlstate, "08002" );
        message = "Connection name in use";
        break;

      case ERROR_08003:
        strcpy( sqlstate, "08003" );
        message = "Connnection does not exist";
        break;

      case ERROR_24000:
        strcpy( sqlstate, "24000" );
        message = "Invalid cursor state";
        break;

      case ERROR_25000:
        message = "Invalid transaction state";
        strcpy( sqlstate, "25000" );
        break;

      case ERROR_25S01:
        message = "Transaction state unknown";
        strcpy( sqlstate, "25S01" );
        break;

      case ERROR_S1000:
        message = "General error";
        strcpy( sqlstate, "S1000" );
        break;

      case ERROR_S1010:
        message = "Function sequence error";
        strcpy( sqlstate, "S1010" );
        break;

      case ERROR_S1011:
        message = "Operation invalid at this time";
        strcpy( sqlstate, "S1011" );
        break;

      case ERROR_S1107:
        message = "Row value out of range";
        strcpy( sqlstate, "S1107" );
        break;

      case ERROR_S1108:
        message = "Concurrency option out of range";
        strcpy( sqlstate, "S1108" );
        break;

      case ERROR_S1C00:
        message = "Driver not capable";
        strcpy( sqlstate, "S1C00" );
        break;

      case ERROR_HY001:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY001" );
        else
            strcpy( sqlstate, "S1011" );
        message = "Memory allocation error";
        break;

      case ERROR_HY004:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY004" );
        else
            strcpy( sqlstate, "S1004" );
        message = "Invalid SQL data type";
        break;

      case ERROR_HY009:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY009" );
        else
            strcpy( sqlstate, "S1009" );
        message = "Invalid use of null pointer";
        break;

      case ERROR_HY010:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY010" );
        else
            strcpy( sqlstate, "S1010" );
        message = "Function sequence error";
        break;

      case ERROR_HY011:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY011" );
        else
            strcpy( sqlstate, "S1011" );
        message = "Attribute cannot be set now";
        break;

      case ERROR_HY013:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY013" );
        else
            strcpy( sqlstate, "S1013" );
        message = "Memory management error";
        break;

      case ERROR_HY017:
        strcpy( sqlstate, "HY017" );
        message = "Invalid use of an automatically allocated descriptor handle";
        break;

      case ERROR_HY024:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY024" );
        else
            strcpy( sqlstate, "S1009" );
        message = "Invalid attribute value";
        break;

      case ERROR_HY090:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY090" );
        else
            strcpy( sqlstate, "S1090" );
        message = "Invalid string or buffer length";
        break;

      case ERROR_HY092:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY092" );
        else
            strcpy( sqlstate, "S1092" );
        message = "Invalid attribute/option identifier";
        break;

      case ERROR_HY097:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY097" );
        else
            strcpy( sqlstate, "S1097" );
        message = "Column type out of range";
        break;

      case ERROR_HY098:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY098" );
        else
            strcpy( sqlstate, "S1098" );
        message = "Scope type out of range";
        break;

      case ERROR_HY099:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY099" );
        else
            strcpy( sqlstate, "S1099" );
        message = "Nullable type out of range";
        break;

      case ERROR_HY100:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY100" );
        else
            strcpy( sqlstate, "S1100" );
        message = "Uniqueness option type out of range";
        break;

      case ERROR_HY101:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY101" );
        else
            strcpy( sqlstate, "S1101" );
        message = "Accuracy option type out of range";
        break;

      case ERROR_HY103:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY103" );
        else
            strcpy( sqlstate, "S1103" );
        message = "Invalid retrieval code";
        break;

      case ERROR_HY105:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY105" );
        else
            strcpy( sqlstate, "S1105" );
        message = "Invalid parameter type";
        break;

      case ERROR_HY106:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY106" );
        else
            strcpy( sqlstate, "S1106" );
        message = "Fetch type out of range";
        break;

      case ERROR_HY110:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HY110" );
        else
            strcpy( sqlstate, "S1110" );
        message = "Invalid driver completion";
        break;

      case ERROR_HYC00:
        if ( connection_mode == SQL_OV_ODBC3 )
            strcpy( sqlstate, "HYC00" );
        else
            strcpy( sqlstate, "S1C00" );
        message = "Optional featire not implemented";
        break;

      case ERROR_IM001:
        strcpy( sqlstate, "IM001" );
        message = "Driver does not support this function";
        break;

      case ERROR_IM002:
        strcpy( sqlstate, "IM002" );
        message = "Data source name not found, and no default driver specified";
        break;

      case ERROR_IM003:
        strcpy( sqlstate, "IM003" );
        message = "Specified driver could not be loaded";
        break;

      case ERROR_IM004:
        strcpy( sqlstate, "IM004" );
        message = "Driver's SQLAllocHandle on SQL_HANDLE_HENV failed";
        break;

      case ERROR_IM005:
        strcpy( sqlstate, "IM005" );
        message = "Driver's SQLAllocHandle on SQL_HANDLE_DBC failed";
        break;

      case ERROR_IM010:
        strcpy( sqlstate, "IM010" );
        message = "Data source name too long";
        break;

      case ERROR_IM012:
        strcpy( sqlstate, "IM012" );
        message = "DRIVER keyword syntax error";
        break;

      case ERROR_SL004:
        strcpy( sqlstate, "SL004" );
        message = "Result set not generated by a SELECT statement";
        break;

      case ERROR_SL009:
        strcpy( sqlstate, "SL009" );
        message = "No columns were bound prior to calling SQLFetch or SQLFetchScroll";
        break;

      case ERROR_SL010:
        strcpy( sqlstate, "SL010" );
        message = "SQLBindCol returned SQL_ERROR on a attempt to bind a internal buffer";
        break;

	  default:
        strcpy( sqlstate, "?????" );
        message = "Unknown";

    }

    if ( txt )
        message = txt;

    __post_internal_error_ex( error_handle,
        sqlstate, 0, message );
}

/*
 * open a log file
 */

int dm_log_open( DMLHANDLE *log_handle, char *program_name,
        char *log_file )
{
    *log_handle = malloc( sizeof( DMLHANDLE ));

    if ( *log_handle )
    {
        (*log_handle) -> program_name = strdup( program_name );
        (*log_handle) -> log_file = strdup( log_file );

        return 1;
    }
    else
    {
        return 0;
    }
}

void dm_log_write( DMLHANDLE log_handle, char *pid,
        char *function_name, int line, int type, int severity,
        char *message )
{
    FILE *fp;

    if ( !log_handle )
        return;

    fp = fopen( log_handle -> log_file, "a" );
    if ( !fp )
    {
        fp = stderr;
    }

    fprintf( fp, "[%s][%s][%s][%d]%s\n", log_handle -> program_name,
            pid, function_name, line, message );

    if ( fp != stderr )
    {
        fclose( fp );
    }
}

void dm_log_close( DMLHANDLE log_handle )
{
    if ( !log_handle )
        return;

    free( log_handle -> program_name );
    free( log_handle -> log_file );
    free( log_handle );
}
