.ad 8
.bm 8
.fm 4
.bt $Copyright (c) 2000-2004 SAP AG$$Page %$
.tm 12
.hm 6
.hs 3
.tt 1 $SQL$Project Distributed Database System$VPA10AC$
.tt 2 $$$
.TT 3 $BurkhardD$CORE-LEVEL FUNCTIONS A - D$$2001-06-27$
***********************************************************
.nf

.nf


    ========== licence begin  GPL
    Copyright (c) 2000-2004 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end

.fo


.fo
Module  :
=========
.sp
Purpose :
.CM *-END-* purpose -------------------------------------
Define  :
.CM *-END-* define --------------------------------------
Use     :
.CM *-END-* use -----------------------------------------
Synonym :
.CM *-END-* synonym -------------------------------------
.sp;.cp 3
Author  : BurkhardD
.sp
.cp 3
Created : 08-31-1993
.sp
.cp 3
Version : 1994-04-25
.sp
.cp 3
Release :  7.3    Date : 2001-06-27
.sp
Specification:
.CM *-END-* specification -------------------------------
.sp 2
***********************************************************
.sp
.cp 10
.fo
.oc _/1
Description:
.CM *-END-* description ---------------------------------
.sp 2
***********************************************************
.sp
.cp 10
.nf
.oc _/1
Structure:
.CM *-END-* structure -----------------------------------
.sp 2
**********************************************************
.sp
.cp 10
.nf
.CM -lll-
Code    :
#ifndef DEBUG
#line 63 "vpa10ac"
#endif
#ifdef WIN
extern int InitWSA(UCHAR FAR *database);
extern HANDLE s_hModule;
#endif
tsp00_Int2 pa01UtilityConnect(void);

#include "vpa00global.h"
#include "vpa10Handle.h"
#include "vpa50Env.h"
#include "vpa40DBC.h"
#include "vpa60Stmt.h"
#include "vpa80String.h"
#include "vpa30.h"
#include "vpa06.h"
#include "vpa09.h"

/* global variables           */
/* Prototypes */
#ifndef SAPDB_FAST
#ifndef _UNICODE_ODBC
UCHAR *PA10_FN_SQLBINDCOL = { (UCHAR*) "SQLBindCol" };
UCHAR *PA10_FN_SQLCANCEL = { (UCHAR*) "SQLCancel" };
UCHAR *PA10_FN_SQLCLOSECURSOR = { (UCHAR*) "SQLCloseCursor" };
UCHAR *PA10_FN_SQLCOLATTRIBUTE = { (UCHAR*) "SQLColAttribute" };
UCHAR *PA10_FN_SQLDESCRIBECOL = { (UCHAR*) "SQLDescribeCol" };
#else
extern UCHAR *PA10_FN_SQLBINDCOL;
extern UCHAR *PA10_FN_SQLCANCEL;
extern UCHAR *PA10_FN_SQLCLOSECURSOR;
extern UCHAR *PA10_FN_SQLCOLATTRIBUTE;
extern UCHAR *PA10_FN_SQLDESCRIBECOL;
#endif
#endif

#ifndef _UNICODE_ODBC
UWORD cross_check = 0;            /* field to check for invalid */
                                  /* dll reuse (prevents bad    */
                                  /* abends in slold)           */
                                  /* data source name from the  */
                                  /* SQLConnect()               */
#endif  /* _UNICODE_ODBC */

#ifndef _UNICODE_ODBC
/* binds a storage location to a field/column */
ODBC_PROC( SQLBindCol, 
           (SQLHSTMT      hstmt,
            SQLUSMALLINT  icol,
            SQLSMALLINT   fCType,
            SQLPOINTER    rgbValue,
            SQLLEN        cbValueMax,
            SQLLEN       *pcbValue),
           (hstmt, icol, fCType, rgbValue, cbValueMax, pcbValue))
{
    RETCODE retcode;
    API_RETCODE api_retcode;
    tpa60Stmt FAR * stmt_block_ptr;
    SWORD real_c_type;
    tpa21DescRecord *appl_rec_ptr;
    tpa21DescRecord *impl_rec_ptr;
    SQLULEN octetLength;
    
    API_TRACE( API_TR_ENTRY, PA10_FN_SQLBINDCOL, 0);
    API_TRACE( API_TR_HANDLE, "hstmt", &hstmt);
    API_TRACE( API_TR_UWORD, "icol", &icol);
    API_TRACE( API_TR_CTYPE, "fCType", &fCType);
    API_TRACE( API_TR_PTR, "rgbValue", &rgbValue);
    API_TRACE( API_TR_SDWORD, "cbValueMax", &cbValueMax);
    API_TRACE( API_TR_PTR, "pcbValue", &pcbValue);

    retcode = SQL_SUCCESS;

    if (pa60VerifyStmt( hstmt ) != API_OK) { /* hstmt valid? */
        retcode = SQL_INVALID_HANDLE;
    }
    else {
        apmstfc(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, SQL_API_SQLBINDCOL);
        /* check column number        */
        if (icol == 0) {
            if (fCType != SQL_C_BOOKMARK
                && fCType != SQL_C_VARBOOKMARK) {
                /* Program type out of range */
                retcode = SQL_ERROR;
                pa60PutError( hstmt, API_ODBC_S1003, NULL);
            }
        } else {
            /* check program type         */
            switch (fCType) {
            case (SQL_C_WCHAR): {}
            case (SQL_C_CHAR): {}
            case (SQL_C_SLONG): {}
            case (SQL_C_ULONG): {}
            case (SQL_C_LONG): {}
            case (SQL_C_SSHORT): {}
            case (SQL_C_USHORT): {}
            case (SQL_C_SHORT): {}
            case (SQL_C_NUMERIC): {} /* new in 3.0 */
#ifdef BIGINT_SUPPORTED                
            case (SQL_C_SBIGINT): {} /* new in 3.0 */
            case (SQL_C_UBIGINT): {} /* new in 3.0 */
#endif /* BIGINT_SUPPORTED */                
            case (SQL_C_FLOAT): {}
            case (SQL_C_DOUBLE): {}
            case (SQL_C_TYPE_DATE): {}
            case (SQL_C_TYPE_TIME): {}
            case (SQL_C_TYPE_TIMESTAMP): {}
            case (SQL_C_DATE): {}
            case (SQL_C_TIME): {}
            case (SQL_C_TIMESTAMP): {}
            case (SQL_C_BINARY):{}
            case (SQL_C_BIT):{}
            case (SQL_C_STINYINT):{}
            case (SQL_C_UTINYINT):{}
            case (SQL_C_TINYINT):{}
            case (SQL_C_DEFAULT): {
                break;
            }
            default: {
                retcode = SQL_ERROR;
                pa60PutError( hstmt, API_ODBC_S1003, NULL );
            }
            }
        }; /* else */
        /* check buffer               */
        if (retcode == SQL_SUCCESS && cbValueMax < 0) {
            retcode = SQL_ERROR;
            pa60PutError( hstmt, API_ODBC_S1009, NULL); /* invalid buffer
                                                         * length     */
        }; /* if */
        if (retcode == SQL_SUCCESS) {
            stmt_block_ptr = (tpa60Stmt FAR *) apdlock(hstmt);
            API_ASSERT_PTR(stmt_block_ptr);
            /* check for overflow of the  */
            /* attribute block array      */
            /* reallocate attr blocks,    */
            /* note this function keeps   */
            /* the old contents           */
            api_retcode = pa20ReallocRecords( stmt_block_ptr->ardPtr,
                                              (UWORD) (icol + API_BIND_INC) );
            if (api_retcode != API_OK) {
                retcode = SQL_ERROR;
                pa60PutError( hstmt, API_ODBC_S1001, NULL);
                /* memory allocation failure */
                apdunlk(hstmt);
                goto error_exit;
            }; /* if */
            api_retcode = pa20ReallocRecords( &stmt_block_ptr->ird,
                                              (UWORD) (icol + API_BIND_INC) );
            if (api_retcode != API_OK) {
                retcode = SQL_ERROR;
                pa60PutError( hstmt, API_ODBC_S1001, NULL);
                /* memory allocation failure */
                apdunlk(hstmt);
                goto error_exit;
            }; /* if */
            
            apdunlk(hstmt);
            appl_rec_ptr = pa20GetRecord( stmt_block_ptr->ardPtr, icol );
            API_ASSERT_PTR( appl_rec_ptr );
            impl_rec_ptr = pa20GetRecord( &stmt_block_ptr->ird, icol );
            API_ASSERT_PTR( impl_rec_ptr );
            
            if (rgbValue)
                appl_rec_ptr -> bound = API_TRUE;
            else {
                appl_rec_ptr -> bound = API_FALSE;
                /* reset count to index of last bound column */
                pa20InitCount( stmt_block_ptr->ardPtr );
            }; /* else */
            pa21SetCType( appl_rec_ptr, fCType );
            appl_rec_ptr -> length = cbValueMax;
            apgstyc( SQL_C_DEFAULT,
                     cbValueMax,
                     fCType,
                     PA_NO_VALID_LEN,
                     PA_NO_VALID_LEN,
                     &real_c_type,
                     &octetLength);

            appl_rec_ptr->octetLength = (SQLLEN) octetLength;
            if (!pa20TypesAreConsistent( stmt_block_ptr->ardPtr, icol )) {
                pa60PutError( hstmt, API_ODBC_HY021, NULL );
                /* Inconsistent descriptor information */
                goto error_exit;
            }; /* else */            
            appl_rec_ptr -> dataPtr        = rgbValue;
            appl_rec_ptr -> octetLengthPtr = pcbValue;
            appl_rec_ptr -> indicatorPtr   = pcbValue;
            impl_rec_ptr -> parameterType  = SQL_PARAM_OUTPUT;
        }; /* if (retcode==SQL_SUCCESS) */
    }; /* else */

error_exit:
    API_TRACE(API_TR_EXIT,PA10_FN_SQLBINDCOL,0);
    API_TRACE(API_TR_RETCODE,"retcode",&retcode);

    return(retcode);

} /* SQLBIndCol */


ODBC_PROC( SQLCancel,
           (SQLHSTMT   hstmt),
           (hstmt))
{
    SQLHDBC      hdbc;
    tpa40DBC    *dbc_block_ptr;
    SQLHENV      henv;
    tpa50Env    *env_block_ptr;
    tpa60Stmt   *stmt_block_ptr;
    RETCODE	     retcode=SQL_SUCCESS;
    API_RETCODE	 api_retcode;
    UWORD		 number_cols;

    API_TRACE(API_TR_ENTRY,PA10_FN_SQLCANCEL,0);
    API_TRACE(API_TR_HANDLE,"hstmt",&hstmt);

    api_retcode = apmstfc(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, 
                          SQL_API_SQLCANCEL);
    if (api_retcode != API_OK) {
        retcode = SQL_INVALID_HANDLE;
    }
    else {    
        apmlocp( &hstmt, &stmt_block_ptr, &hdbc, &dbc_block_ptr,
                 &henv, &env_block_ptr);
        if (pa09IsAsync(stmt_block_ptr, dbc_block_ptr, &retcode)) {
            retcode = SQL_SUCCESS;
#ifdef ASYNCENABLED
            if (stmt_block_ptr->async.hThread) {
                pa09Semaphore (PA09_SEMAPHORE_SQLCANCEL, PA09_WAIT_FOR_SEMAPHORE);  /* PTS 1120833 */
                apecancel(&dbc_block_ptr->esqblk, dbc_block_ptr);
                if (dbc_block_ptr->esqblk.esq_sql_code != 0) { 
                    retcode = SQL_ERROR;
                    pa60PutError( hstmt, pa41apmercv(&dbc_block_ptr->esqblk),
                                  &dbc_block_ptr->esqblk);
                }     
                stmt_block_ptr->async.canceled = TRUE;
                pa09Semaphore (PA09_SEMAPHORE_SQLCANCEL, PA09_RELEASE_SEMAPHORE);
            }
#endif
        }
        else {
            UDWORD odbcVersion = 0;

            pa10GetODBCVersion( SQL_HANDLE_DBC,
                                (SQLHANDLE) dbc_block_ptr,
                                &odbcVersion );
            if (odbcVersion < SQL_OV_ODBC3) {
                /* treat Cancel as SQLFreeStmt( SQL_CLOSE ) */
                number_cols = stmt_block_ptr -> number_cols;
     
                retcode = CALL_ODBC(SQLFreeStmt,(hstmt, (UWORD) SQL_CLOSE));
                
                if ((retcode == SQL_SUCCESS) && (number_cols > 0)) {
                    retcode = SQL_SUCCESS_WITH_INFO;  
                    /* Cancel treated as FreeStmt/Close */
                    pa60PutError( hstmt, API_ODBC_01S05, NULL);
                }
            }
        }
    }

    API_TRACE(API_TR_EXIT,PA10_FN_SQLCANCEL,0);
    API_TRACE(API_TR_RETCODE,"retcode",&retcode);

    return (retcode);
} /* SQLCancel */


/* ODBC 3.0 */
ODBC_PROC( SQLCloseCursor, (SQLHSTMT    hstmt),
           (hstmt))
{
   RETCODE retcode = SQL_ERROR;
   tpa60Stmt *stmtPtr = NULL;
   
   API_TRACE( API_TR_ENTRY, PA10_FN_SQLCLOSECURSOR, 0);
   API_TRACE( API_TR_HANDLE, "hstmt", &hstmt);
   
   if (pa60VerifyStmt( hstmt ) != API_OK) { /* hstmt valid? */
       retcode = SQL_INVALID_HANDLE;
   } else {
       stmtPtr = (tpa60Stmt*) hstmt;
       if (stmtPtr->state != API_STMT_EXECUTED
           && stmtPtr->state != API_STMT_POSITIONED ) {
           retcode = SQL_ERROR;
           pa60PutError( hstmt,
                         API_ODBC_24000, NULL); /* Invalid cursor state */
       } else {
           retcode = CALL_ODBC( SQLFreeStmt, ( hstmt, SQL_CLOSE ) );
       }; /* else */
   }; /* else */
   
   API_TRACE( API_TR_EXIT, PA10_FN_SQLCLOSECURSOR, 0);
   API_TRACE( API_TR_RETCODE, "retcode", &retcode);

   return (retcode);
} /* SQLCloseCursor */
#endif   /* _UNICODE_ODBC */

/* for WIN64 MS changed the type of pfDesc from SQLPOINTER to SQLLEN* */
#ifdef _WIN64
#define SQL_7_ARGTYPE SQLLEN*
#else
#define SQL_7_ARGTYPE SQLPOINTER
#endif

#ifdef _UNICODE_ODBC
ODBC_PROC( SQLColAttributeW,
           (SQLHSTMT      hstmt,
            SQLUSMALLINT  icol,
            SQLUSMALLINT  fDescType,
            SQLPOINTER    rgbDesc,
            SQLSMALLINT   cbDescMax,
            SQLSMALLINT  *pcbDesc,
            SQL_7_ARGTYPE pfDesc),
           (hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc))
#else
ODBC_PROC( SQLColAttribute,
           (SQLHSTMT      hstmt,
            SQLUSMALLINT  icol,
            SQLUSMALLINT  fDescType,
            SQLPOINTER    rgbDesc,
            SQLSMALLINT   cbDescMax,
            SQLSMALLINT  *pcbDesc,
            SQL_7_ARGTYPE pfDesc),
           (hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc))
#endif
#undef SQL_7_ARGTYPE
{
    RETCODE      retcode = SQL_ERROR;
    API_RETCODE  api_retcode;
    UWORD        number_cols;
    UWORD        state;
    API_HANDLE   sqlda_handle;
    sqldatype   *sqlda_ptr;
    tpa60Stmt   *stmt_block_ptr;
    UWORD        sqlState = API_ODBC_00000; /* success */
#ifdef _UNICODE_ODBC
    const tsp77encoding *nativeEncoding = sp77nativeUnicodeEncoding ();
#else
    const tsp77encoding *nativeEncoding = sp77encodingAscii; 
#endif
   
    API_TRACE(API_TR_ENTRY,PA10_FN_SQLCOLATTRIBUTE,0);
    API_TRACE(API_TR_HANDLE,"hstmt",&hstmt);
    API_TRACE(API_TR_UWORD,"icol",&icol);
    API_TRACE(API_TR_COLATTR,"fDescType",&fDescType);
    API_TRACE(API_TR_PTR,"rgbDesc",&rgbDesc);
    API_TRACE(API_TR_SWORD,"cbDescMax",&cbDescMax);
    API_TRACE(API_TR_PTR,"pcbDesc",&pcbDesc);
    API_TRACE(API_TR_SWORD,"pcbDesc", pcbDesc);
    API_TRACE(API_TR_SDWORD,"pfDesc", pfDesc);

  
    if ( apmstfc( SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
                  SQL_API_SQLCOLATTRIBUTES) != API_OK) {
        retcode = SQL_INVALID_HANDLE;
    }
    else {
        /* verify the statement */
        if (pa60VerifyStmt( hstmt ) != API_OK) {
            retcode = SQL_INVALID_HANDLE;
        }
        else {
            /* lock memory for the statement */
            stmt_block_ptr = (tpa60Stmt FAR *) apdlock(hstmt);
            API_ASSERT_PTR(stmt_block_ptr);
            state = stmt_block_ptr->state;
            /* get number of columns touched */
            number_cols = stmt_block_ptr -> number_cols;
            /* get link for output-sqlda  */
            /* and output-attribute-array */
            sqlda_handle = stmt_block_ptr -> output_sqlda_handle;

            if (state == API_STMT_ALLOCATED) {
                retcode = SQL_ERROR;
                pa60PutError( hstmt, API_ODBC_S1010, NULL);
                /* function sequence error */
                goto exit_1_lock;
            }
            /* make sure ... */
            if ( (fDescType > SQL_COLUMN_LABEL)
                 && fDescType != SQL_DESC_BASE_TABLE_NAME                  
                 && fDescType != SQL_DESC_BASE_COLUMN_NAME
                 && fDescType != SQL_DESC_CONCISE_TYPE                 
                 && fDescType != SQL_DESC_COUNT
                 && fDescType != SQL_DESC_LENGTH
                 && fDescType != SQL_DESC_LITERAL_PREFIX                 
                 && fDescType != SQL_DESC_LITERAL_SUFFIX                 
                 && fDescType != SQL_DESC_LOCAL_TYPE_NAME                 
                 && fDescType != SQL_DESC_NAME
                 && fDescType != SQL_DESC_NUM_PREC_RADIX                 
                 && fDescType != SQL_DESC_NULLABLE
                 && fDescType != SQL_DESC_OCTET_LENGTH                 
                 && fDescType != SQL_DESC_PRECISION
                 && fDescType != SQL_DESC_SCALE
                 && fDescType != SQL_DESC_TYPE
                 && fDescType != SQL_DESC_UNNAMED) {                
                retcode = SQL_ERROR;
                pa60PutError( hstmt, API_ODBC_S1091, NULL);
                /* Descriptor type out of range */
                goto exit_1_lock;
            }
#ifdef _UNICODE_ODBC
            if (   fDescType == SQL_DESC_BASE_COLUMN_NAME
                || fDescType == SQL_DESC_BASE_TABLE_NAME
                || fDescType == SQL_DESC_CATALOG_NAME
                || fDescType == SQL_DESC_LABEL
                || fDescType == SQL_DESC_LITERAL_PREFIX
                || fDescType == SQL_DESC_LITERAL_SUFFIX
                || fDescType == SQL_DESC_LOCAL_TYPE_NAME
                || fDescType == SQL_DESC_SCHEMA_NAME
                || fDescType == SQL_DESC_TABLE_NAME
                || fDescType == SQL_DESC_TYPE_NAME) {

                /* for UNICODE: buffer length must be an even number */
                if (cbDescMax & 1 && cbDescMax > 0)
                    cbDescMax--;
            }
#endif
            
            if (number_cols == 0) {          /* statement has columns */
                retcode = SQL_ERROR;
                pa60PutError( hstmt, API_ODBC_24000, NULL); /* invalid
                                                             * cursor state */
                goto exit_1_lock;
            }
            if (fDescType != SQL_COLUMN_COUNT) {
                /* make sure ... */
                if (icol > number_cols) { /* column is valid */
                    retcode = SQL_ERROR;
                    pa60PutError( hstmt, API_ODBC_S1002, NULL);
                    /* invalid column number */
                    goto exit_1_lock;
                }
            }
            if (fDescType == SQL_COLUMN_NAME || 
                fDescType == SQL_COLUMN_LABEL) {
                /* make sure ... */
                if (cbDescMax < 0) { /* cbDescMax is valid */
                    retcode = SQL_ERROR;
                    pa60PutError( hstmt, API_ODBC_S1090, NULL);
                    /* invalid string or buffer length */
                    goto exit_1_lock;
                }
            }

            if (fDescType == SQL_COLUMN_TABLE_NAME
                ||fDescType == SQL_DESC_BASE_TABLE_NAME) {
              UDWORD len;
                retcode =
                    pa80CopyTpr05String ((UCHAR*) rgbDesc,
                                         cbDescMax,
                                         &len,
                                         stmt_block_ptr->table_name,
                                         &sqlState );
                if (sqlState != API_ODBC_00000) {
                    pa60PutError( hstmt, sqlState, NULL );
                }
                else
                  *pcbDesc = (SQLSMALLINT) len;
            } else {
                /* lock the SQLDA */
                sqlda_ptr = (sqldatype FAR *) apdlock(sqlda_handle);
                API_ASSERT_PTR(sqlda_ptr);
                api_retcode = pa20ColAttr( sqlda_ptr,
                                           &stmt_block_ptr->ird,
                                           icol,
                                           fDescType,
                                           rgbDesc,
                                           cbDescMax,
                                           pcbDesc,
                                           (SQLPOINTER) pfDesc,
                                           nativeEncoding);
                switch (api_retcode) {
                case (API_OK): {
                    retcode = SQL_SUCCESS;
                    break;
                }
                case (API_NOT_OK): {
                    retcode = SQL_ERROR;
                break;
                }
                case (API_TRUNCATE): {
                    retcode = SQL_SUCCESS_WITH_INFO;
                    pa60PutError( hstmt, API_ODBC_01004, NULL );
                    break;
                }
                }
                /* all done */
                /* unlock sqlda, attribute-array */
                apdunlk(sqlda_handle);
            }; /* else */
            
        exit_1_lock:
            apdunlk(hstmt);                 /* unlock statement */
        }
    }
    /* trace output parameter, ret-code */
    API_TRACE(API_TR_EXIT,PA10_FN_SQLCOLATTRIBUTE,0);
    API_TRACE(API_TR_RETCODE,"retcode",&retcode);
    if (rgbDesc &&
        (fDescType == SQL_COLUMN_NAME
         || fDescType == SQL_DESC_LABEL
         || fDescType == SQL_COLUMN_LABEL
         || fDescType == SQL_DESC_NAME
         || fDescType == SQL_COLUMN_TABLE_NAME
         || fDescType == SQL_DESC_LITERAL_PREFIX
         || fDescType == SQL_DESC_LITERAL_SUFFIX
         || fDescType == SQL_DESC_LOCAL_TYPE_NAME
         || fDescType == SQL_DESC_BASE_TABLE_NAME
         || fDescType == SQL_DESC_BASE_COLUMN_NAME)) {
        API_TRACE_LEN( API_TR_ODBC_STRING, "rgbDesc", rgbDesc, *pcbDesc );
    }
    API_TRACE(API_TR_SWORD,"*pcbDesc",pcbDesc);
    API_TRACE(API_TR_SWORD,"*pfDesc",pfDesc);

    return (retcode);
} /* SQLColAttribute */


/* describes one field/column in the resultant table */
#ifdef _UNICODE_ODBC
ODBC_PROC( SQLDescribeColW,
           (SQLHSTMT        hstmt,
            SQLUSMALLINT    icol,
            SQLWCHAR       *szColName,
            SQLSMALLINT     cbColNameMax,
            SQLSMALLINT    *pcbColName,
            SQLSMALLINT    *pfSqlType,
            SQLULEN        *pcbColDef,
            SQLSMALLINT    *pibScale,
            SQLSMALLINT    *pfNullable),
          ( hstmt, icol, szColName, cbColNameMax, pcbColName, pfSqlType, pcbColDef, pibScale, pfNullable))
#else
ODBC_PROC( SQLDescribeCol,
           (SQLHSTMT        hstmt,
            SQLUSMALLINT    icol,
            SQLCHAR        *szColName,
            SQLSMALLINT     cbColNameMax,
            SQLSMALLINT    *pcbColName,
            SQLSMALLINT    *pfSqlType,
            SQLULEN        *pcbColDef,
            SQLSMALLINT    *pibScale,
            SQLSMALLINT    *pfNullable),
          ( hstmt, icol, szColName, cbColNameMax, pcbColName, pfSqlType, pcbColDef, pibScale, pfNullable))
#endif
{
    RETCODE retcode = SQL_ERROR;
    API_RETCODE api_retcode;
    UWORD       number_cols;
    UWORD       state;
    API_HANDLE  sqlda_handle;
    sqldatype  *sqlda_ptr;
    tpa60Stmt  *stmt_block_ptr;
#ifdef _UNICODE_ODBC
    const tsp77encoding *nativeEncoding = sp77nativeUnicodeEncoding ();
#else
    const tsp77encoding *nativeEncoding = sp77encodingAscii; 
#endif
    
    API_TRACE(API_TR_ENTRY,PA10_FN_SQLDESCRIBECOL,0);
    API_TRACE(API_TR_HANDLE,"hstmt",&hstmt);
    API_TRACE(API_TR_WORD,"icol",&icol);
    API_TRACE(API_TR_PTR,"szColName",&szColName);
    API_TRACE(API_TR_SWORD,"cbColNameMax",&cbColNameMax);
    API_TRACE(API_TR_PTR,"pcbColName",&pcbColName);
    API_TRACE(API_TR_PTR,"pfSqlType",&pfSqlType);
    API_TRACE(API_TR_PTR,"pcbColDef",&pcbColDef);
    API_TRACE(API_TR_PTR,"pibScale",&pibScale);
    API_TRACE(API_TR_PTR,"pfNullable",&pfNullable);

    if (apmstfc(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, 
                SQL_API_SQLDESCRIBECOL) != API_OK) {
        retcode = SQL_INVALID_HANDLE;
    }
    else {
        if (pa60VerifyStmt( hstmt ) != API_OK) { /* hstmt valid? */
            retcode = SQL_INVALID_HANDLE;
        }
        else {
            stmt_block_ptr = (tpa60Stmt FAR *) apdlock(hstmt);
            API_ASSERT_PTR(stmt_block_ptr);
            state = stmt_block_ptr->state;
            number_cols = stmt_block_ptr -> number_cols;
            sqlda_handle = stmt_block_ptr -> output_sqlda_handle;
            /* verify statement prepared */
            if (state == API_STMT_ALLOCATED) {
                retcode = SQL_ERROR;
                pa60PutError( hstmt,
                              API_ODBC_S1010, /* function sequence error */
                              NULL);
                goto exit_1_lock;
            }
            /* verify statement has cols  */
            if (number_cols == 0) {
                retcode = SQL_ERROR;
                pa60PutError( hstmt, API_ODBC_24000, NULL); /* invalid
                                                             * cursor state */
                goto exit_1_lock;
            }
            /* make sure the column */
            /* is valid             */
            if (icol > number_cols) {
                retcode = SQL_ERROR;
                pa60PutError( hstmt, API_ODBC_S1002, NULL); /* invalid
                                                             * column number */
                goto exit_1_lock;
            }
            /* make sure the        */
            /* cbColNameMax is valid*/
            if (cbColNameMax < 0) {
                retcode = SQL_ERROR;
                pa60PutError( hstmt, API_ODBC_S1090, NULL); /* invalid
                                                             * buffer length */
                goto exit_1_lock;
            };
            /* column 0 is only valid if bookmarks are enabled */
            if (icol == 0
                && stmt_block_ptr->stmtopt.use_bookmarks == SQL_UB_OFF) {
                /* invalid descriptor index */
                pa60PutError( hstmt, API_ODBC_07009, NULL); 
                goto exit_1_lock;
            }; /* if */
            
            /* lock the SQLDA */
            sqlda_ptr = (sqldatype*) apdlock(sqlda_handle);
            API_ASSERT_PTR(sqlda_ptr);
    
            /* notice that only pointers  */
            /* are passed, no "handles",  */
            /* the storage management is  */
            /* done in this routine.      */

            api_retcode =
                pa20DescribeCol( sqlda_ptr,          /* pointer to SQLDA */
                                 &stmt_block_ptr->ird,
                                 icol,               /* column number */
                                 (UCHAR*) szColName, /* ptr to column name
                                                      * as a C string      */
                                 cbColNameMax,       /* max size column name */
                                 pcbColName,         /* ptr to col. name size */
                                 pfSqlType,          /* ptr to data type */
                                 pcbColDef,          /* ptr to precision */
                                 pibScale,           /* ptr to scale */
                                 pfNullable,         /* ptr to "null"able flag */
                                 nativeEncoding);
    
            /* likewise, the ODBC style   */
            /* error handling is done here*/
            /* and not in the "low-level" */
            /* routine                    */

            switch (api_retcode) {
            case (API_OK):
                retcode = SQL_SUCCESS;
                break;
            case (API_NOT_OK):
                retcode = SQL_ERROR;
                break;
            case (API_TRUNCATE):
                retcode = SQL_SUCCESS_WITH_INFO;
                pa60PutError( hstmt, API_ODBC_01004, NULL); /* data
                                                             * truncated */
                break;
            }
            /* all done */
            apdunlk(sqlda_handle);

        exit_1_lock:
            apdunlk(hstmt);
        } /* of if hstmt valid */
    } /* of set odbc_function */

    pa06ConvDateTimeTypes( stmt_block_ptr, pfSqlType );
    
    API_TRACE(API_TR_EXIT,PA10_FN_SQLDESCRIBECOL,0);
    API_TRACE(API_TR_RETCODE,"retcode",&retcode);
    if (retcode != SQL_ERROR) {
        if (szColName != NULL &&
            pcbColName != NULL) {
            API_TRACE_LEN(API_TR_ODBC_STRING,"szColName",
                          szColName,*pcbColName);
        }
        if (pcbColName != NULL) {
            API_TRACE(API_TR_SWORD,"*pcbColName",pcbColName);
        }
        if (pfSqlType != NULL) {
            API_TRACE(API_TR_SQLTYPE, "*pfSqlType", pfSqlType);
        }
        if (pcbColDef != NULL) {
            API_TRACE(API_TR_UDWORD,"*pcbColDef",pcbColDef);
        }
        if (pibScale != NULL) {
            API_TRACE(API_TR_SWORD,"*pibScale",pibScale);
        }
        if (pfNullable != NULL) {
            API_TRACE(API_TR_SWORD,"*pfNullable",pfNullable);
        }

    }
    
    return (retcode);
} /* SQLDescribeCol */

.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
