.ad 8
.bm 8
.fm 4
.bt $Copyright (c) 2000-2005 SAP AG$$Page %$
.tm 12
.hm 6
.hs 3
.tt 1 $SQL$Project Distributed Database System$VPA11PC$
.tt 2 $$$
.TT 3 $BurkhardD$LEVEL 1 FUNCTIONS P - Z$2001-07-10$
***********************************************************
.nf

.nf

.nf

    ========== licence begin  GPL
    Copyright (c) 2000-2005 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


.fo
Module  :
=========
.sp
Purpose :
.CM *-END-* purpose -------------------------------------
Define  :
#ifndef DEBUG
#line 21 "vpa11pc" 
#endif

#include "vpa00global.h"
#include "vpa20Desc.h"
#include "vpa50Env.h"
#include "vpa40DBC.h"
#include "vpa60Stmt.h"
#include "vpa30.h"
#include "vpa06.h"
#include "vpa09.h"
#include "SAPDB/SAPDBCommon/MemoryManagement/SAPDBMem_Alloca.h"

/* Factor for type SQL Datatypes numbers */
#define SQL_OUTPRM_FACTOR 100
.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-07-10
.sp
Release :  7.3    Date : 2001-07-10
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 72 "vpa11pc" 
#endif

VOID pa01trsqerr (tpa41ESQBlock * api_cb_ptr);

/* Prototypes from VPA10EC */
RETCODE pa10execute( tpa50Env  *env_block_ptr,
                     tpa40DBC  *dbc_block_ptr,
                     tpa60Stmt *stmt_block_ptr,
                     SQLHSTMT   hstmt);

/* http://pts:1080/webpts?wptsdetail=yes&ErrorType=1&ErrorID=1130120 */
const char * pa12_getTablePrefix (tpa40DBC *dbc_block_ptr);

extern SDWORD pa07blockmodus;

#ifndef SAPDB_FAST
#ifndef _UNICODE_ODBC
UCHAR *PA11_FN_SQLPARAMDATA = { (UCHAR*) "SQLParamData" };
UCHAR *PA11_FN_SQLPUTDATA = { (UCHAR*) "SQLPutData" };
UCHAR *PA11_FN_SQLSPECIALCOLUMNS = { (UCHAR*) "SQLSpecialColumns" };
UCHAR *PA11_FN_SQLSTATISTICS = { (UCHAR*) "SQLStatistics" };
UCHAR *PA11_FN_SQLTABLES = { (UCHAR*) "SQLTables" };
#else
extern UCHAR *PA11_FN_SQLPARAMDATA;
extern UCHAR *PA11_FN_SQLPUTDATA;
extern UCHAR *PA11_FN_SQLSPECIALCOLUMNS;
extern UCHAR *PA11_FN_SQLSTATISTICS;
extern UCHAR *PA11_FN_SQLTABLES;
#endif
#endif

/* ------------------------------------------------------------------------ */
/* SQLTables */
/* API_TABLE_SCAN */
#ifndef _UNICODE_ODBC
const char *PA11SELECTTABLESCAN = \
"SELECT TABLE_QUALIFIER, TABLE_OWNER, TABLE_NAME, TABLE_TYPE, REMARKS \
FROM %sTABLES ";

const char *PA11SELECTTABLESWHERE   = "WHERE ";
const char *PA11SELECTTABLESAND     = "AND ";
const char *PA11SELECTTABLESOWNER   = "TABLE_OWNER LIKE '%'=.*S' ESCAPE '\\' ";
const char *PA11SELECTTABLESTABNAME = "TABLE_NAME LIKE '%'=.*S' ESCAPE '\\' ";
const char *PA11SELECTTABLESTYPE    = "TABLE_TYPE IN (%'=.*S) ";
const char *PA11SELECTTABLESORDERBY = "ORDER BY 4, 2, 3 ";

/* API_QUALIFIER_SCAN */
const char *PA11SELECTQUALIFIERSCAN = \
"SELECT NULL TABLE_QUALIFIER, NULL TABLE_OWNER, NULL TABLE_NAME, \
NULL TABLE_TYPE, NULL REMARKS FROM "SYSDBA".DUAL WHERE NULL <> NULL";

/* API_TYPE_SCAN */
const char *PA11SELECTTABLETYPE = \
"SELECT NULL TABLE_QUALIFIER, NULL TABLE_OWNER, NULL TABLE_NAME, \
'ALIAS' TABLE_TYPE, NULL REMARKS FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'RESULT', NULL FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'SNAPSHOT', NULL FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'SYSTEM', NULL FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'SYSTEM TABLE', NULL FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'TABLE', NULL FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'UNLOADED', NULL FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'VIEW', NULL FROM DUAL \
ORDER BY 4";

/* API_OWNER_SCAN */
const char *PA11SELECTOWNERSCAN = \
"SELECT NULL TABLE_QUALIFIER, USERNAME TABLE_OWNER, NULL TABLE_NAME, \ 
NULL TABLE_TYPE, NULL REMARKS FROM "SYSDOMAIN".USERS ORDER BY 2 ";

/* in ODBC version 3.0 the fields TABLE_QUALIFIER and TABLE_OWNER
 * are renamed */
const char *PA11SELECTTABLESCAN_OV3 = \
"SELECT TABLE_QUALIFIER TABLE_CAT, TABLE_OWNER TABLE_SCHEM, TABLE_NAME, \
TABLE_TYPE, REMARKS \
FROM %sTABLES ";

/* API_QUALIFIER_SCAN */
const char *PA11SELECTQUALIFIERSCAN_OV3 = \
"SELECT NULL TABLE_CAT, NULL TABLE_SCHEM, NULL TABLE_NAME, \
NULL TABLE_TYPE, NULL REMARKS FROM "SYSDBA".DUAL WHERE NULL <> NULL";

/* API_TYPE_SCAN */
const char *PA11SELECTTABLETYPE_OV3 = \
"SELECT NULL TABLE_CAT, NULL TABLE_SCHEM, NULL TABLE_NAME, \
'ALIAS' TABLE_TYPE, NULL REMARKS FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'RESULT', NULL FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'SNAPSHOT', NULL FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'SYSTEM', NULL FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'SYSTEM TABLE', NULL FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'TABLE', NULL FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'UNLOADED', NULL FROM DUAL \
UNION ALL SELECT NULL, NULL, NULL, 'VIEW', NULL FROM DUAL \
ORDER BY 4";

/* API_OWNER_SCAN */
const char *PA11SELECTOWNERSCAN_OV3 = \
"SELECT NULL TABLE_CAT, USERNAME TABLE_SCHEM, \
NULL TABLE_NAME, \ 
NULL TABLE_TYPE, NULL REMARKS FROM "SYSDOMAIN".USERS ORDER BY 2 ";

/* ------------------------------------------------------------------------ */
/* SQLStatistics */
/* http://pts:1080/webpts?wptsdetail=yes&ErrorType=0&ErrorID=1132620
   COLLATION or ASC_OR_DESC has to be a CHAR ASCII column */
const char *PA11SELECTTABLESTATQUICK = \
"SELECT TABLE_QUALIFIER, TABLE_OWNER, TABLE_NAME, NUM(NULL) NON_UNIQUE, \
NULL INDEX_QUALIFIER, NULL INDEX_NAME, 0 TYPE, NULL SEQ_IN_INDEX, \
NULL COLUMN_NAME, ASCII(NULL) COLLATION, CARDINALITY, PAGES, FILTER_CONDITION \ 
FROM %sINDEXES WHERE TABLE_OWNER='%%'=.*S' AND TABLE_NAME='%%'=.*S' \
AND INDEX_NAME = 'SYSPRIMARYKEYINDEX' AND SEQ_IN_INDEX=1 ";

const char *PA11SELECTINDEXSTATQUICK = \
"UNION ALL SELECT TABLE_QUALIFIER, TABLE_OWNER, TABLE_NAME, NON_UNIQUE, \
INDEX_QUALIFIER, INDEX_NAME, TYPE, SEQ_IN_INDEX, COLUMN_NAME, ASCII(COLLATION), \
CARDINALITY, PAGES, FILTER_CONDITION FROM %sINDEXES \ 
WHERE TABLE_OWNER='%%'=.*S' AND TABLE_NAME='%%'=.*S' AND COLUMN_NAME <> 'SYSKEY' ";

const char *PA118015TABLESTATQUICK = \
"SELECT NULL TABLE_QUALIFIER, '%'=.*S' TABLE_OWNER, '%'=.*S' TABLE_NAME, \
NUM(NULL) NON_UNIQUE, NULL INDEX_QUALIFIER, NULL INDEX_NAME, 0 TYPE, \
NULL SEQ_IN_INDEX, NULL COLUMN_NAME, ASCII(NULL) COLLATION, \
NUM(NULL) CARDINALITY, NUM(NULL) PAGES, NULL FILTER_CONDITION \
FROM "SYSDBA".DUAL ";

const char *PA11SELECTTABLESTATENSURE = \
"SELECT NULL TABLE_QUALIFIER, OWNER TABLE_OWNER, TABLENAME TABLE_NAME, \
NUM(NULL) NON_UNIQUE, NULL INDEX_QUALIFIER, NULL INDEX_NAME, 0 TYPE, \
NULL SEQ_IN_INDEX, NULL COLUMN_NAME, ASCII(NULL) COLLATION, ROWS CARDINALITY, \
PAGECOUNT PAGES, NULL FILTER_CONDITION FROM %sTABLESTAT \
WHERE OWNER = '%%'=.*S' AND TABLENAME = '%%'=.*S' ";

const char *PA11SELECTINDEXSTATESURE = \
"UNION SELECT TABLE_QUALIFIER, TABLE_OWNER, TABLE_NAME, NON_UNIQUE, \
INDEX_QUALIFIER, INDEX_NAME, TYPE, SEQ_IN_INDEX, COLUMN_NAME, ASCII(COLLATION), \
ROWS, PAGECOUNT, NULL FROM %sINDEXES, %sINDEXSTAT \
WHERE TABLE_OWNER = '%%'=.*S' AND OWNER = TABLE_OWNER \
AND TABLE_NAME = '%%'=.*S' AND TABLENAME = TABLE_NAME \
AND (INDEXNAME = INDEX_NAME OR COLUMNNAME = INDEX_NAME) ";

const char *PA11SELECTPRIMARYKEYSTATENSURE = \
"UNION SELECT TABLE_QUALIFIER, TABLE_OWNER, TABLE_NAME, 0, NULL, INDEX_NAME, \
TYPE, SEQ_IN_INDEX, COLUMN_NAME, ASCII(COLLATION), ROWS, PAGECOUNT, NULL \
FROM %sINDEXES, %sTABLESTAT \
WHERE TABLE_OWNER = '%%'=.*S' AND OWNER = TABLE_OWNER \
AND TABLE_NAME = '%%'=.*S' AND TABLENAME = TABLE_NAME \
AND INDEX_NAME = 'SYSPRIMARYKEYINDEX' AND COLUMN_NAME <> 'SYSKEY' ";

/* the same for ODBC version 3.x. Only some column names changed */
const char *PA11SELECTTABLESTATQUICK_OV3 = \
"SELECT TABLE_QUALIFIER TABLE_CAT, TABLE_OWNER TABLE_SCHEM, \
TABLE_NAME, NUM(NULL) NON_UNIQUE, \
NULL INDEX_QUALIFIER, NULL INDEX_NAME, 0 TYPE, NULL ORDINAL_POSITION, \
NULL COLUMN_NAME, NULL ASC_OR_DESC, CARDINALITY, PAGES, FILTER_CONDITION \ 
FROM %sINDEXES WHERE TABLE_OWNER='%%'=.*S' AND TABLE_NAME='%%'=.*S' \
AND INDEX_NAME = 'SYSPRIMARYKEYINDEX' AND SEQ_IN_INDEX=1 ";

const char *PA11SELECTINDEXSTATQUICK_OV3 = \
"UNION ALL SELECT TABLE_QUALIFIER TABLE_CAT, TABLE_OWNER TABLE_SCHEM, \
TABLE_NAME, NON_UNIQUE, INDEX_QUALIFIER, INDEX_NAME, TYPE, SEQ_IN_INDEX ORDINAL_POSITION, \
COLUMN_NAME, ASCII(COLLATION) ASC_OR_DESC, CARDINALITY, PAGES, FILTER_CONDITION \
FROM %sINDEXES \ 
WHERE TABLE_OWNER='%%'=.*S' AND TABLE_NAME='%%'=.*S' AND COLUMN_NAME <> 'SYSKEY' ";

const char *PA118015TABLESTATQUICK_OV3 = \
"SELECT NULL TABLE_CAT, '%'=.*S' TABLE_SCHEM, '%'=.*S' TABLE_NAME, \
NUM(NULL) NON_UNIQUE, NULL INDEX_QUALIFIER, NULL INDEX_NAME, 0 TYPE, \
NULL ORDINAL_POSITION, NULL COLUMN_NAME, NULL ASC_OR_DESC, \
NUM(NULL) CARDINALITY, NUM(NULL) PAGES, NULL FILTER_CONDITION \
FROM "SYSDBA".DUAL ";

const char *PA11SELECTTABLESTATENSURE_OV3 = \
"SELECT NULL TABLE_CAT, OWNER TABLE_SCHEM, TABLENAME TABLE_NAME, \
NUM(NULL) NON_UNIQUE, NULL INDEX_QUALIFIER, NULL INDEX_NAME, 0 TYPE, \
NULL ORDINAL_POSITION, NULL COLUMN_NAME, NULL ASC_OR_DESC, ROWS CARDINALITY, \
PAGECOUNT PAGES, NULL FILTER_CONDITION FROM %sTABLESTAT \
WHERE OWNER = '%%'=.*S' AND TABLENAME = '%%'=.*S' ";

const char *PA11SELECTINDEXSTATESURE_OV3 = \
"UNION SELECT TABLE_QUALIFIER TABLE_CAT, TABLE_OWNER TABLE_SCHEM, \
TABLE_NAME, NON_UNIQUE, INDEX_QUALIFIER, INDEX_NAME, TYPE, \
SEQ_IN_INDEX ORDINAL_POSITION, COLUMN_NAME, ASCII(COLLATION) ASC_OR_DESC, \
ROWS, PAGECOUNT, NULL FROM %sINDEXES, %sINDEXSTAT \
WHERE TABLE_OWNER = '%%'=.*S' AND OWNER = TABLE_OWNER \
AND TABLE_NAME = '%%'=.*S' AND TABLENAME = TABLE_NAME \
AND (INDEXNAME = INDEX_NAME OR COLUMNNAME = INDEX_NAME) ";

const char *PA11SELECTPRIMARYKEYSTATENSURE_OV3 = \
"UNION SELECT TABLE_QUALIFIER TABLE_CAT, TABLE_OWNER TABLE_SCHEM, \
TABLE_NAME, 0, NULL, INDEX_NAME, TYPE, SEQ_IN_INDEX ORDINAL_POSITION, \
COLUMN_NAME, ASCII(COLLATION) ASC_OR_DESC, ROWS, PAGECOUNT, NULL \
FROM %sINDEXES, %sTABLESTAT \
WHERE TABLE_OWNER = '%%'=.*S' AND OWNER = TABLE_OWNER \
AND TABLE_NAME = '%%'=.*S' AND TABLENAME = TABLE_NAME \
AND INDEX_NAME = 'SYSPRIMARYKEYINDEX' AND COLUMN_NAME <> 'SYSKEY' ";

/* ------------------------------------------------------------------------ */
/* SQLSpecialColumns SQL-Statements */
const char *PA11SELECTSPECCOLEMPTY = \ 
"SELECT NULL SCOPE, NULL COLUMN_NAME, NULL DATA_TYPE, NULL TYPE_NAME, \
NULL PRECISION, NULL \"LENGTH\", NULL SCALE, NULL PSEUDO_COLUMN \
FROM "SYSDBA".DUAL WHERE NULL <> NULL";

const char *PA11SELECTSPECCOLSYSKEY = \
"SELECT NUM(1) SCOPE, 'SYSKEY' COLUMN_NAME, 99 DATA_TYPE, \
'CHAR' TYPE_NAME, NUM(8) PRECISION, NUM(8) \"LENGTH\", \
NULL SCALE, NUM(2) PSEUDO_COLUMN, 'BYTE' CODETYPE FROM "SYSDBA".DUAL %s";

const char *PA11SELECTSPECCOLWHERE = "WHERE NULL<>NULL ";

const char *PA11SELECTSPECCOLORDERBY = "ORDER BY 1 ";

const char *PA11SELECTSPECCOLPRMKEY = \
"SELECT NUM(1) SCOPE, COLUMN_NAME, DATA_TYPE, TYPE_NAME, PRECISION, \ 
LENGTH, SCALE, NUM(2) PSEUDO_COLUMN, CODETYPE FROM %sCOLUMNS \
WHERE KEY_SEQ IS NOT NULL AND TABLE_OWNER = '%%'=.*S' AND TABLE_NAME = '%%'=.*S' ";

const char *PA11SELECTSPECCOLEXSTAB = "EXISTS TABLE \"%'=.*S\".\"%'=.*S\" ";

/* the same for ODBC 3.x with some column names changed (its so boring) */
const char *PA11SELECTSPECCOLEMPTY_OV3 = \ 
"SELECT NULL SCOPE, NULL COLUMN_NAME, NULL DATA_TYPE, NULL TYPE_NAME, \
NULL COLUMN_SIZE, NULL BUFFER_LENGTH, NULL DECIMAL_DIGITS, NULL PSEUDO_COLUMN \
FROM "SYSDBA".DUAL WHERE NULL <> NULL";

const char *PA11SELECTSPECCOLSYSKEY_OV3 =  
"SELECT NUM(1) SCOPE, 'SYSKEY' COLUMN_NAME, 99 DATA_TYPE, \
'CHAR' TYPE_NAME, NUM(8) COLUMN_SIZE, NUM(8) BUFFER_LENGTH, \
NULL DECIMAL_DIGITS, NUM(2) PSEUDO_COLUMN, 'BYTE' CODETYPE \
FROM "SYSDBA".DUAL %s";

const char *PA11SELECTSPECCOLPRMKEY_OV3 = 
"SELECT NUM(1) SCOPE, COLUMN_NAME, DATA_TYPE, TYPE_NAME, \
PRECISION COLUMN_SIZE, LENGTH BUFFER_LENGTH, SCALE DECIMAL_DIGITS, \
NUM(2) PSEUDO_COLUMN, CODETYPE \
FROM %sCOLUMNS \
WHERE KEY_SEQ IS NOT NULL AND TABLE_OWNER = '%%'=.*S' AND TABLE_NAME = '%%'=.*S' ";

#else     /* _UNICODE_ODBC */

extern const char *PA11SELECTTABLESCAN;
extern const char *PA11SELECTTABLESWHERE;
extern const char *PA11SELECTTABLESAND;
extern const char *PA11SELECTTABLESOWNER;
extern const char *PA11SELECTTABLESTABNAME;
extern const char *PA11SELECTTABLESTYPE;
extern const char *PA11SELECTTABLESORDERBY;
extern const char *PA11SELECTQUALIFIERSCAN;
extern const char *PA11SELECTTABLETYPE;
extern const char *PA11SELECTOWNERSCAN;
extern const char *PA11SELECTTABLESCAN_OV3;
extern const char *PA11SELECTQUALIFIERSCAN_OV3;
extern const char *PA11SELECTTABLETYPE_OV3;
extern const char *PA11SELECTOWNERSCAN_OV3;
extern const char *PA11SELECTTABLESTATQUICK;
extern const char *PA11SELECTINDEXSTATQUICK;
extern const char *PA118015TABLESTATQUICK;
extern const char *PA11SELECTTABLESTATENSURE;
extern const char *PA11SELECTINDEXSTATESURE;
extern const char *PA11SELECTPRIMARYKEYSTATENSURE;
extern const char *PA11SELECTTABLESTATQUICK_OV3;
extern const char *PA11SELECTINDEXSTATQUICK_OV3;
extern const char *PA118015TABLESTATQUICK_OV3;
extern const char *PA11SELECTTABLESTATENSURE_OV3;
extern const char *PA11SELECTINDEXSTATESURE_OV3;
extern const char *PA11SELECTPRIMARYKEYSTATENSURE_OV3;
extern const char *PA11SELECTSPECCOLEMPTY;
extern const char *PA11SELECTSPECCOLSYSKEY;
extern const char *PA11SELECTSPECCOLWHERE;
extern const char *PA11SELECTSPECCOLORDERBY;
extern const char *PA11SELECTSPECCOLPRMKEY;
extern const char *PA11SELECTSPECCOLEXSTAB;
extern const char *PA11SELECTSPECCOLEMPTY_OV3;
extern const char *PA11SELECTSPECCOLSYSKEY_OV3;
extern const char *PA11SELECTSPECCOLPRMKEY_OV3;
#endif      /* _UNICODE_ODBC */

#define PA11ORDER " ORDER BY  4,7,5,6,8"
#define PA11SPECCOLEMPTY	(0)
#define PA11SPECCOLSYSKEY	(1)
#define PA11SPECCOLPRMKEY	(2)
/* ------------------------------------------------------------------------ */

#ifndef _UNICODE_ODBC
ODBC_PROC(SQLParamData,
          (SQLHSTMT     hstmt,
           SQLPOINTER  *prgbValue),
          (hstmt, prgbValue))
{
    RETCODE          retcode;
    API_RETCODE      api_retcode;
    SQLHDBC          hdbc;
    UWORD            state;
    tpa40DBC        *dbc_block_ptr;
    SQLHENV          henv;
    tpa62DBCSpecial *dbc_special_ptr;
    tpa50Env        *env_block_ptr;
    tpa60Stmt       *stmt_block_ptr;
    SWORD            number_parms;
    SWORD            last_param;
    tpa21DescRecord *impl_rec_ptr;
    
    API_TRACE(API_TR_ENTRY, PA11_FN_SQLPARAMDATA, 0);
    API_TRACE(API_TR_HANDLE,"hstmt",&hstmt);
    API_TRACE(API_TR_PTR,"prgbValue",&prgbValue);

    retcode = SQL_SUCCESS;
    api_retcode = apmstfc(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, 
                          SQL_API_SQLPARAMDATA);
    if (api_retcode != API_OK) {
        retcode = pa06stfcerror(api_retcode, hstmt);
        goto no_lock_exit;
    }
    if (pa60VerifyStmt( hstmt ) != API_OK) { /* hstmt valid? */
        retcode = SQL_INVALID_HANDLE;
        goto no_lock_exit;
    }; /* if */
    apmlocp(&hstmt, &stmt_block_ptr, &hdbc, &dbc_block_ptr, 
            &henv, &env_block_ptr);
    /* !!! do not call pa60ResetError, because errors from SQLPutData
     * are delayed until SQLParamData (see dbc_special -> last_error */
    if (stmt_block_ptr -> setPosNeedData) {
        /* SQL_NEED_DATA came from SQLSetPos so we have to use
         * the hstmt_setpos which is the statement for the positioned
         * update or insert statement. PTS 1104697
         */
        if (!pa60VerifyStmt( stmt_block_ptr->hstmt_setpos )) {
            /* general error */
            retcode = SQL_ERROR;
            pa60PutError( hstmt, API_ODBC_S1000, NULL );
            goto lock_1_exit;
        } else {
            stmt_block_ptr = (tpa60Stmt*) stmt_block_ptr->hstmt_setpos;
        };
    }; /* if */
    state = stmt_block_ptr->state;
    dbc_special_ptr = &stmt_block_ptr -> dbc_special;
    API_TRACE(API_TR_SWORD, "last_error", &dbc_special_ptr -> last_error);
    if (dbc_special_ptr -> last_error == API_TRUE) {
        retcode = SQL_ERROR;
        goto lock_1_exit;
    }    
    if (stmt_block_ptr -> need_data) {
        retcode = SQL_ERROR;
        /* function sequence error */
        pa60PutError( hstmt, API_ODBC_S1010, NULL);
        goto lock_1_exit;
    }; /* if */
    
    number_parms = stmt_block_ptr -> number_parms;
    if (number_parms > 0) {      
        last_param = stmt_block_ptr -> next_param;
        if (state == API_STMT_PREPARED) {
            /* search non long columns */
            pa60Param( stmt_block_ptr->apdPtr,
                       &stmt_block_ptr->ipd,
                       stmt_block_ptr,
                       prgbValue,
                       TRUE );
            if (stmt_block_ptr -> next_param == -1)
                /* long columns */
                pa60Param( stmt_block_ptr->apdPtr,
                           &stmt_block_ptr->ipd,
                           stmt_block_ptr,
                           prgbValue,
                           FALSE );
        }
        else /* only long columns */
            pa60Param( stmt_block_ptr->apdPtr,
                       &stmt_block_ptr->ipd,
                       stmt_block_ptr,
                       prgbValue,
                       FALSE );
        if (stmt_block_ptr -> next_param != -1) {
            retcode = SQL_NEED_DATA;
            stmt_block_ptr -> need_data = TRUE;
        }	 
        else {
            if (state == API_STMT_PREPARED) {
                sqldatype * sqlda_ptr;  
                API_HANDLE sqlda_handle;
                sqlda_handle = stmt_block_ptr -> input_sqlda_handle;
                sqlda_ptr = (sqldatype*) sqlda_handle;
                API_ASSERT_PTR(sqlda_ptr);
                stmt_block_ptr->input_sqlda_ptr = sqlda_ptr;
                retcode = pa10execute( env_block_ptr,
                                       dbc_block_ptr,
                                       stmt_block_ptr,
                                       hstmt);	    
            }	
            if (stmt_block_ptr -> number_rows != 0) {
                api_retcode = pa20Move( stmt_block_ptr->apdPtr,
                                        &stmt_block_ptr->ipd,
                                        number_parms,
                                        dbc_special_ptr );
                if (api_retcode != API_OK) 
                    retcode = pa60PutESQError( hstmt, api_retcode );
            }
        }
        if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
            if (last_param >= 0 && state == API_STMT_EXECUTED) {
                impl_rec_ptr = pa20GetRecord( &stmt_block_ptr->ipd,
                                              (UWORD) (last_param+1) );
                API_ASSERT_PTR( impl_rec_ptr );
                if ( apgislong( impl_rec_ptr->type)) {
                    UCHAR * ptr;
                    sqldatype * sqlda_ptr;  
                    API_HANDLE sqlda_handle;
                    sqlda_handle = stmt_block_ptr -> input_sqlda_handle;
                    sqlda_ptr = (sqldatype*) sqlda_handle;
                    API_ASSERT_PTR(sqlda_ptr);
                    stmt_block_ptr->input_sqlda_ptr = sqlda_ptr;
                    pa21GetLongAddr( &ptr, impl_rec_ptr );
                    apgsvstrl( ptr, 0);
                    stmt_block_ptr -> next_param = last_param;
                    sqlda_handle = stmt_block_ptr -> input_sqlda_handle;
                    sqlda_ptr = (sqldatype*) sqlda_handle;
                    API_ASSERT_PTR(sqlda_ptr);
                    stmt_block_ptr->input_sqlda_ptr = sqlda_ptr;	 
                    api_retcode = apeput1l( &dbc_block_ptr->esqblk,
                                            dbc_block_ptr, 
                                            stmt_block_ptr );
                    /* return error if last long part went wrong
                       http://pts:1080/webpts?wptsdetail=yes&ErrorType=0&ErrorID=1131148 */
                    if ( dbc_block_ptr->esqblk.esq_sql_code != PA_OK) {
                      retcode = SQL_ERROR;
                      pa60PutError (hstmt, API_ODBC_S1000, &dbc_block_ptr->esqblk);
                    }
                    pa30SubtransEnd(&dbc_block_ptr->esqblk, dbc_block_ptr);
                }
            }
            if (pa40UseOldAutocommit( dbc_block_ptr )) {
                if (dbc_block_ptr->set_autocommit_flag)
                    api_retcode = pa30commit( &dbc_block_ptr->esqblk,
                                              dbc_block_ptr);
            }; /* if */
            /* reset the parameter for next execution */
            stmt_block_ptr -> next_param = -1;
	 
            stmt_block_ptr -> state = API_STMT_EXECUTED;
            pa20Unset( &stmt_block_ptr->ipd, number_parms);
        }
    }
    /* if SQLParamData finishes successful, an error from SQLPutData has to be removed
       http://pts:1080/webpts?wptsdetail=yes&ErrorType=0&ErrorID=1138262 */
    if (retcode == SQL_SUCCESS)
      pa60ResetError (hstmt);
lock_1_exit:

no_lock_exit:
    API_TRACE(API_TR_EXIT, PA11_FN_SQLPARAMDATA, 0);
    API_TRACE(API_TR_PTR, "*prgbValue", prgbValue);
    API_TRACE(API_TR_RETCODE, "retcode",&retcode);
    return(retcode);
} /* SQLParamData */

ODBC_PROC( SQLPutData,
           (SQLHSTMT     hstmt,
            SQLPOINTER   rgbValue,
            SQLLEN       cbValue),
           (hstmt, rgbValue, cbValue))
{
    RETCODE          retcode;
    SQLHDBC          hdbc;
    tpa40DBC        *dbc_block_ptr;
    SQLHENV          henv;
    tpa50Env        *env_block_ptr;
    tpa60Stmt       *stmt_block_ptr;
    tpa62DBCSpecial *dbc_special_ptr;
    UWORD            number_parms;
    SWORD            param;
    API_RETCODE      api_retcode, conv_retcode;
    sqldatype       *sqlda_ptr;  
    API_HANDLE       sqlda_handle;
    PTR              rgbValueBlock;
    SQLLEN           cbValueBlock;
    tpa21DescRecord *appl_rec_ptr;
    tpa21DescRecord *impl_rec_ptr;    

    API_TRACE(API_TR_ENTRY, PA11_FN_SQLPUTDATA, 0);
    API_TRACE(API_TR_HANDLE,"hstmt",&hstmt);
    API_TRACE(API_TR_PTR,"rgbValue",&rgbValue);
    API_TRACE(API_TR_SDWORD,"cbValue",&cbValue);

    api_retcode = apmstfc(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, 
                          SQL_API_SQLPUTDATA);
    if (api_retcode != API_OK) {
        retcode = pa06stfcerror(api_retcode, hstmt);
    }
    else {
        retcode = SQL_SUCCESS;
        if (cbValue < 0 && cbValue != SQL_NTS && cbValue != SQL_NULL_DATA) {
            retcode = SQL_ERROR;
            pa60PutError( hstmt, API_ODBC_S1090, NULL);
            goto exit_func;
        }
        if (!pa60VerifyStmt( hstmt )) {
            retcode = SQL_INVALID_HANDLE;
            goto exit_func;
        };
        apmlocp(&hstmt, &stmt_block_ptr, &hdbc, &dbc_block_ptr, 
                &henv, &env_block_ptr);
        if (stmt_block_ptr -> setPosNeedData) {
            /* SQL_NEED_DATA came from SQLSetPos so we have to use
             * the hstmt_setpos which is the statement for the positioned
             * update or insert statement. PTS 1104697
             */
            if (!pa60VerifyStmt( stmt_block_ptr->hstmt_setpos )) {
                /* general error */
                retcode = SQL_ERROR;
                pa60PutError( hstmt, API_ODBC_S1000, NULL );
                goto exit_func;
            } else {
                stmt_block_ptr = (tpa60Stmt*) stmt_block_ptr->hstmt_setpos;
            };
        }; /* if */
    
        dbc_special_ptr = &stmt_block_ptr -> dbc_special;
      
        param = stmt_block_ptr -> next_param;
        API_TRACE(API_TR_SWORD,"param",&param);      
        if (param == -1) {
            retcode = SQL_ERROR;
            pa60PutError( hstmt, API_ODBC_S1010, NULL);
            goto exit_func;
        }

        number_parms = stmt_block_ptr -> number_parms;
        API_TRACE(API_TR_UWORD,"number_parms",&number_parms);      
      
        cbValueBlock = (cbValue == SQL_NTS) ? API_STRLEN(rgbValue) : cbValue;
        rgbValueBlock = rgbValue;
        API_TRACE(API_TR_SDWORD, "cbValueBlock", &cbValueBlock);      
        if (number_parms > 0) {
            SQLLEN *pcbV;
            UCHAR *rgbV;	    

            appl_rec_ptr = pa20GetRecord( stmt_block_ptr->apdPtr,
                                          (UWORD) (param+1) );
            impl_rec_ptr = pa20GetRecord( &stmt_block_ptr->ipd,
                                          (UWORD) (param+1) );
            API_ASSERT_PTR( appl_rec_ptr );
            API_ASSERT_PTR( impl_rec_ptr );
            
            rgbV = appl_rec_ptr -> dataPtr;
            pcbV = appl_rec_ptr -> octetLengthPtr;
            for(;;) {
                SQLLEN cbBlockSize;
                if (param != -1) {
                    appl_rec_ptr -> dataPtr = rgbValueBlock;
                    /* http://pts:1080/webpts?wptsdetail=yes&ErrorType=0&ErrorID=1122725 */
                    if (cbValue == SQL_NULL_DATA)
                        appl_rec_ptr -> indicatorPtr = &cbValueBlock;
                    appl_rec_ptr -> octetLengthPtr = &cbValueBlock;
                    if (apgislong( impl_rec_ptr -> type)) {
                        if ( cbValueBlock > (SDWORD) dbc_block_ptr -> blocksize-2) {
                            /* http://pts:1080/webpts?wptsdetail=yes&ErrorType=0&ErrorID=1138262 */
                            cbBlockSize = dbc_block_ptr -> blocksize-2;
                            appl_rec_ptr -> octetLengthPtr = &cbBlockSize;
                        }
                        impl_rec_ptr -> movedLen = 0;
                    }
                    conv_retcode = pa20PutRec( appl_rec_ptr,
                                               impl_rec_ptr,   /* PTS 1122478 */
                                               stmt_block_ptr->stmtopt.sqlmode);
                    retcode = pa60PutESQError( hstmt, conv_retcode );
                    if ( retcode != SQL_SUCCESS
                         && retcode != SQL_SUCCESS_WITH_INFO ) {
                        retcode = SQL_SUCCESS;
                        dbc_special_ptr -> last_error = API_TRUE;
                        break;
                    }
                }
                if (apgislong( impl_rec_ptr -> type)) {
                    if (stmt_block_ptr->state == API_STMT_PREPARED) {
                        if (cbValueBlock == SQL_NULL_DATA ) {
                            break;
                        }
                        pa30SubtransBegin( &dbc_block_ptr->esqblk,
                                           dbc_block_ptr );
                        sqlda_handle = stmt_block_ptr -> input_sqlda_handle;
                        sqlda_ptr = (sqldatype*) sqlda_handle;
                        API_ASSERT_PTR(sqlda_ptr);
                        stmt_block_ptr->input_sqlda_ptr = sqlda_ptr;
                        retcode = pa10execute( env_block_ptr,
                                               dbc_block_ptr,
                                               stmt_block_ptr,
                                               hstmt);
                    }

                    if (stmt_block_ptr->number_rows > 0  ||  stmt_block_ptr->stmt_function_code != csp1_update_fc) {
                    if ( (retcode == SQL_SUCCESS
                          || retcode == SQL_SUCCESS_WITH_INFO)
                         && stmt_block_ptr->state == API_STMT_EXECUTED) {
                        if (cbValueBlock != SQL_NULL_DATA) {
                            if (cbValueBlock > 0) {
                                sqlda_handle =
                                    stmt_block_ptr -> input_sqlda_handle;
                                sqlda_ptr = (sqldatype*) sqlda_handle;
                                API_ASSERT_PTR(sqlda_ptr);
                                stmt_block_ptr->input_sqlda_ptr = sqlda_ptr;
                                /* send long data only if length > 0
                                   http://pts:1080/webpts?wptsdetail=yes&ErrorType=0&ErrorID=1135698 */
                                if (!(impl_rec_ptr->optimizePtr  &&
                                      apggvstrl (impl_rec_ptr->optimizePtr) == 0))
                                  api_retcode = apeput1l( &dbc_block_ptr->esqblk,
                                                          dbc_block_ptr, 
                                                          stmt_block_ptr );
                                /* if length is 0, do not send any data in this SQLPutData */
                                if (impl_rec_ptr->optimizePtr  &&
                                    apggvstrl (impl_rec_ptr->optimizePtr) == 0)
                                  cbValueBlock = 0;

                                if ( dbc_block_ptr->esqblk.esq_sql_code
                                     != PA_OK) {
                                    retcode = SQL_ERROR;
                                    pa60PutError( hstmt, 
                                                  pa41apmercv( &dbc_block_ptr
                                                           ->esqblk),
                                                  &dbc_block_ptr->esqblk);
                                }
                            }
                        }
                        else {
                            retcode = SQL_ERROR;
                            pa41apmmker( API_SQLODBC_22002,
                                         &dbc_block_ptr->esqblk);
                            pa60PutError( hstmt,
                                          API_ODBC_S1000,
                                          &dbc_block_ptr->esqblk);
                            pa01trsqerr(&dbc_block_ptr->esqblk);
                            pa30SubtransRollback( &dbc_block_ptr->esqblk,
                                                  dbc_block_ptr );
                        }		
                    }
                    if ( retcode == SQL_SUCCESS
                         || retcode == SQL_SUCCESS_WITH_INFO) {
                        stmt_block_ptr -> state = API_STMT_EXECUTED;
                    }
                    else {
                        /* unterdrueckt Fehlermeldungen, die beim ersten
                         * ausfuehren des SQL Kommandos auftreten, diese
                         * werden nur von SQLParamData ausgegeben */
                        if (stmt_block_ptr -> state == API_STMT_PREPARED) {
                            retcode = SQL_SUCCESS;
                            dbc_special_ptr -> last_error = API_TRUE;
                        }
                        stmt_block_ptr -> state = API_STMT_PREPARED;
                        break;
                    }
                } else {
                        /* http://pts:1080/webpts?wptsdetail=yes&ErrorType=0&ErrorID=1138262 */
                        pa60PutError( hstmt, API_ODBC_01001, &dbc_block_ptr->esqblk);
                        retcode = SQL_SUCCESS_WITH_INFO;
                        stmt_block_ptr->state = API_STMT_EXECUTED;
                        dbc_special_ptr -> last_error = API_TRUE;
                        break; /* for (;;) */
                    }
                 } /* apgislon */
                if ( param != -1 &&
                     (retcode == SQL_SUCCESS
                      || retcode == SQL_SUCCESS_WITH_INFO)) {
                    API_TRACE( API_TR_SDWORD, "moved_len",
                               &impl_rec_ptr -> movedLen);
                    if (conv_retcode == API_OK) {
                        rgbValueBlock = (UCHAR*) rgbValueBlock
                            + *(appl_rec_ptr -> octetLengthPtr);
                        if (cbValueBlock > 0)
                            cbValueBlock -= *appl_rec_ptr -> octetLengthPtr;
                        else 
                            cbValueBlock = 0;
                    }
                    if (conv_retcode == API_TRUNCATE) {
                        rgbValueBlock = (UCHAR*) rgbValueBlock
                            + impl_rec_ptr -> movedLen;
                        if (cbValueBlock > 0)
                            cbValueBlock -= impl_rec_ptr -> movedLen;
                        else 
                            cbValueBlock = 0;
                    }
                    API_TRACE(API_TR_SDWORD, "cbValueBlock", &cbValueBlock);
                }
                else 
                    break;
                if (cbValueBlock <= 0)
                    break;
            } /* end for(;;) */
            appl_rec_ptr -> dataPtr = rgbV;
            appl_rec_ptr -> octetLengthPtr = pcbV;
            stmt_block_ptr -> need_data = FALSE;
        }
    } /* of if hstmt valid */
exit_func:   
    API_TRACE(API_TR_EXIT, PA11_FN_SQLPUTDATA, 0);
    API_TRACE(API_TR_RETCODE, "retcode", &retcode);

    return(retcode);
} /* SQLPutData */

#endif  /* of _UNICODE_ODBC */ 


typedef struct {
   tpr05_String *owner_buffer;
   tpr05_String *name_buffer;
   UWORD         mode;
} pa11StackSpecialColumns;

#ifdef _UNICODE_ODBC
ODBC_PROC(SQLSpecialColumnsW,
	  (SQLHSTMT       hstmt,
	   SQLUSMALLINT   fColType,
	   SQLWCHAR      *szTableQualifier,
	   SQLSMALLINT    cbTableQualifier,
	   SQLWCHAR      *szTableOwner,
	   SQLSMALLINT    cbTableOwner,
	   SQLWCHAR      *szTableName,
	   SQLSMALLINT    cbTableName,
	   SQLUSMALLINT   fScope,
	   SQLUSMALLINT   fNullable),
	  (hstmt, fColType, szTableQualifier, cbTableQualifier, szTableOwner, 
           cbTableOwner, szTableName, cbTableName, fScope, fNullable))
#else
ODBC_PROC(SQLSpecialColumns,
	  (SQLHSTMT       hstmt,
	   SQLUSMALLINT   fColType,
	   SQLCHAR       *szTableQualifier,
	   SQLSMALLINT    cbTableQualifier,
	   SQLCHAR       *szTableOwner,
	   SQLSMALLINT    cbTableOwner,
	   SQLCHAR       *szTableName,
	   SQLSMALLINT    cbTableName,
	   SQLUSMALLINT   fScope,
	   SQLUSMALLINT   fNullable),
	  (hstmt, fColType, szTableQualifier, cbTableQualifier, szTableOwner, 
           cbTableOwner, szTableName, cbTableName, fScope, fNullable))
#endif
{
    RETCODE		retcode = SQL_SUCCESS;
    API_RETCODE api_retcode;
    SDWORD		number_rows;
    UWORD		state;
    pa11StackSpecialColumns LV;
    tpa60Stmt  *stmt_block_ptr;
    SQLHDBC     hdbc;
    tpa40DBC   *dbc_block_ptr;
    SQLHENV     henv;
    tpa50Env   *env_block_ptr;
    SDWORD      odbcVersion;
    const char *selectSpecColEmpty;
    const char *selectSpecColSysKey;
    char       *selectSpecColPrmKey;
    const char *tableprefix;
    long res;
#ifdef _UNICODE_ODBC
    const tsp77encoding *encodingType = sp77nativeUnicodeEncoding ();
    SQLCHAR        sql_string [(API_SQL_STRING_SWAG*2) * sizeof (tsp81_UCS2Char)];
#else
    const tsp77encoding *encodingType = sp77encodingAscii;
    SQLCHAR        sql_string [(API_SQL_STRING_SWAG * 3)];
#endif   
    SQLCHAR       *sql_ptr = sql_string;
    const int charSize = encodingType->fixedCharacterSize;

    API_TRACE(API_TR_ENTRY,PA11_FN_SQLSPECIALCOLUMNS,0);
    API_TRACE(API_TR_HANDLE,"hstmt",&hstmt);
    API_TRACE(API_TR_UWORD,"fColType",&fColType);
    API_TRACE_LEN(API_TR_ODBC_STRING,"szTableQualifier",
                  szTableQualifier, cbTableQualifier);
    API_TRACE(API_TR_SWORD,"cbTableQualifier",&cbTableQualifier);
    API_TRACE_LEN(API_TR_ODBC_STRING,"szTableOwner",
                  szTableOwner, cbTableOwner);
    API_TRACE(API_TR_SWORD,"cbTableOwner",&cbTableOwner);
    API_TRACE_LEN(API_TR_ODBC_STRING,"szTableName",
                  szTableName, cbTableName);
    API_TRACE(API_TR_SWORD,"cbTableName",&cbTableName);
    API_TRACE(API_TR_UWORD,"fScope",&fScope);
    API_TRACE(API_TR_UWORD,"fNullable",&fNullable);

    LV.owner_buffer = LV.name_buffer = NULL;

    if (cbTableQualifier != SQL_NTS)
      cbTableQualifier *= charSize;
    if (cbTableOwner != SQL_NTS)
      cbTableOwner *= charSize;
    if (cbTableName != SQL_NTS)
      cbTableName *= charSize;

    api_retcode = apmstfc(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, 
                          SQL_API_SQLSPECIALCOLUMNS);
    if (api_retcode != API_OK) {
        retcode = SQL_INVALID_HANDLE;
    }
    /* ----------------------------------------------------------------- */ 
    else {
        /* ----- Check hstmt ----- */
        if (pa60VerifyStmt(hstmt) != API_OK) {
            retcode = SQL_INVALID_HANDLE;
        } 
        else {
            /* determine which ODBC version the application wants */
            if (!pa10GetODBCVersion( SQL_HANDLE_STMT, hstmt,
                                     &odbcVersion )) {
                retcode = SQL_ERROR;
                /* general error */
                pa60PutError( hstmt, API_ODBC_S1000, NULL);
                goto exit_1_lock;                    
            }; /* if */
            apmlocp(&hstmt, &stmt_block_ptr, &hdbc, &dbc_block_ptr, 
                    &henv, &env_block_ptr);
            state = stmt_block_ptr->state;
            tableprefix = pa12_getTablePrefix (dbc_block_ptr);
            /* ODBC version 3.0 defines different column-names */
            if (odbcVersion == SQL_OV_ODBC3) {
                selectSpecColEmpty  = PA11SELECTSPECCOLEMPTY_OV3;
                selectSpecColSysKey = PA11SELECTSPECCOLSYSKEY_OV3;
                selectSpecColPrmKey = (char *) alloca (strlen(PA11SELECTSPECCOLPRMKEY_OV3) + 30);
                sprintf (selectSpecColPrmKey, PA11SELECTSPECCOLPRMKEY_OV3, tableprefix);
            } else { /* version < 3.x */
                selectSpecColEmpty  = PA11SELECTSPECCOLEMPTY;
                selectSpecColSysKey = PA11SELECTSPECCOLSYSKEY;
                selectSpecColPrmKey = (char *) alloca (strlen(PA11SELECTSPECCOLPRMKEY) + 30);
                sprintf (selectSpecColPrmKey, PA11SELECTSPECCOLPRMKEY, tableprefix);
            }; /* else */            
            PA09ENTERASYNCFUNCTION(dbc_block_ptr, stmt_block_ptr);
            if (pa09IsAsync(stmt_block_ptr, dbc_block_ptr, NULL)) {
                if (pa09IsConnectionBusy(stmt_block_ptr, dbc_block_ptr)) {
                    retcode = SQL_ERROR;
                    pa60PutError( hstmt, API_ODBC_S1010, NULL);
                    goto exit_1_lock;
                }	
                if (state == API_STMT_POSITIONED) {
                    /* function seqeunces error */
                    retcode = SQL_ERROR;            /* SQLSTATE: 24000 */
                    pa60PutError( hstmt, API_ODBC_24000, NULL);
                    goto exit_1_lock;
                }
                /* ----- Check fColType ----- */
                if ( (fColType != SQL_BEST_ROWID) && 
                     (fColType != SQL_ROWVER)) {
                    /* Invalid fColType value */
                    retcode = SQL_ERROR;
                    pa60PutError( hstmt, API_ODBC_S1097, NULL);
                    goto exit_1_lock;
                }
                /* ----- Check fScope ----- */
                if ( (fScope != SQL_SCOPE_CURROW) && 
                     (fScope != SQL_SCOPE_TRANSACTION) &&
                     (fScope != SQL_SCOPE_SESSION)) {
                    /* Invalid fScope value */
                    retcode = SQL_ERROR;
                    pa60PutError( hstmt, API_ODBC_S1098, NULL);
                    goto exit_1_lock;
                }
                /* ----- Check fNullable ----- */
                if ((fNullable != SQL_NO_NULLS) && 
                    (fNullable != SQL_NULLABLE)) {
                    /* Invalid fNullable value */
                    retcode = SQL_ERROR;
                    pa60PutError( hstmt, API_ODBC_S1099, NULL);
                    goto exit_1_lock;
                }	
                /* --------------------------------------------------- */
                /* create strings (ASCII) */
                LV.owner_buffer = pr05IfCom_String_NewDynString (API_USERID_MAX_LEN+1, NULL);
                LV.name_buffer  = pr05IfCom_String_NewDynString (API_TABLE_NAME_MAX+1, NULL);

                /* ***** szTableOwner */
                if (szTableOwner == NULL) {
                  if (pr05IfCom_String_strcpy (LV.owner_buffer, dbc_block_ptr->userid) != ok_epr05)
                    api_retcode = API_NOT_OK;
                }
                else 
                  api_retcode = pa80ODBCtoTpr05 (LV.owner_buffer,
                                                 encodingType,
                                                 szTableOwner,
                                                 cbTableOwner);
	 
                /* ***** szTableName */
                if (api_retcode == API_OK) {
                  if (szTableName == NULL) {
                      /*     API_STRCPY( (UCHAR*) LV.name_buffer->rawString, (UCHAR*) ""); */
                  }
                  else 
                    api_retcode = pa80ODBCtoTpr05 (LV.name_buffer,
                                                   encodingType,
                                                   szTableName,
                                                   cbTableName);
                }
	 
                if (api_retcode != API_OK) {
                    retcode = SQL_ERROR;
                    pa60PutError( hstmt,API_ODBC_S1090, NULL);
                    goto exit_1_lock;
                }
                /* ---------------------------------------------------- */
                /* set mode for rowset */
                LV.mode = PA11SPECCOLSYSKEY;
                if ((fColType == SQL_BEST_ROWID) && 
                    ((fScope == SQL_SCOPE_CURROW) ||
                     (fScope == SQL_SCOPE_TRANSACTION)))
                    LV.mode = PA11SPECCOLPRMKEY;
                /* ---------------------------------------------------- */ 
                stmt_block_ptr -> dbc_special.special =
                    API_SPEC_SQLSPECIALCOLUMNS;
                if (pa09IsAsync(stmt_block_ptr, dbc_block_ptr, &retcode)) {
                    /* store the local stack to restore get the
                     * values in async call */
                    pa09SaveStack( &stmt_block_ptr->async.hLocalValues,
                                   &LV,
                                   sizeof(LV));
                    pa09PrepareAsyncCall( hstmt, SQL_API_SQLSPECIALCOLUMNS);
                }
            } /* async exec */
            if (pa09IsAsync(stmt_block_ptr, dbc_block_ptr, &retcode)) {
                pa09ExecuteAsyncCall(hstmt);
                goto exit_async;
            }
            else {
                /* restore the stack values from async caller */
                if (stmt_block_ptr->async.hLocalValues) {
                    pa09RestoreStack(stmt_block_ptr->async.hLocalValues, &LV);
                    apdfree(stmt_block_ptr->async.hLocalValues);
                    stmt_block_ptr->async.hLocalValues = API_NULL_HANDLE;
                }
            }
            /* -------------------------------------------------------- */ 
            /* check exists table */
            res = sp77sprintfUnicode (encodingType,
                                      sql_ptr, sizeof(sql_string), 
                                      PA11SELECTSPECCOLEXSTAB,
                                      LV.owner_buffer->encodingType,
                                      LV.owner_buffer->cbLen,
                                      LV.owner_buffer->rawString,
                                      LV.name_buffer->encodingType,
                                      LV.name_buffer->cbLen,
                                      LV.name_buffer->rawString);
#ifdef _UNICODE_ODBC
            retcode = CALL_ODBC(SQLExecDirectW, (hstmt, (SQLWCHAR*) sql_ptr, SQL_NTS));
#else
            retcode = CALL_ODBC(SQLExecDirect, (hstmt, sql_ptr, SQL_NTS));
#endif
            if (retcode != SQL_SUCCESS) {
                retcode = SQL_SUCCESS;
                LV.mode = PA11SPECCOLEMPTY;
            }

            switch (LV.mode) {
            case (PA11SPECCOLPRMKEY): {
                /* check primary key column */
                res = sp77sprintfUnicode (encodingType,
                                          sql_ptr, sizeof(sql_string), 
                                          selectSpecColPrmKey,
                                          LV.owner_buffer->encodingType,
                                          LV.owner_buffer->cbLen,
                                          LV.owner_buffer->rawString,
                                          LV.name_buffer->encodingType,
                                          LV.name_buffer->cbLen,
                                          LV.name_buffer->rawString,
                                          PA11SELECTSPECCOLORDERBY);
#ifdef _UNICODE_ODBC
                retcode = CALL_ODBC(SQLPrepareW, (hstmt, (SQLWCHAR*) sql_ptr, SQL_NTS));
#else
                retcode = CALL_ODBC(SQLPrepare, (hstmt, sql_ptr, SQL_NTS));
#endif
                if (retcode == SQL_SUCCESS) {
                    retcode = CALL_ODBC(SQLExecute, (hstmt));
                    number_rows = stmt_block_ptr -> number_rows;
                    API_TRACE(API_TR_SDWORD,"nuber_rows", &number_rows);
		     
                    /* get syskey for table, if row_not_found */
                    if (number_rows == 0) {
                        retcode = CALL_ODBC(SQLFreeStmt, (hstmt, SQL_CLOSE));
                        res = sp77sprintfUnicode (encodingType,
                                                  sql_ptr, sizeof(sql_string), 
                                                  selectSpecColSysKey,
                                                  PA11SELECTSPECCOLORDERBY);
                        stmt_block_ptr -> dbc_special.special =
                            API_SPEC_SQLSPECIALCOLUMNS;
#ifdef _UNICODE_ODBC
                        retcode = CALL_ODBC(SQLPrepareW, (hstmt, (SQLWCHAR*) sql_ptr, SQL_NTS));
#else
                        retcode = CALL_ODBC(SQLPrepare, (hstmt, sql_ptr, SQL_NTS));
#endif
                        if (retcode == SQL_SUCCESS) 
                            retcode = CALL_ODBC(SQLExecute, (hstmt));
                    }
                }
                break;
            }
            /* -------------------------------------------------------- */ 
            case (PA11SPECCOLSYSKEY): {
                res = sp77sprintfUnicode (encodingType,
                                          sql_ptr, sizeof(sql_string), 
                                          selectSpecColSysKey,
                                          PA11SELECTSPECCOLWHERE);
#ifdef _UNICODE_ODBC
                retcode = CALL_ODBC(SQLPrepareW, (hstmt, (SQLWCHAR*) sql_ptr, SQL_NTS));
#else
                retcode = CALL_ODBC(SQLPrepare, (hstmt, sql_ptr, SQL_NTS));
#endif
                if (retcode == SQL_SUCCESS) 
                    retcode = CALL_ODBC(SQLExecute, (hstmt));
                break;
            }
            /* -------------------------------------------------------- */ 
            case (PA11SPECCOLEMPTY): {
                res = sp77sprintfUnicode (encodingType,
                                          sql_ptr, sizeof(sql_string), 
                                          selectSpecColEmpty);
#ifdef _UNICODE_ODBC
                retcode = CALL_ODBC(SQLPrepareW, (hstmt, (SQLWCHAR*) sql_ptr, SQL_NTS));
#else
                retcode = CALL_ODBC(SQLPrepare, (hstmt, sql_ptr, SQL_NTS));
#endif
                if (retcode == SQL_SUCCESS) 
                    retcode = CALL_ODBC(SQLExecute, (hstmt));
                break;
            }
            } /* of switch */
            /* -------------------------------------------------------- */ 
        exit_1_lock:
            pr05IfCom_String_DeleteString (LV.owner_buffer);
            pr05IfCom_String_DeleteString (LV.name_buffer);
        exit_async:
            PA09LEAVEASYNCFUNCTION();
        }  /* start processing */
    } /* set odbc_funtion */ 
    API_TRACE(API_TR_EXIT,PA11_FN_SQLSPECIALCOLUMNS,0);
    API_TRACE(API_TR_RETCODE,"retcode",&retcode);

    return(retcode);
} /* SQLSpecialColumns */


typedef struct {
    tpr05_String *table_buffer;
    tpr05_String *owner_buffer;
    UWORD         fUnique;
    UWORD         fAccuracy;
} pa11StackStatistics;

#ifdef _UNICODE_ODBC
ODBC_PROC(SQLStatisticsW, 
	  (SQLHSTMT        hstmt,
	   SQLWCHAR       *szTableQualifier,
	   SQLSMALLINT     cbTableQualifier,
	   SQLWCHAR       *szTableOwner,
	   SQLSMALLINT     cbTableOwner,
	   SQLWCHAR       *szTableName,
	   SQLSMALLINT     cbTableName,
	   SQLUSMALLINT    fUnique,
	   SQLUSMALLINT    fAccuracy),
	  (hstmt, szTableQualifier, cbTableQualifier, szTableOwner, cbTableOwner, szTableName,
           cbTableName, fUnique, fAccuracy))
#else
ODBC_PROC(SQLStatistics, 
	  (SQLHSTMT        hstmt,
	   SQLCHAR        *szTableQualifier,
	   SQLSMALLINT     cbTableQualifier,
	   SQLCHAR        *szTableOwner,
	   SQLSMALLINT     cbTableOwner,
	   SQLCHAR        *szTableName,
	   SQLSMALLINT     cbTableName,
	   SQLUSMALLINT    fUnique,
	   SQLUSMALLINT    fAccuracy),
	  (hstmt, szTableQualifier, cbTableQualifier, szTableOwner, cbTableOwner, szTableName,
           cbTableName, fUnique, fAccuracy))
#endif
{
    RETCODE		 retcode=SQL_SUCCESS;
    API_RETCODE  api_retcode;
    pa11StackStatistics LV;
    UCHAR        qualifier_buffer [API_TABLE_NAME_MAX+1];
    UCHAR        type_buffer [26];
    SQLHDBC      hdbc;
    SQLHENV      henv;
    tpa40DBC    *dbc_block_ptr;
    tpa50Env    *env_block_ptr;
    tpa60Stmt   *stmt_block_ptr;
    UWORD        state;
    SDWORD       odbcVersion;
    const char  *s8015TableStatQuick;
    char        *selectTableStatQuick;
    char        *selectIndexStatQuick;
    char        *selectTableStatEnsure;
    char        *selectIndexStatEnsure;
    char        *selectPrimaryKeyStatEnsure;
    const char  *tableprefix;
    int i;        
#ifdef _UNICODE_ODBC
    const tsp77encoding *encodingType = sp77nativeUnicodeEncoding ();
    SQLCHAR      sql_string [(API_SQL_STRING_SWAG * 3) * sizeof (tsp81_UCS2Char)];
#else
    const tsp77encoding *encodingType = sp77encodingAscii;
    SQLCHAR      sql_string [(API_SQL_STRING_SWAG * 3)];
#endif   
    const int charSize = encodingType->fixedCharacterSize;
    SQLCHAR     *sql_ptr = sql_string; 
    SQLCHAR     *ptr     = sql_ptr;
    long         res;

    API_TRACE(API_TR_ENTRY,PA11_FN_SQLSTATISTICS,0);
    API_TRACE(API_TR_HANDLE,"hstmt",&hstmt);
    API_TRACE_LEN(API_TR_ODBC_STRING,"szTableQualifier",
                  szTableQualifier, cbTableQualifier);
    API_TRACE(API_TR_SWORD,"cbTableQualifier",&cbTableQualifier);
    API_TRACE_LEN(API_TR_ODBC_STRING,"szTableOwner",
                  szTableOwner, cbTableOwner);
    API_TRACE(API_TR_SWORD,"cbTableOwner",&cbTableOwner);
    API_TRACE_LEN(API_TR_ODBC_STRING,"szTableName",
                  szTableName, cbTableName);
    API_TRACE(API_TR_SWORD,"cbTableName",&cbTableName);
    API_TRACE(API_TR_UWORD,"fUnique",&fUnique);
    API_TRACE(API_TR_UWORD,"fAccuracy",&fAccuracy);

    LV.table_buffer = LV.owner_buffer = NULL;

    if (cbTableQualifier != SQL_NTS)
      cbTableQualifier *= charSize;
    if (cbTableOwner != SQL_NTS)
      cbTableOwner *= charSize;
    if (cbTableName != SQL_NTS)
      cbTableName *= charSize;
       
    api_retcode = apmstfc(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, 
                          SQL_API_SQLSTATISTICS);
    if (api_retcode != API_OK) {
        retcode = SQL_INVALID_HANDLE;
    }
    else {
        if (pa60VerifyStmt( hstmt ) != API_OK) { /* hstmt valid? */
            retcode = SQL_INVALID_HANDLE;
        }
        else {
            /* determine which ODBC version the application wants */
            if (!pa10GetODBCVersion( SQL_HANDLE_STMT, hstmt,
                                     &odbcVersion )) {
                retcode = SQL_ERROR;
                /* general error */
                pa60PutError( hstmt, API_ODBC_S1000, NULL);
                goto exit_immediately;                    
            } /* if */
            /* if tablename is NULL -> HY009, not in ODBC2 */
            if (szTableName == NULL  &&  odbcVersion != SQL_OV_ODBC2) {
                retcode = SQL_ERROR;
                /* general error */
                pa60PutError( hstmt, API_ODBC_HY009, NULL);
                goto exit_immediately;                    
            } /* if */

            apmlocp(&hstmt, &stmt_block_ptr, &hdbc, &dbc_block_ptr, 
                    &henv, &env_block_ptr);
            state = stmt_block_ptr->state;
            tableprefix = pa12_getTablePrefix (dbc_block_ptr);
            /* ODBC version 3.0 defines different column-names */
            if (odbcVersion == SQL_OV_ODBC3) {
                s8015TableStatQuick = PA118015TABLESTATQUICK_OV3;
                selectTableStatQuick  = (char *) alloca (strlen(PA11SELECTTABLESTATQUICK_OV3) + 30);
                selectIndexStatQuick  = (char *) alloca (strlen(PA11SELECTINDEXSTATQUICK_OV3) + 30);
                selectTableStatEnsure = (char *) alloca (strlen(PA11SELECTTABLESTATENSURE_OV3) + 30);
                selectIndexStatEnsure = (char *) alloca (strlen(PA11SELECTINDEXSTATESURE_OV3) + 30);
                selectPrimaryKeyStatEnsure = (char *) alloca (strlen(PA11SELECTPRIMARYKEYSTATENSURE_OV3) + 30);

                sprintf (selectTableStatQuick, PA11SELECTTABLESTATQUICK_OV3, tableprefix);
                sprintf (selectIndexStatQuick, PA11SELECTINDEXSTATQUICK_OV3, tableprefix);
                sprintf (selectTableStatEnsure, PA11SELECTTABLESTATENSURE_OV3, tableprefix);
                sprintf (selectIndexStatEnsure, PA11SELECTINDEXSTATESURE_OV3,
                         tableprefix, tableprefix);
                sprintf (selectPrimaryKeyStatEnsure, PA11SELECTPRIMARYKEYSTATENSURE_OV3,
                         tableprefix, tableprefix);
            } else { /* version < 3.x */
                s8015TableStatQuick = PA118015TABLESTATQUICK;
                selectTableStatQuick  = (char *) alloca (strlen(PA11SELECTTABLESTATQUICK) + 30);
                selectIndexStatQuick  = (char *) alloca (strlen(PA11SELECTINDEXSTATQUICK) + 30);
                selectTableStatEnsure = (char *) alloca (strlen(PA11SELECTTABLESTATENSURE) + 30);
                selectIndexStatEnsure = (char *) alloca (strlen(PA11SELECTINDEXSTATESURE) + 30);
                selectPrimaryKeyStatEnsure = (char *) alloca (strlen(PA11SELECTPRIMARYKEYSTATENSURE) + 30);

                sprintf (selectTableStatQuick, PA11SELECTTABLESTATQUICK, tableprefix);
                sprintf (selectIndexStatQuick, PA11SELECTINDEXSTATQUICK, tableprefix);
                sprintf (selectTableStatEnsure, PA11SELECTTABLESTATENSURE, tableprefix);
                sprintf (selectIndexStatEnsure, PA11SELECTINDEXSTATESURE,
                         tableprefix, tableprefix);
                sprintf (selectPrimaryKeyStatEnsure, PA11SELECTPRIMARYKEYSTATENSURE,
                         tableprefix, tableprefix);
            }; /* else */            
            PA09ENTERASYNCFUNCTION(dbc_block_ptr, stmt_block_ptr);
            if (pa09IsAsync(stmt_block_ptr, dbc_block_ptr, NULL)) {
                if (pa09IsConnectionBusy(stmt_block_ptr, dbc_block_ptr)) {
                    retcode = SQL_ERROR;
                    pa60PutError( hstmt,
                                  API_ODBC_S1010, NULL);
                    goto exit_1_lock;
                }	
                if (state == API_STMT_POSITIONED) {
                    /* function seqeunces error */
                    retcode = SQL_ERROR;            /* SQLSTATE: 24000 */
                    pa60PutError( hstmt, 
                                  API_ODBC_24000, NULL);
                    goto exit_1_lock;
                }
                
/*                 if (szTableQualifier != NULL) { */
/*                     api_retcode = apmwtos( szTableQualifier, */
/*                                            cbTableQualifier, */
/*                                            qualifier_buffer, */
/*                                            sizeof(qualifier_buffer) ); */
/*                     if (api_retcode != API_OK) { */
/*                         retcode = SQL_ERROR; */
/*                         pa60PutError( hstmt, API_ODBC_S1090, NULL); */
/*                         goto exit_1_lock; */
/*                     } */
/*                 } */
                /* create strings (ASCII) */
                LV.table_buffer = pr05IfCom_String_NewDynString (charSize * (API_TABLE_NAME_MAX+1), 
                                                                 encodingType);
                LV.owner_buffer = pr05IfCom_String_NewDynString (charSize * (API_USERID_MAX_LEN+1),
                                                                 encodingType);

                if (LV.table_buffer == NULL || LV.owner_buffer == NULL) {
                  retcode = SQL_ERROR;            
                  pa60PutError( hstmt, API_ODBC_S1001, NULL);
                  goto exit_1_lock;
                }

                if (szTableOwner == NULL || cbTableOwner == 0) {
                  if (pr05IfCom_String_strcpy (LV.owner_buffer, dbc_block_ptr->userid) != ok_epr05)
                    api_retcode = API_NOT_OK;
                }
                else {
                    api_retcode = pa80ODBCtoTpr05 (LV.owner_buffer,
                                                   encodingType,
                                                   szTableOwner,
                                                   cbTableOwner);
                    if (api_retcode != API_OK) {
                        retcode = SQL_ERROR;
                        pa60PutError( hstmt, API_ODBC_S1090, NULL);
                        goto exit_1_lock;
                    }
                }

                if (szTableName == NULL || cbTableName == 0) {
                  /*                    API_STRCPY( (UCHAR*) LV.table_buffer->rawString, (UCHAR*) ""); */
                }
                else {
                    api_retcode = pa80ODBCtoTpr05 (LV.table_buffer,
                                                   encodingType,
                                                   szTableName,
                                                   cbTableName);
                    if (api_retcode != API_OK) {
                        retcode = SQL_ERROR;
                        pa60PutError( hstmt, API_ODBC_S1090, NULL);
                        goto exit_1_lock;
                    }
                }     
                LV.fUnique = fUnique;
                LV.fAccuracy = fAccuracy;
      
                stmt_block_ptr -> dbc_special.special = API_SPEC_SQLSTATISTICS;
                if (pa09IsAsync(stmt_block_ptr, dbc_block_ptr, &retcode)) {
                    /* store the local stack to restore get the values
                     * in async call */
                    pa09SaveStack( &stmt_block_ptr->async.hLocalValues,
                                   &LV,
                                   sizeof(LV));
                    pa09PrepareAsyncCall( hstmt, SQL_API_SQLSTATISTICS );
                }
            } /* async exec */
            if (pa09IsAsync(stmt_block_ptr, dbc_block_ptr, &retcode)) {
                pa09ExecuteAsyncCall(hstmt);
                goto exit_async;
            }
            else {
                /* restore the stack values from async caller */
                if (stmt_block_ptr->async.hLocalValues) {
                    pa09RestoreStack(stmt_block_ptr->async.hLocalValues, &LV);
                    apdfree(stmt_block_ptr->async.hLocalValues);
                    stmt_block_ptr->async.hLocalValues = API_NULL_HANDLE;
                }
            }

            if (LV.fUnique != SQL_INDEX_UNIQUE) {
                API_STRCPY((UCHAR*) type_buffer, (UCHAR*) "");
            }
            else {
                API_STRCPY( (UCHAR*) type_buffer,
                            (UCHAR*) "AND INDEX_TYPE = 'UNIQUE'");
            }
            if ( LV.fAccuracy == SQL_ENSURE ) {
                ptr += res = sp77sprintfUnicode (encodingType,
                                           ptr, sizeof(sql_string)-(ptr-sql_ptr), 
                                           selectTableStatEnsure,
                                           LV.owner_buffer->encodingType,
                                           LV.owner_buffer->cbLen,
                                           LV.owner_buffer->rawString,
                                           LV.table_buffer->encodingType,
                                           LV.table_buffer->cbLen,
                                           LV.table_buffer->rawString);
                ptr += res = sp77sprintfUnicode (encodingType,
                                           ptr, sizeof(sql_string)-(ptr-sql_ptr), 
                                           selectIndexStatEnsure,
                                           LV.owner_buffer->encodingType,
                                           LV.owner_buffer->cbLen,
                                           LV.owner_buffer->rawString,
                                           LV.table_buffer->encodingType,
                                           LV.table_buffer->cbLen,
                                           LV.table_buffer->rawString);

                ptr += res = sp77sprintfUnicode (encodingType,
                                           ptr, sizeof(sql_string)-(ptr-sql_ptr), 
                                           "%s",
                                           type_buffer);

                ptr += res = sp77sprintfUnicode (encodingType,
                                           ptr, sizeof(sql_string)-(ptr-sql_ptr), 
                                           selectPrimaryKeyStatEnsure,
                                           LV.owner_buffer->encodingType,
                                           LV.owner_buffer->cbLen,
                                           LV.owner_buffer->rawString,
                                           LV.table_buffer->encodingType,
                                           LV.table_buffer->cbLen,
                                           LV.table_buffer->rawString);
            }
            else {
                ptr += res = sp77sprintfUnicode (encodingType,
                                           ptr, sizeof(sql_string)-(ptr-sql_ptr), 
                                           selectTableStatQuick,
                                           LV.owner_buffer->encodingType,
                                           LV.owner_buffer->cbLen,
                                           LV.owner_buffer->rawString,
                                           LV.table_buffer->encodingType,
                                           LV.table_buffer->cbLen,
                                           LV.table_buffer->rawString);

                ptr += res = sp77sprintfUnicode (encodingType,
                                           ptr, sizeof(sql_string)-(ptr-sql_ptr), 
                                           selectIndexStatQuick,
                                           LV.owner_buffer->encodingType,
                                           LV.owner_buffer->cbLen,
                                           LV.owner_buffer->rawString,
                                           LV.table_buffer->encodingType,
                                           LV.table_buffer->cbLen,
                                           LV.table_buffer->rawString);
                
                ptr += res = sp77sprintfUnicode (encodingType,
                                           ptr, sizeof(sql_string)-(ptr-sql_ptr), 
                                           "%s",
                                           type_buffer);

/*                 API_STRCAT( ptr, type_buffer); */
/*                 ptr += API_STRLEN(type_buffer); */
            }
            ptr += res = sp77sprintfUnicode (encodingType,
                                       ptr, sizeof(sql_string)-(ptr-sql_ptr), 
                                       "%s",
                                       PA11ORDER);
                /*            API_STRCAT( ptr, PA11ORDER); */

#ifdef _UNICODE_ODBC
            retcode = CALL_ODBC(SQLPrepareW, (hstmt, (SQLWCHAR*) sql_ptr, SQL_NTS));
#else
            retcode = CALL_ODBC(SQLPrepare, (hstmt, sql_ptr, SQL_NTS));
#endif
            if (retcode == SQL_SUCCESS) {
                retcode = CALL_ODBC(SQLExecute, (hstmt));
            }
            if (retcode != SQL_SUCCESS) {
                if(dbc_block_ptr->esqblk.sqlca.sqlcode == -8015) {
                    ptr = sql_ptr;

                    ptr += res = sp77sprintfUnicode (encodingType,
                                               ptr, sizeof(sql_string)-(ptr-sql_ptr), 
                                               s8015TableStatQuick,
                                               LV.owner_buffer->encodingType,
                                               LV.owner_buffer->cbLen,
                                               LV.owner_buffer->rawString,
                                               LV.table_buffer->encodingType,
                                               LV.table_buffer->cbLen,
                                               LV.table_buffer->rawString);
#ifdef _UNICODE_ODBC
                    retcode = CALL_ODBC(SQLPrepareW, (hstmt, (SQLWCHAR*) sql_ptr, SQL_NTS));
#else
                    retcode = CALL_ODBC(SQLPrepare, (hstmt, sql_ptr, SQL_NTS));
#endif
                    if (retcode == SQL_SUCCESS) {
                        retcode = CALL_ODBC(SQLExecute, (hstmt));
                    }
                }
            }
        exit_1_lock:
            pr05IfCom_String_DeleteString (LV.owner_buffer);
            pr05IfCom_String_DeleteString (LV.table_buffer);
        exit_async:
            PA09LEAVEASYNCFUNCTION();
        exit_immediately: ;
        }  /* start processing */
    } /* set odbc_funtion */ 
    API_TRACE(API_TR_EXIT,PA11_FN_SQLSTATISTICS,0);
    API_TRACE(API_TR_RETCODE,"retcode",&retcode);
   
    return(retcode);
} /* SQLStatistics */


typedef struct {
    tpr05_String *type_string;
    tpr05_String *qualifier_string;
    tpr05_String *owner_string;
    tpr05_String *table_string;
} pa11StackTables;

#ifdef _UNICODE_ODBC
ODBC_PROC(SQLTablesW, (SQLHSTMT      hstmt,
                       SQLWCHAR     *szTableQualifier,
            	       SQLSMALLINT   cbTableQualifier,
                       SQLWCHAR     *szTableOwner,
                       SQLSMALLINT   cbTableOwner,
                       SQLWCHAR     *szTableName,
	               SQLSMALLINT   cbTableName,
	               SQLWCHAR     *szTableType,
	               SQLSMALLINT   cbTableType),
  ( hstmt, szTableQualifier, cbTableQualifier, szTableOwner,
    cbTableOwner, szTableName, cbTableName, szTableType, cbTableType))
#else
ODBC_PROC(SQLTables, (SQLHSTMT      hstmt,
                       SQLCHAR      *szTableQualifier,
            	       SQLSMALLINT   cbTableQualifier,
                       SQLCHAR      *szTableOwner,
                       SQLSMALLINT   cbTableOwner,
                       SQLCHAR      *szTableName,
	               SQLSMALLINT   cbTableName,
	               SQLCHAR      *szTableType,
	               SQLSMALLINT   cbTableType),
  ( hstmt, szTableQualifier, cbTableQualifier, szTableOwner,
    cbTableOwner, szTableName, cbTableName, szTableType, cbTableType))
#endif
{
    RETCODE         retcode=SQL_SUCCESS;
    API_RETCODE     api_retcode;
    SDWORD          table_type;
    UWORD           mode = API_TABLE_SCAN; /* default, list tables */
    UWORD           state;
    pa11StackTables LV;
    SQLHDBC         hdbc;
    SQLHENV         henv;
    tpa40DBC       *dbc_block_ptr;
    tpa50Env       *env_block_ptr;
    tpa60Stmt      *stmt_block_ptr;
    UWORD           comment;
    UDWORD          odbcVersion;
    char         *selectTableScan;
    const char   *selectQualifierScan;
    const char   *selectTableType;
    const char   *selectOwnerScan;
    const char   *tableprefix;
    tsp00_Uint4    srcBytesParsed;
    char           rawString[10];
    tpr05_String   percentStr, *sqlString = NULL, *whereString = NULL;

#ifdef _UNICODE_ODBC
    const tsp77encoding *encodingType = sp77nativeUnicodeEncoding ();
#else
    const tsp77encoding *encodingType = sp77encodingAscii;
#endif   
    const int charSize = encodingType->fixedCharacterSize;
    
    API_TRACE(API_TR_ENTRY,PA11_FN_SQLTABLES,0);
    API_TRACE(API_TR_HANDLE,"hstmt",&hstmt);
    API_TRACE_LEN(API_TR_ODBC_STRING,"szTableQualifier",
                  szTableQualifier, cbTableQualifier);
    API_TRACE(API_TR_SWORD,"cbTableQualifier",&cbTableQualifier);
    API_TRACE_LEN(API_TR_ODBC_STRING,"szTableOwner",
                  szTableOwner, cbTableOwner);
    API_TRACE(API_TR_SWORD,"cbTableOwner",&cbTableOwner);
    API_TRACE_LEN(API_TR_ODBC_STRING,"szTableName",
                  szTableName, cbTableName);
    API_TRACE(API_TR_SWORD,"cbTableName",&cbTableName);
    API_TRACE_LEN(API_TR_ODBC_STRING,"szTableType",
                  szTableType, cbTableType);
    API_TRACE(API_TR_SWORD,"cbTableType",&cbTableType);
   
    LV.type_string  = LV.qualifier_string = NULL;
    LV.owner_string = LV.table_string     = NULL;

    if (cbTableQualifier != SQL_NTS)
      cbTableQualifier *= charSize;
    if (cbTableOwner != SQL_NTS)
      cbTableOwner *= charSize;
    if (cbTableName != SQL_NTS)
      cbTableName *= charSize;
    if (cbTableType != SQL_NTS)    /* PTS 1121190 */
       cbTableType *= charSize;

    api_retcode = apmstfc(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, 
                          SQL_API_SQLTABLES);
    if (api_retcode != API_OK) {
        retcode = SQL_INVALID_HANDLE;
    }
    else {
        if (pa60VerifyStmt( hstmt ) != API_OK) { /* hstmt valid? */
            retcode = SQL_INVALID_HANDLE;
        }
        else {
            apmlocp(&hstmt, &stmt_block_ptr, &hdbc, &dbc_block_ptr, 
                    &henv, &env_block_ptr);
            /* determine which ODBC version the application wants */
            if (!pa10GetODBCVersion( SQL_HANDLE_STMT, hstmt,
                                     &odbcVersion )) {
                retcode = SQL_ERROR;
                /* general error */
                pa60PutError( hstmt, API_ODBC_S1000, NULL);
                goto exit_1_lock;                    
            }; /* if */
            tableprefix = pa12_getTablePrefix (dbc_block_ptr);
            /* ODBC version 3.0 defines different column-names */
            if (odbcVersion == SQL_OV_ODBC3) {
                selectTableScan = (char *) alloca (strlen(PA11SELECTTABLESCAN_OV3) + 30);
                sprintf (selectTableScan, PA11SELECTTABLESCAN_OV3, tableprefix);
                selectQualifierScan = PA11SELECTQUALIFIERSCAN_OV3;
                selectTableType     = PA11SELECTTABLETYPE_OV3;
                selectOwnerScan     = PA11SELECTOWNERSCAN_OV3;
            } else { /* version < 3.x */
                selectTableScan = (char *) alloca (strlen(PA11SELECTTABLESCAN) + 30);
                sprintf (selectTableScan, PA11SELECTTABLESCAN, tableprefix);
                selectQualifierScan = PA11SELECTQUALIFIERSCAN;
                selectTableType     = PA11SELECTTABLETYPE;
                selectOwnerScan     = PA11SELECTOWNERSCAN;
            }; /* else */            
            state = stmt_block_ptr->state;
            PA09ENTERASYNCFUNCTION(dbc_block_ptr, stmt_block_ptr);
            if (pa09IsAsync(stmt_block_ptr, dbc_block_ptr, NULL)) {
                if (pa09IsConnectionBusy(stmt_block_ptr, dbc_block_ptr)) {
                    retcode = SQL_ERROR;
                    pa60PutError( hstmt, API_ODBC_S1010, NULL);
                    goto exit_1_lock;
                }	
                if (state == API_STMT_POSITIONED) {
                    /* function seqeunces error */
                    retcode = SQL_ERROR;
                    pa60PutError( hstmt, API_ODBC_24000, NULL);
                    goto exit_1_lock;
                }
                
                /* create strings */
                LV.type_string      = 
                  pr05IfCom_String_NewDynString (charSize * ((API_SQL_STRING_SWAG / 2)+1), 
                                                 encodingType);
                LV.qualifier_string = 
                  pr05IfCom_String_NewDynString (charSize * (API_TABLE_NAME_MAX+1), 
                                                 encodingType);
                LV.owner_string     = 
                  pr05IfCom_String_NewDynString (charSize * ((API_USERID_MAX_LEN*2)+1), 
                                                 encodingType);
                LV.table_string     = 
                  pr05IfCom_String_NewDynString (charSize * ((API_TABLE_NAME_MAX*2)+1), 
                                                 encodingType);

                if (LV.type_string   == NULL || LV.qualifier_string == NULL ||
                    LV.owner_string  == NULL || LV.table_string     == NULL)  {
                  retcode = SQL_ERROR;            
                  pa60PutError( hstmt, API_ODBC_S1001, NULL);
                  goto exit_1_lock;
                }

                if (szTableQualifier == NULL) {
                  sp78convertBuffer (encodingType,
                                     LV.qualifier_string->rawString,
                                     LV.qualifier_string->cbMaxLen,
                                     &LV.qualifier_string->cbLen,
                                     sp77encodingAscii,
                                     "%",
                                     API_STRLEN ("%"),
                                     &srcBytesParsed);
                } else {
                    api_retcode = pa80ODBCtoTpr05 (LV.qualifier_string,
                                                   encodingType,
                                                   szTableQualifier,
                                                   cbTableQualifier);
                    if (api_retcode != API_OK) {
                        retcode = SQL_ERROR;
                        pa60PutError( hstmt, API_ODBC_S1090, NULL);
                        goto exit_1_lock;
                    };
                }
      	 
                if (szTableOwner == NULL) {
                  sp78convertBuffer (encodingType,
                                     LV.owner_string->rawString,
                                     LV.owner_string->cbMaxLen,
                                     &LV.owner_string->cbLen,
                                     sp77encodingAscii,
                                     "%",
                                     API_STRLEN ("%"),
                                     &srcBytesParsed);
                } else {
                    api_retcode = pa80ODBCtoTpr05 (LV.owner_string,
                                                   encodingType,
                                                   szTableOwner,
                                                   cbTableOwner);

                    if (api_retcode != API_OK) {
                        retcode = SQL_ERROR;
                        pa60PutError( hstmt, API_ODBC_S1090, NULL);
                        goto exit_1_lock;
                    };
                }
      
                if (szTableName == NULL) {
                  sp78convertBuffer (encodingType,
                                     LV.table_string->rawString,
                                     LV.table_string->cbMaxLen,
                                     &LV.table_string->cbLen,
                                     sp77encodingAscii,
                                     "%",
                                     API_STRLEN ("%"),
                                     &srcBytesParsed);
                } else {
                    api_retcode = pa80ODBCtoTpr05 (LV.table_string,
                                                   encodingType,
                                                   szTableName,
                                                   cbTableName);

                    if (api_retcode != API_OK) {
                        retcode = SQL_ERROR;
                        pa60PutError( hstmt, API_ODBC_S1090, NULL);
                        goto exit_1_lock;
                    };
                    pr05IfCom_String_toupper (LV.table_string);
                }
            
                if (szTableType == NULL) {
                  sp78convertBuffer (encodingType,
                                     LV.type_string->rawString,
                                     LV.type_string->cbMaxLen,
                                     &LV.type_string->cbLen,
                                     sp77encodingAscii,
                                     "%",
                                     API_STRLEN ("%"),
                                     &srcBytesParsed);
                } else {
                    api_retcode = pa80ODBCtoTpr05 (LV.type_string,
                                                   encodingType,
                                                   szTableType,
                                                   cbTableType);

                    if (api_retcode != API_OK) {
                        retcode = SQL_ERROR;
                        pa60PutError( hstmt, API_ODBC_S1090, NULL);
                        goto exit_1_lock;
                    };
                };
                stmt_block_ptr -> dbc_special.special = API_SPEC_SQLTABLES;
                if (pa09IsAsync(stmt_block_ptr, dbc_block_ptr, &retcode)) {
                    /* store the local stack to restore get the values
                     * in async call */
                    pa09SaveStack( &stmt_block_ptr->async.hLocalValues,
                                   &LV,
                                   sizeof(LV));
                    pa09PrepareAsyncCall(hstmt, SQL_API_SQLTABLES);     
                }
            } /* async exec */
            if (pa09IsAsync( stmt_block_ptr, dbc_block_ptr, &retcode )) {
                pa09ExecuteAsyncCall( hstmt );
                goto exit_async;
            } else {
                /* restore the stack values from async caller */
                if (stmt_block_ptr->async.hLocalValues) {
                    pa09RestoreStack(stmt_block_ptr->async.hLocalValues, &LV);
                    apdfree(stmt_block_ptr->async.hLocalValues);
                    stmt_block_ptr->async.hLocalValues = API_NULL_HANDLE;
                }
            }
            /* build string "%" in appropriated encoding for comparing */
            percentStr.allocationType = constant_epr05;
            pr05IfCom_String_InitString (&percentStr, rawString, sizeof (rawString), 
                                         encodingType, constant_epr05);
            pr05IfCom_String_ClearString (&percentStr);
            pr05IfCom_String_strcatP (&percentStr, "%", API_STRLEN ("%"), sp77encodingAscii);
                                         
            if (pr05IfCom_String_strcmp (LV.qualifier_string, &percentStr) == 0
                && LV.owner_string->cbLen == 0
                && LV.table_string->cbLen == 0)  {
                mode = API_QUALIFIER_SCAN; /* list qualifiers */
            }

            if (pr05IfCom_String_strcmp (LV.owner_string, &percentStr) == 0
                && LV.qualifier_string->cbLen == 0
                && LV.table_string->cbLen == 0)  {
                mode = API_OWNER_SCAN; /* list owners */
            }
      
            if (pr05IfCom_String_strcmp (LV.type_string, &percentStr) == 0
                && LV.qualifier_string->cbLen == 0
                && LV.table_string->cbLen == 0
                && LV.owner_string->cbLen == 0) {
                mode = API_TYPE_SCAN; /* list tabletypes */
            }
            API_TRACE(API_TR_UWORD,"mode",&mode);

            if (mode == API_TABLE_SCAN) {
                table_type = API_TABLE_NONE;
                api_retcode = pa01chktabtyp (LV.type_string,
                                             &table_type);
                if (api_retcode != API_OK) {
                    retcode = SQL_ERROR;
                    pa60PutError( hstmt, API_ODBC_S1000, NULL);
                    goto exit_1_lock;
                }    
                api_retcode = pa01mktabtyp( table_type,
                                            LV.type_string);
                if (api_retcode != API_OK) {
                    retcode = SQL_ERROR;
                    pa60PutError( hstmt, API_ODBC_S1001, NULL);
                    goto exit_1_lock;
                }    
            }
            comment = dbc_block_ptr->catalogcomments;
            /* ------------------------------------------------------- */
            sqlString = pr05IfCom_String_NewDynString (charSize * API_SQL_STRING_SWAG * 2, 
                                                       encodingType);
            whereString = pr05IfCom_String_NewDynString (charSize * API_SQL_STRING_SWAG / 2, 
                                                         encodingType);
            if (sqlString == NULL || whereString == NULL) {
              retcode = SQL_ERROR;            
              pa60PutError( hstmt, API_ODBC_S1001, NULL);
              goto exit_1_lock;
            }
            switch (mode) {
            case (API_TABLE_SCAN): {
                if (retcode == SQL_SUCCESS) {
                    pr05IfCom_String_strcatP (sqlString, 
                                              selectTableScan,
                                              API_STRLEN (selectTableScan),
                                              sp77encodingAscii);
                    if (LV.owner_string->cbLen > 0
                        || LV.table_string->cbLen > 0
                        || table_type != API_TABLE_NONE) {
                        /* add a where clause */
                        pr05IfCom_String_strcatP (sqlString, 
                                                  PA11SELECTTABLESWHERE,
                                                  API_STRLEN (PA11SELECTTABLESWHERE),
                                                  sp77encodingAscii);
                    }
                    if (LV.owner_string->cbLen > 0) {
                        whereString->cbLen = 
                          sp77sprintfUnicode (whereString->encodingType,
                                              whereString->rawString, whereString->cbMaxLen, 
                                              PA11SELECTTABLESOWNER,
                                              LV.owner_string->encodingType,
                                              LV.owner_string->cbLen,
                                              LV.owner_string->rawString);
                        pr05IfCom_String_strcat (sqlString, whereString);

                        if (LV.table_string->cbLen > 0
                            || table_type != API_TABLE_NONE) 
                            pr05IfCom_String_strcatP (sqlString, 
                                                      PA11SELECTTABLESAND,
                                                      API_STRLEN (PA11SELECTTABLESAND),
                                                      sp77encodingAscii);
                    }
                    if (LV.table_string->cbLen > 0) {
                        whereString->cbLen = 
                          sp77sprintfUnicode (whereString->encodingType,
                                              whereString->rawString, whereString->cbMaxLen, 
                                              PA11SELECTTABLESTABNAME,
                                              LV.table_string->encodingType,
                                              LV.table_string->cbLen,
                                              LV.table_string->rawString);
                        pr05IfCom_String_strcat (sqlString, whereString);

                        if (table_type != API_TABLE_NONE) 
                            pr05IfCom_String_strcatP (sqlString, 
                                                      PA11SELECTTABLESAND,
                                                      API_STRLEN (PA11SELECTTABLESAND),
                                                      sp77encodingAscii);
                    }		  
                    if (table_type != API_TABLE_NONE) {
                        whereString->cbLen = 
                          sp77sprintfUnicode (whereString->encodingType,
                                              whereString->rawString, whereString->cbMaxLen, 
                                              PA11SELECTTABLESTYPE,
                                              LV.type_string->encodingType,
                                              LV.type_string->cbLen,
                                              LV.type_string->rawString);
                        pr05IfCom_String_strcat (sqlString, whereString);
                    }
                    pr05IfCom_String_strcatP (sqlString, 
                                              PA11SELECTTABLESORDERBY,
                                              API_STRLEN (PA11SELECTTABLESORDERBY),
                                              sp77encodingAscii);
                    retcode = SQL_SUCCESS;
                }
                break;
            }
            /* ----------------------------------------------------- */
            case (API_QUALIFIER_SCAN): { /* list qualifiers */
                if (retcode == SQL_SUCCESS) {
                    pr05IfCom_String_strcatP (sqlString, 
                                              selectQualifierScan,
                                              API_STRLEN (selectQualifierScan),
                                              sp77encodingAscii);
                    retcode = SQL_SUCCESS;
                }
                break;
            }
            /* ------------------------------------------------------ */
            case (API_TYPE_SCAN): { /* list tabletypes */
                if (retcode == SQL_SUCCESS) {
                    pr05IfCom_String_strcatP (sqlString, 
                                              selectTableType,
                                              API_STRLEN (selectTableType),
                                              sp77encodingAscii);
                    retcode = SQL_SUCCESS;
                }
                break;
            }
            /* ------------------------------------------------------- */
            case (API_OWNER_SCAN): { /* list owners */
                if (retcode == SQL_SUCCESS) {
                    pr05IfCom_String_strcatP (sqlString, 
                                              selectOwnerScan,
                                              API_STRLEN (selectOwnerScan),
                                              sp77encodingAscii);
                    retcode = SQL_SUCCESS;
                }
                break;
            }
            default: {
                retcode = SQL_ERROR;	    
            }
            }
            /* -------------------------------------------------------- */

            if (retcode == SQL_SUCCESS) {
#ifdef _UNICODE_ODBC
                retcode = CALL_ODBC(SQLPrepareW, (hstmt, sqlString->rawString, 
                                                  sqlString->cbLen / sizeof (tsp81_UCS2Char)));
#else
                retcode = CALL_ODBC(SQLPrepare, (hstmt, sqlString->rawString, sqlString->cbLen));
#endif
                if (retcode == SQL_SUCCESS)
                    retcode = CALL_ODBC(SQLExecute, (hstmt));    
            }
        exit_1_lock:
            pr05IfCom_String_DeleteString (sqlString);
            pr05IfCom_String_DeleteString (whereString);

            pr05IfCom_String_DeleteString (LV.type_string);
            pr05IfCom_String_DeleteString (LV.qualifier_string);
            pr05IfCom_String_DeleteString (LV.owner_string);
            pr05IfCom_String_DeleteString (LV.table_string);
        exit_async:
            PA09LEAVEASYNCFUNCTION();
        }  /* start processing */
    } /* set odbc_funtion */ 

    API_TRACE(API_TR_EXIT,PA11_FN_SQLTABLES,0);
    API_TRACE(API_TR_RETCODE,"retcode",&retcode);
    return(retcode);
} /* SQLTables */


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