/*
** PREPARE.C - This is the module containing the code for SQL for
** preparing SQL Commands and other functions prior to execution.
**
** (c) 1996 by Dirk Ohme - all rights reserved
*/

#ifdef OS2
#  include <os2.h>
#endif
#ifdef WIN
#  include <dos.h>
#endif

#include "cli.h"

/*---------------------------------------------------------------------------*/
/*      Allocate a SQL statement                                             */
/*---------------------------------------------------------------------------*/
RETCODE SQL_API SQLAllocStmt(
        LPDBC   lpdbc,
        HSTMT FAR *phstmt)
{
        /*
        ** check parameter
        */
        LogEntry( LOG_STATUS, "[SQLAllocStmt] lpdbc = $%08lX", lpdbc );
        if( NULL == lpdbc )
        {
                LogEntry( LOG_ERROR,      "[SQLAllocStmt] NULL == lpdbc" );
                LogEntry( LOG_RETURNCODE, "[SQLAllocStmt] SQL_INVALID_HANDLE" );
                return SQL_INVALID_HANDLE;
        }

        if( NULL == phstmt )
        {
                strcpy( lpdbc->szSqlState, "S1009" );
                lpdbc->pszSqlMsg = "[SQLAllocStmt] NULL == phstmt";
                LogEntry( LOG_ERROR, lpdbc->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLAllocStmt] SQL_ERROR (%s)",
                          lpdbc->szSqlState );
                return SQL_ERROR;
        }

        /*
        ** allocate memory
        */
        *phstmt = malloc( sizeof(STMT) );
        if( SQL_NULL_HSTMT == *phstmt )
        {
                strcpy( lpdbc->szSqlState, "S1001" );
                lpdbc->pszSqlMsg = "[SQLAllocStmt] memory allocation failure";
                LogEntry( LOG_ERROR, lpdbc->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLAllocStmt] SQL_ERROR (%s)",
                          lpdbc->szSqlState );
                return SQL_ERROR;
        }

        /*
        ** initialize memory
        */
        LogEntry( LOG_RETURNCODE, "[SQLAllocStmt] *phstmt = $%08lX", *phstmt );
        memset( *phstmt, 0, sizeof(STMT) );

        ((SQLHSTMT)(*phstmt))->pSqlDbc        = lpdbc;
        ((SQLHSTMT)(*phstmt))->szSqlState     = lpdbc->szSqlState;
#ifdef mSQL
        ((SQLHSTMT)(*phstmt))->szMsqlErrorMsg = &lpdbc->szMsqlErrorMsg[0];
#endif

#ifdef ORACLE
        /*
        ** get cursor (Oracle)
        */
        if( oopen( &(((SQLHSTMT)(*phstmt))->cda), &lpdbc->lda,
                   NULL, -1, -1, NULL, -1) )
        {
                strcpy( lpdbc->szSqlState, "S1001" );
                lpdbc->pszSqlMsg = "[SQLAllocStmt] can't open cursor";
                LogEntry( LOG_ERROR, lpdbc->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLAllocStmt] SQL_ERROR (%s)",
                          lpdbc->szSqlState );
                return SQL_ERROR;
        }
#endif

        /*
        ** increase number of open statements and set initial cursor name
        */
        lpdbc->ciActive++;
        sprintf( ((SQLHSTMT)(*phstmt))->szCursorName,
#ifdef mSQL
                 "SQLCUR_%05u_%03u",
                 lpdbc->hDbSocket,
#endif
#ifdef ORACLE
                 "SQLCUR_ORA_%03u",
#endif
                 lpdbc->ciActive
               );

        /*
        ** return success
        */
        LogEntry( LOG_RETURNCODE, "[SQLAllocStmt] SQL_SUCCESS" );
        return SQL_SUCCESS;
}


/*---------------------------------------------------------------------------*/
/*      Free a SQL Statement                                                 */
/*---------------------------------------------------------------------------*/
RETCODE SQL_API SQLFreeStmt(
        LPSTMT  lpstmt,
        UWORD   fOption)
{
        /*
        ** check parameter
        */
        LogEntry( LOG_STATUS, "[SQLFreeStmt] lpstmt  = $%08lX", lpstmt );
        LogEntry( LOG_STATUS, "              fOption = %s (%d)",
                  (SQL_CLOSE == fOption)          ? "SQL_CLOSE"
                  : (SQL_DROP == fOption)         ? "SQL_DROP"
                  : (SQL_UNBIND == fOption)       ? "SQL_UNBIND"
                  : (SQL_RESET_PARAMS == fOption) ? "SQL_RESET_PARAMS"
                  : "???",
                  lpstmt );
        if( NULL == lpstmt )
        {
                LogEntry( LOG_ERROR,      "[SQLFreeStmt] NULL == lpstmt" );
                LogEntry( LOG_RETURNCODE, "[SQLFreeStmt] SQL_INVALID_HANDLE" );
                return SQL_INVALID_HANDLE;
        }
        if( SQL_CLOSE        != fOption ||
            SQL_DROP         != fOption ||
            SQL_UNBIND       != fOption ||
            SQL_RESET_PARAMS != fOption )
        {
        }

        /*
        ** reset parameters
        */
        switch( fOption )
        {
                case SQL_CLOSE:
                case SQL_DROP:
                case SQL_UNBIND:
                case SQL_RESET_PARAMS:
                        strcpy( lpstmt->szSqlState, "00000" );
                        lpstmt->pszSqlMsg = NULL;
                        /* do nothing */
                        break;
                default:
                        strcpy( lpstmt->szSqlState, "S1092" );
                        lpstmt->pszSqlMsg =
                            "[SQLFreeStmt] invalid fOption specified";
                        LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                        LogEntry( LOG_RETURNCODE,
                                  "[SQLFreeStmt] SQL_ERROR (%s)",
                                  lpstmt->szSqlState );
                        return SQL_ERROR;
        } /* switch */

        /*
        ** unbind parameters
        */
        switch( fOption )
        {
                case SQL_CLOSE:
                case SQL_DROP:
                case SQL_UNBIND:
                        /* do nothing */
                default:
                        break;
        } /* switch */

        /*
        ** drop statement parameters
        */
        switch( fOption )
        {
                case SQL_CLOSE:
                case SQL_DROP:
                        /*---| free query |---*/
                        if( NULL != lpstmt->pszQuery )
                        {
                                free( lpstmt->pszQuery );
                                lpstmt->pszQuery = NULL;
                        }

                        /*---| free result handle |---*/
#ifdef mSQL
                        if( NULL != lpstmt->pMsqlResult )
                        {
                                msqlFreeResult( lpstmt->pMsqlResult );
                                lpstmt->pMsqlResult = NULL;
                        }
#endif
#ifdef ORACLE
                        oclose( &lpstmt->cda );
#endif

                        /*---| decrease number of active statements |---*/
                        lpstmt->pSqlDbc->ciActive--;
                default:
                        break;
        } /* switch */

        /*
        ** withdraw statement handle
        */
        if( SQL_CLOSE == fOption )
        {
                free( lpstmt );
        }

        /*
        ** return success
        */
        LogEntry( LOG_RETURNCODE, "[SQLFreeStmt] SQL_SUCCESS" );
        return SQL_SUCCESS;
}


/*---------------------------------------------------------------------------*/
/*      Perform a Prepare on the SQL statement                               */
/*---------------------------------------------------------------------------*/
RETCODE SQL_API SQLPrepare(
        LPSTMT  lpstmt,
        UCHAR FAR *szSqlStr,
        SDWORD  cbSqlStr)
{                                                /*--------------------------*/
#ifdef ORACLE
        int     ciParam;                         /* index parameter counter  */
        sb4     cbColSize;                       /* column size              */
#endif
        int     ciSrc;                           /* source index counter     */
        int     ciDst;                           /* destination index counter*/
        char    cStringDel;                      /* string delimiter         */
                                                 /*--------------------------*/
        /*
        ** check parameter
        */
        LogEntry( LOG_STATUS, "[SQLPrepare] lpstmt   = $%08lX", lpstmt );
        LogEntry( LOG_STATUS, "             szSqlStr = $%08lX", szSqlStr );
        LogEntry( LOG_STATUS, "             cbSqlStr =  %5d",   cbSqlStr );
        if( NULL == lpstmt )
        {
                LogEntry( LOG_ERROR,      "[SQLPrepare] NULL == lpstmt" );
                LogEntry( LOG_RETURNCODE, "[SQLPrepare] SQL_INVALID_HANDLE" );
                return SQL_INVALID_HANDLE;
        }
        if( NULL == szSqlStr )
        {
                strcpy( lpstmt->szSqlState, "S1009" );
                lpstmt->pszSqlMsg = "[SQLPrepare] NULL == szSqlStr";
                LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLPrepare] SQL_ERROR (%s)",
                          lpstmt->szSqlState );
                return SQL_ERROR;
        }

        /*
        ** check statement handle
        */
        if( NULL != lpstmt->pszQuery )
        {
                strcpy( lpstmt->szSqlState, "24000" );
                lpstmt->pszSqlMsg = "[SQLPrepare] statement already in use";
                LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLPrepare] SQL_ERROR (%s)",
                          lpstmt->szSqlState );
                return SQL_ERROR;
        }

        /*
        ** calculate memory needed to keep statment
        */
        ciSrc      = 0;
        ciDst      = 1;
        cStringDel = '\0';
        while( '\0' != szSqlStr[ciSrc] &&
               (SQL_NTS == cbSqlStr || ciSrc < cbSqlStr)
             )
        {
                /*---| check every character |---*/
                switch( szSqlStr[ciSrc] )
                {
                        case '?':               /* place holder? */
                                if( 0 == cStringDel )
                                {
                                        ciDst += 3;
                                }
                                ciDst++;
                                break;
#ifdef mSQL
                        case '%':               /* some other stuff? */
                                ciDst += 2;
                                break;
#endif
                        case '\'':              /* string delimiter? */
                                if( 0 == cStringDel )
                                        cStringDel = '\'';
                                else if( '\'' == cStringDel )
                                        cStringDel = 0;
                                ciDst++;
                                break;
                        case '"':               /* string delimiter? */
                                if( 0 == cStringDel )
                                        cStringDel = '"';
                                else if( '"' == cStringDel )
                                        cStringDel = 0;
                                ciDst++;
                                break;
                        default:                /* any other character ... */
                                ciDst++;
                }

                /*---| next character |---*/
                ciSrc++;
        }

        /*
        ** allocate memory for statement buffer
        */
        lpstmt->pszQuery = malloc( ciDst );
        if( NULL == lpstmt->pszQuery )
        {
                strcpy( lpstmt->szSqlState, "S1001" );
                lpstmt->pszSqlMsg = "[SQLPrepare] memory allocation error";
                LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLPrepare] SQL_ERROR (%s)",
                          lpstmt->szSqlState );
                return SQL_ERROR;
        }
        memset( lpstmt->pszQuery, 0, ciDst );

        /*
        ** prepare statement (mSQL, Oracle)
        **
        **  --> ignore (copy-only) all characters between string delimiters
        **      string delimiters are the characters " and '
        **  --> outside of strings, each % is expanded to %% and ? (place-
        **      holder for SQLSetParam()) is expanded to '%?' (mSQL)
        **  --> outside strings, each ? (placeholder for SQLSetParam())
        **      is expanded to ':pXX', where XX is a number (Oracle)
        **
        ** notes (mSQL):
        **    1) '%?' is translated by SQLSetParam() to its correct
        **       value(  %c  - char,  %d  - decimal, '%s' - strings ... )
        **    2) when parsing a prepared SQL statement character-wise,
        **       at occurrence of '%' the string pointer has to be
        **       increased two-times instead of one-time in order to
        **       parse in the right way!
        **
        ** notes (Oracle):
        **    1) there is no separate parsing in SQLSetParam() as
        **       needed for mSQL ...
        */
        ciSrc      =
        ciDst      = 0;
        cStringDel = '\0';
#ifdef ORACLE
        ciParam    = 1;
#endif
        while( '\0' != szSqlStr[ciSrc] &&
               (SQL_NTS == cbSqlStr || ciSrc < cbSqlStr)
             )
        {
                /*---| check every character |---*/
                switch( szSqlStr[ciSrc] )
                {
                        case '?':               /* place holder? */
                                if( 0 == cStringDel )
                                {
#ifdef mSQL
                                        lpstmt->pszQuery[ciDst++] = '\'';
                                        lpstmt->pszQuery[ciDst++] = '%';
                                        lpstmt->pszQuery[ciDst++] = '?';
#endif
#ifdef ORACLE
                                        lpstmt->pszQuery[ciDst++] = ':';
                                        lpstmt->pszQuery[ciDst++] = 'p';
                                        lpstmt->pszQuery[ciDst++] = '0' + (ciParam / 10);
                                        lpstmt->pszQuery[ciDst++] = '0' + (ciParam % 10);
                                        ciParam++;
#endif
                                }
                                else
                                {
                                        lpstmt->pszQuery[ciDst++] = '?';
                                }
                                break;
#ifdef mSQL
                        case '%':               /* some other stuff? */
                                lpstmt->pszQuery[ciDst++] = '%';
                                lpstmt->pszQuery[ciDst++] = '%';
                                break;
#endif
                        case '\'':              /* string delimiter? */
                                if( 0 == cStringDel )
                                        cStringDel = '\'';
                                else if( '\'' == cStringDel )
                                        cStringDel = 0;
                                lpstmt->pszQuery[ciDst++] = '\'';
                                break;
                        case '"':               /* string delimiter? */
                                if( 0 == cStringDel )
                                        cStringDel = '"';
                                else if( '"' == cStringDel )
                                        cStringDel = 0;
                                lpstmt->pszQuery[ciDst++] = '"';
                                break;
                        default:                /* any other character ... */
                                lpstmt->pszQuery[ciDst++] = szSqlStr[ciSrc];
                }

                /*---| next character |---*/
                ciSrc++;
        }
        lpstmt->pszQuery[ciDst] = '\0';

#ifdef ORACLE
        /*
        ** prepare statement (Oracle)
        */
        lpstmt->ciCol = 0;
        if( oparse(&lpstmt->cda, lpstmt->pszQuery, -1, 1, 2) )
        {
                strcpy( lpstmt->szSqlState, "S1001" );
                lpstmt->pszSqlMsg = "[SQLPrepare] preparation of statement failed";
                LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLPrepare] SQL_ERROR (%s)",
                          lpstmt->szSqlState );
                return SQL_ERROR;
        }

        /*
        ** get number of resulting columns (Oracle)
        ** (limit number of resulting columns to a maximum of 255)
        */
        lpstmt->cda.rc = 0;
        lpstmt->ciCol  = 1;
        while( 255 >= lpstmt->ciCol &&
               !odescr( &lpstmt->cda, lpstmt->ciCol, &cbColSize,
                        0, 0, 0, 0, 0, 0, 0) )
        {
                (lpstmt->ciCol)++;
        }
        (lpstmt->ciCol)--;
#endif

        /*
        ** return success
        */
        LogEntry( LOG_RETURNCODE, "[SQLPrepare] SQL_SUCCESS" );
        return SQL_SUCCESS;
}


/*---------------------------------------------------------------------------*/
/*      Set parameters on a statement handle                                 */
/*---------------------------------------------------------------------------*/
RETCODE SQL_API SQLSetParam(
        LPSTMT  lpstmt,
        UWORD   ipar,
        SWORD   fCType,
        SWORD   fSqlType,
        UDWORD  cbColDef,
        SWORD   ibScale,
        PTR     rgbValue,
        SDWORD FAR *pcbValue)
{                                                /*--------------------------*/
#ifdef mSQL
        int      ci;                             /* index counter            */
        char    *psz;                            /* string pointer           */
#endif
#ifdef ORACLE
        char     szBuffer[8];                    /* parameter buffer         */
        sword    fType;                          /* type of parameter        */
        sword    fScale;                         /* scaling of parameter     */
        sword    cbLen;                          /* length of data object    */
#endif
                                                 /*--------------------------*/
        /*
        ** check parameter
        */
        LogEntry( LOG_STATUS, "[SQLSetParam] lpstmt   = $%08lX", lpstmt   );
        LogEntry( LOG_STATUS, "              ipar     =  %5d",   ipar     );
        LogEntry( LOG_STATUS, "              fCType   =  %5d",   fCType   );
        LogEntry( LOG_STATUS, "              fSqlType =  %5d",   fSqlType );
        LogEntry( LOG_STATUS, "              cbColDef =  %5d",   cbColDef );
        LogEntry( LOG_STATUS, "              ibScale  =  %5d",   ibScale  );
        LogEntry( LOG_STATUS, "              rgbValue = $%08lX", rgbValue );
        LogEntry( LOG_STATUS, "              pcbValue = $%08lX", pcbValue );
        if( NULL == lpstmt )
        {
                LogEntry( LOG_ERROR,      "[SQLSetParam] NULL == lpstmt" );
                LogEntry( LOG_RETURNCODE, "[SQLSetParam] SQL_INVALID_HANDLE" );
                return SQL_INVALID_HANDLE;
        }
        if( NULL == lpstmt->pszQuery )
        {
                strcpy( lpstmt->szSqlState, "S1010" );
                lpstmt->pszSqlMsg = "[SQLSetParam] must be called after SQLPrepare()";
                LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLSetParam] SQL_ERROR (%s)",
                          lpstmt->szSqlState );
                return SQL_ERROR;
        }

#ifdef mSQL
        /*
        ** address parameter (mSQL)
        */
        psz = (0 >= (ci=ipar)) ? NULL : lpstmt->pszQuery;
        while( 0 < ci && '\0' != *psz )
        {
                /*---| check for parameter entry |---*/
                if( '%' == *psz )
                {
                        psz++;
                        switch( *psz )
                        {
                                case '%':                  /* character % */
                                        break;
                                case '?':                  /* free parameter */
                                case 'c':                  /* previous set   */
                                case 'd':                  /* parameter ...  */
                                case 'e':
                                case 'E':
                                case 'g':
                                case 'G':
                                case 'f':
                                case 'i':
                                case 'o':
                                case 's':
                                case 'u':
                                case 'x':
                                case 'X':
                                        ci--;
                                        if( 0 == ci )
                                        {
                                                psz -= 3;
                                        }
                                        break;
                                default:                   /* ??? */
                                        break;
                        }
                }

                /*---| next character |---*/
                psz++;
        }

        /*
        ** set new parameter (mSQL)
        */
        if( NULL == psz || 0 != ci )
        {
                strcpy( lpstmt->szSqlState, "S1093" );
                lpstmt->pszSqlMsg = "[SQLSetParam] invalid parameter number ipar";
                LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLSetParam] SQL_ERROR (%s)",
                          lpstmt->szSqlState );
                return SQL_ERROR;
        }
        if( NULL == rgbValue )
        {
                strcpy( lpstmt->szSqlState, "S1009" );
                lpstmt->pszSqlMsg = "[SQLSetParam] NULL == rgbValue";
                LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLSetParam] SQL_ERROR (%s)",
                          lpstmt->szSqlState );
                return SQL_ERROR;
        }
        /*---| set string delimiters if necessary |---*/
        if( SQL_CHAR == fSqlType )
        {
                psz[0] = '\'';
                psz[3] = '\'';
        }
        else
        {
                psz[0] = ' ';
                psz[3] = ' ';
        }
        /*---| set contents |---*/
        if( SQL_C_DEFAULT == fCType )
        {
                fCType = fSqlType;
        }
        switch( fCType )
        {
                case SQL_C_CHAR:
                case SQL_C_DBCHAR:
                        psz[2]                    = 's';
                        lpstmt->pParamVar[ipar-1] = rgbValue;
                        if( SQL_NTS != cbColDef )
                        {
                                ((char *) rgbValue)[cbColDef] = '\0';
                                lpstmt->cbParamLen[ipar-1]    = cbColDef;
                        }
                        else
                        {
                                lpstmt->cbParamLen[ipar-1] = strlen(rgbValue);
                        }
                        break;
                case SQL_C_INTEGER:
                        psz[2]                     = 'd';
                        lpstmt->pParamVar[ipar-1]  = rgbValue;
                        lpstmt->cbParamLen[ipar-1] = sizeof(int);
                        break;
                case SQL_C_REAL:
                        psz[2]                     = 'g';
                        lpstmt->pParamVar[ipar-1]  = rgbValue;
                        lpstmt->cbParamLen[ipar-1] = sizeof(float);
                        break;
                default:
                        strcpy( lpstmt->szSqlState, "S1004" );
                        lpstmt->pszSqlMsg = "[SQLSetParam] invalid C data type";
                        LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                        LogEntry( LOG_RETURNCODE,
                                  "[SQLSetParam] SQL_ERROR (%s)",
                                  lpstmt->szSqlState );
                        return SQL_ERROR;
        }
        /*---| set return variable |---*/
        lpstmt->pcbParam[ipar-1] = pcbValue;
#endif

#ifdef ORACLE
        /*
        ** check parameter number (Oracle)
        */
        if( 0 >= ipar )
        {
                strcpy( lpstmt->szSqlState, "S1093" );
                lpstmt->pszSqlMsg = "[SQLSetParam] invalid parameter number ipar";
                LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLSetParam] SQL_ERROR (%s)",
                          lpstmt->szSqlState );
                return SQL_ERROR;
        }

        /*
        ** set type and scaling of parameter (Oracle)
        */
        fScale = ibScale;
        if( SQL_C_DEFAULT == fCType )
        {
                fCType = fSqlType;
        }
        switch( fCType )
        {
                case SQL_C_CHAR:
                case SQL_C_DBCHAR:      fType = VARCHAR2_TYPE;
                                        cbLen = cbColDef;
                                        break;
                case SQL_C_INTEGER:     fType = INT_TYPE;
                                        cbLen = sizeof( int );
                                        break;
                case SQL_C_REAL:        fType = NUMBER_TYPE;
                                        cbLen = sizeof( float );
                                        break;
                default:
                        strcpy( lpstmt->szSqlState, "S1004" );
                        lpstmt->pszSqlMsg = "[SQLSetParam] invalid C data type";
                        LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                        LogEntry( LOG_RETURNCODE,
                                  "[SQLSetParam] SQL_ERROR (%s)",
                                  lpstmt->szSqlState );
                        return SQL_ERROR;
        }

        /*
        ** set parameter (Oracle)
        */
        if( NULL != pcbValue )
                *pcbValue = 0;
        sprintf( szBuffer, ":p%02u", ipar );
        if( obndrv( &lpstmt->cda, szBuffer, -1, rgbValue,
                    cbLen, fType, -1, (sb2 *) pcbValue, 0, -1, -1) )
        {
                strcpy( lpstmt->szSqlState, "07006" );
                lpstmt->pszSqlMsg = "[SQLSetParam] can't convert C to SQL data type";
                LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLSetParam] SQL_ERROR (%s)",
                          lpstmt->szSqlState );
                return SQL_ERROR;
        }
#endif

        /*
        ** return success
        */
        LogEntry( LOG_RETURNCODE, "[SQLSetParam] SQL_SUCCESS" );
        return SQL_SUCCESS;
}


/*---------------------------------------------------------------------------*/
/*      Returns the description of a parameter marker.                       */
/*---------------------------------------------------------------------------*/
RETCODE SQL_API SQLDescribeParam(
        LPSTMT  lpstmt,
        UWORD   ipar,
        SWORD FAR *pfSqlType,
        UDWORD FAR *pcbColDef,
        SWORD FAR *pibScale,
        SWORD FAR *pfNullable)
{
        return SQL_SUCCESS;
}


/*---------------------------------------------------------------------------*/
/*      Sets multiple values (arrays) for the set of parameter markers.      */
/*---------------------------------------------------------------------------*/
RETCODE SQL_API SQLParamOptions(
        LPSTMT  lpstmt,
        UDWORD  crow,
        UDWORD FAR *pirow)
{
        return SQL_SUCCESS;
}


/*---------------------------------------------------------------------------*/
/*      Returns the number of parameter markers.                             */
/*---------------------------------------------------------------------------*/
RETCODE SQL_API SQLNumParams(
        LPSTMT  lpstmt,
    SWORD FAR *pcpar)
{
        return SQL_SUCCESS;
}


/*---------------------------------------------------------------------------*/
/*      Sets options that control the behavior of cursors.                   */
/*---------------------------------------------------------------------------*/
RETCODE SQL_API SQLSetScrollOptions(
        LPSTMT  lpstmt,
        UWORD   fConcurrency,
        SDWORD  crowKeyset,
        UWORD   crowRowset)
{
        return SQL_SUCCESS;
}


/*---------------------------------------------------------------------------*/
/*      Set the cursor name on a statement handle                            */
/*---------------------------------------------------------------------------*/
RETCODE SQL_API SQLSetCursorName(
        LPSTMT  lpstmt,
        UCHAR FAR *szCursor,
        SWORD   cbCursor)
{
        /*
        ** check parameter
        */
        LogEntry( LOG_STATUS, "[SQLSetCursorName] lpstmt   = $%08lX", lpstmt   );
        LogEntry( LOG_STATUS, "                   szCursor = $%08lX", szCursor );
        LogEntry( LOG_STATUS, "                   cbCursor =  %5d",   cbCursor );
        if( NULL == lpstmt )
        {
                LogEntry( LOG_ERROR,      "[SQLSetCursorName] NULL == lpstmt" );
                LogEntry( LOG_RETURNCODE, "[SQLSetCursorName] SQL_INVALID_HANDLE" );
                return SQL_INVALID_HANDLE;
        }
        if( NULL == szCursor || 0 == isalpha(*szCursor) )
        {
                strcpy( lpstmt->szSqlState, "34000" );
                lpstmt->pszSqlMsg = "[SQLSetCursorName] invalid cursor name";
                LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLSetCursorName] SQL_ERROR (%s)",
                          lpstmt->szSqlState );
                return SQL_ERROR;
        }

        /*
        ** copy cursor name, set terminating NUL if necessary
        */
        if( SQL_NTS == cbCursor )
        {
                strncpy( lpstmt->szCursorName, szCursor, SQL_MAX_CURSOR_NAME );
        }
        else
        {
                strncpy( lpstmt->szCursorName, szCursor,
                         MIN(SQL_MAX_CURSOR_NAME - 1, cbCursor) );
                lpstmt->szCursorName[ MIN( SQL_MAX_CURSOR_NAME - 1,
                                           cbCursor) ] = '\0';
        }

        /*
        ** return success
        */
        LogEntry( LOG_RETURNCODE, "[SQLSetCursorName] SQL_SUCCESS" );
        return SQL_SUCCESS;
}


/*---------------------------------------------------------------------------*/
/*      Return the cursor name for a statement handle                        */
/*---------------------------------------------------------------------------*/
RETCODE SQL_API SQLGetCursorName(
        LPSTMT  lpstmt,
        UCHAR FAR *szCursor,
        SWORD   cbCursorMax,
        SWORD FAR *pcbCursor)
{                                                /*--------------------------*/
        int     ci;                              /* counter variable         */
                                                 /*--------------------------*/
        /*
        ** check parameter
        */
        LogEntry( LOG_STATUS, "[SQLGetCursorName] lpstmt      = $%08lX", lpstmt      );
        LogEntry( LOG_STATUS, "                   szCursor    = $%08lX", szCursor    );
        LogEntry( LOG_STATUS, "                   cbCursorMax =  %5d",   cbCursorMax );
        LogEntry( LOG_STATUS, "                   pcbCursor   = $%08lX", pcbCursor   );
        if( NULL == lpstmt )
        {
                LogEntry( LOG_ERROR,      "[SQLGetCursorName] NULL == lpstmt" );
                LogEntry( LOG_RETURNCODE, "[SQLGetCursorName] SQL_INVALID_HANDLE" );
                return SQL_INVALID_HANDLE;
        }
        if( NULL == szCursor )
        {
                strcpy( lpstmt->szSqlState, "S1090" );
                lpstmt->pszSqlMsg = "[SQLGetCursorName] NULL == szCursor";
                LogEntry( LOG_ERROR, lpstmt->pszSqlMsg );
                LogEntry( LOG_RETURNCODE, "[SQLGetCursorName] SQL_ERROR (%s)",
                          lpstmt->szSqlState );
                return SQL_ERROR;
        }

        /*
        ** copy cursor name
        */
        strncpy( szCursor, lpstmt->szCursorName, cbCursorMax );

        /*
        ** set length of transfered data
        */
        ci = strlen( lpstmt->szCursorName );
        if( NULL != pcbCursor )
        {
                *pcbCursor = MIN( ci, cbCursorMax );
        }
        if( cbCursorMax < ci )
        {
                strcpy( lpstmt->szSqlState, "01004" );
                lpstmt->pszSqlMsg = "[SQLGetCursorName] cursor name was truncated";
                LogEntry( LOG_WARNING, lpstmt->pszSqlMsg );
                LogEntry( LOG_RETURNCODE,
                          "[SQLGetCursorName] SQL_SUCCESS_WITH_INFO (%s)",
                          lpstmt->szSqlState );
                return SQL_SUCCESS_WITH_INFO;
        }

        /*
        ** return success
        */
        LogEntry( LOG_RETURNCODE, "[SQLGetCursorName] SQL_SUCCESS" );
        return SQL_SUCCESS;
}

/*===| end of file |=========================================================*/
