Commit the changed files from the enhanced branch
authorDave Page <dpage@pgadmin.org>
Sat, 8 Apr 2006 16:30:02 +0000 (16:30 +0000)
committerDave Page <dpage@pgadmin.org>
Sat, 8 Apr 2006 16:30:02 +0000 (16:30 +0000)
67 files changed:
Makefile.am
bind.c
bind.h
catfunc.h [new file with mode: 0644]
columninfo.c
columninfo.h
configure.ac
connection.c
connection.h
convert.c
convert.h
descriptor.c
descriptor.h
dlg_specific.c
dlg_specific.h
dlg_wingui.c
drvconn.c
environ.c
environ.h
execute.c
info.c
info30.c
inouealc.c [new file with mode: 0644]
license.txt
loadlib.c [new file with mode: 0644]
loadlib.h [new file with mode: 0644]
lobj.c [new file with mode: 0644]
lobj.h [new file with mode: 0644]
md5.c
misc.c
misc.h
multibyte.c
multibyte.h
mylog.c [new file with mode: 0644]
odbc-drop.sql [new file with mode: 0644]
odbc.sql [new file with mode: 0644]
odbcapi.c
odbcapi25w.c [new file with mode: 0644]
odbcapi30.c
odbcapi30w.c
odbcapiw.c
options.c
parse.c
pgapi30.c
pgapifunc.h
pgtypes.c
pgtypes.h
psqlodbc.c
psqlodbc.h
psqlodbc.rc
psqlodbc35w.dsp [new file with mode: 0644]
psqlodbc_api30w.def [new file with mode: 0644]
qresult.c
qresult.h
resource.h
results.c
setup.c
socket.c [new file with mode: 0644]
socket.h [new file with mode: 0644]
statement.c
statement.h
tuple.c
tuple.h
version.h
win32_30w.mak [new file with mode: 0644]
win_setup.h
win_unicode.c

index 53e9593c537160c178ba6bed211115f304a809a9..f2b093ef22e6a80c39361181e174a37c4830b3f6 100644 (file)
@@ -1,62 +1,48 @@
 #-------------------------------------------------------------------------
 #
-# Makefile.am for psqlodbc (PostgreSQL ODBC driver)
+# Makefile.am for psqlodbc30w (PostgreSQL ODBC driver)
 #
-# $Header: /home/heikki/psqlodbc-cvs-copy/psqlodbc/Makefile.am,v 1.31 2006/01/14 18:12:00 petere Exp $
+# $Header: /home/heikki/psqlodbc-cvs-copy/psqlodbc/Makefile.am,v 1.32 2006/04/08 16:30:00 dpage Exp $
 #
 #-------------------------------------------------------------------------
 
 AUTOMAKE_OPTIONS = 1.6 foreign
 
-if enable_unicode
-lib_LTLIBRARIES = psqlodbcw.la
-else
-lib_LTLIBRARIES = psqlodbca.la
-endif
+lib_LTLIBRARIES = psqlodbc30w.la
 
-AM_LDFLAGS = -module -no-undefined -avoid-version
-LIBS += -lpq
+psqlodbc30w_la_LDFLAGS = -module -no-undefined -avoid-version
 
-psqlodbca_la_SOURCES = \
-   info.c bind.c columninfo.c connection.c convert.c drvconn.c \
-   environ.c execute.c win_md5.c misc.c options.c \
-   pgtypes.c psqlodbc.c qresult.c results.c parse.c \
-   statement.c tuple.c tuplelist.c dlg_specific.c odbcapi.c \
-   multibyte.c \
-   odbcapi30.c pgapi30.c info30.c descriptor.c
+psqlodbc30w_la_LIBADD = -lpq
 
-psqlodbca_la_SOURCES += \
+psqlodbc30w_la_SOURCES = \
+   info.c bind.c columninfo.c connection.c convert.c drvconn.c \
+   environ.c execute.c lobj.c win_md5.c misc.c options.c \
+   pgtypes.c psqlodbc.c qresult.c results.c socket.c parse.c \
+   statement.c tuple.c dlg_specific.c loadlib.c \
+   multibyte.c odbcapi.c descriptor.c \
+   odbcapi30.c pgapi30.c info30.c mylog.c \
+\
    bind.h columninfo.h connection.h convert.h descriptor.h \
-   dlg_specific.h environ.h \
-   connection.h md5.h misc.h multibyte.h pgapifunc.h pgtypes.h \
-   psqlodbc.h qresult.h resource.h statement.h tuple.h \
-   tuplelist.h version.h
+   dlg_specific.h environ.h iodbc.h isql.h isqlext.h \
+   lobj.h md5.h misc.h multibyte.h pgapifunc.h pgtypes.h \
+   psqlodbc.h qresult.h resource.h socket.h statement.h tuple.h \
+   version.h loadlib.h
 
-psqlodbcw_la_SOURCES = $(psqlodbca_la_SOURCES) \
-   odbcapi30w.c odbcapiw.c win_unicode.c    
+if enable_unicode
+psqlodbc30w_la_SOURCES += \
+odbcapiw.c odbcapi30w.c win_unicode.c
+endif
 
-EXTRA_psqlodbca_la_SOURCES = md5.c
-EXTRA_psqlodbcw_la_SOURCES = md5.c
+EXTRA_psqlodbc30w_la_SOURCES = md5.c
 
 EXTRA_DIST = license.txt readme.txt odbcinst.ini \
-   libtool.m4 psqlodbca.def psqlodbcw.def win32.mak \
-   dlg_wingui.c win_setup.h win_md5.c setup.c \
+   libtool.m4 psqlodbc_api30w.def win32_30w.mak \
+   dlg_wingui.c win_setup.h setup.c \
    win_unicode.c psqlodbc.rc psqlodbc.reg \
-   psqlodbc.dsp psqlodbc.dsw \
-   docs/index.html docs/config.html \
-   docs/faq.html docs/howto-accesslo.html \
-   docs/howto-accessvba.html docs/howto-bo.html \
-   docs/howto-ch.html docs/howto-csharp.html \
-   docs/howto-vb.html docs/howto-vblo.html \
-   docs/unix-compilation.html docs/win32-compilation.html \
-   docs/release.html \
-   installer/banner.bmp installer/lgpl.rtf \
-   installer/new.bmp installer/up.bmp \
-   installer/Make.bat installer/upgrade.bat \
-   installer/psqlodbc.wxs installer/psqlodbcm.wxs \
-   installer/README.txt
+   psqlodbc35w.dsp psqlodbc35w.dsw 
    
 MAINTAINERCLEANFILES = \
    Makefile.in config.guess config.h.in config.sub configure \
    install-sh missing mkinstalldirs aclocal.m4 ltmain.sh \
    libtool.m4 depcomp
+
diff --git a/bind.c b/bind.c
index 9e1cdac128ce1104971feef9652c92b4d1035a9c..aba623ec60d9af914e8ec411566699fa9b2dce7c 100644 (file)
--- a/bind.c
+++ b/bind.c
@@ -13,6 +13,8 @@
  *-------
  */
 
+#include <stdlib.h>
+#include <string.h>
 #include "bind.h"
 
 #include "environ.h"
@@ -20,8 +22,7 @@
 #include "descriptor.h"
 #include "qresult.h"
 #include "pgtypes.h"
-#include <stdlib.h>
-#include <string.h>
+#include "multibyte.h"
 
 #include "pgapifunc.h"
 
@@ -34,11 +35,11 @@ PGAPI_BindParameter(
                    SQLSMALLINT fParamType,
                    SQLSMALLINT fCType,
                    SQLSMALLINT fSqlType,
-                   SQLUINTEGER cbColDef,
+                   SQLULEN cbColDef,
                    SQLSMALLINT ibScale,
                    PTR rgbValue,
-                   SQLINTEGER cbValueMax,
-                   SQLINTEGER *pcbValue)
+                   SQLLEN cbValueMax,
+                   SQLLEN FAR * pcbValue)
 {
    StatementClass *stmt = (StatementClass *) hstmt;
    CSTR func = "PGAPI_BindParameter";
@@ -71,7 +72,7 @@ PGAPI_BindParameter(
    /* store the given info */
    apdopts->parameters[ipar].buflen = cbValueMax;
    apdopts->parameters[ipar].buffer = rgbValue;
-   apdopts->parameters[ipar].used = (Int4 *) pcbValue;
+   apdopts->parameters[ipar].used = pcbValue;
    apdopts->parameters[ipar].CType = fCType;
    ipdopts->parameters[ipar].SQLType = fSqlType;
    ipdopts->parameters[ipar].paramType = fParamType;
@@ -79,8 +80,9 @@ PGAPI_BindParameter(
    ipdopts->parameters[ipar].decimal_digits = ibScale;
    ipdopts->parameters[ipar].precision = 0;
    ipdopts->parameters[ipar].scale = 0;
-   ipdopts->parameters[ipar].PGType = sqltype_to_pgtype(stmt, fSqlType);
-
+   if (0 == ipdopts->parameters[ipar].PGType)
+       ipdopts->parameters[ipar].PGType = sqltype_to_pgtype(stmt, fSqlType);
+#if (ODBCVER >= 0x0300)
    switch (fCType)
    {
        case SQL_C_NUMERIC:
@@ -96,6 +98,7 @@ PGAPI_BindParameter(
    }
    apdopts->parameters[ipar].precision = ipdopts->parameters[ipar].precision;
    apdopts->parameters[ipar].scale = ipdopts->parameters[ipar].scale;
+#endif /* ODBCVER */
 
    /*
     * If rebinding a parameter that had data-at-exec stuff in it, then
@@ -115,18 +118,23 @@ PGAPI_BindParameter(
 
    if (pcbValue && apdopts->param_offset_ptr)
        pcbValue += (*apdopts->param_offset_ptr >> 2);
+#ifdef NOT_USED /* evaluation of pcbValue here is dangerous */
    /* Data at exec macro only valid for C char/binary data */
    if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC ||
                     *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET))
        apdopts->parameters[ipar].data_at_exec = TRUE;
    else
        apdopts->parameters[ipar].data_at_exec = FALSE;
+#endif /* NOT_USED */
 
    /* Clear premature result */
    if (stmt->status == STMT_PREMATURE)
        SC_recycle_statement(stmt);
 
-   mylog("PGAPI_BindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue : -777, apdopts->parameters[ipar].data_at_exec);
+   mylog("%s: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d,", func, ipar, fParamType, fCType, fSqlType, cbColDef, ibScale);
+   /*** mylog("rgbValue=%x, pcbValue = %x(%d), data_at_exec = %d\n", rgbValue, pcbValue, pcbValue ? *pcbValue : -777, apdopts->parameters[ipar].data_at_exec); ***/
+
+   mylog("rgbValue=%x, pcbValue = %x, data_at_exec = %d\n", rgbValue, pcbValue, apdopts->parameters[ipar].data_at_exec);
 
    return SQL_SUCCESS;
 }
@@ -135,22 +143,23 @@ PGAPI_BindParameter(
 /* Associate a user-supplied buffer with a database column. */
 RETCODE        SQL_API
 PGAPI_BindCol(
-           HSTMT hstmt,
-           SQLUSMALLINT icol, 
-           SQLSMALLINT fCType,
-           PTR rgbValue, 
-           SQLINTEGER cbValueMax,
-           SQLINTEGER *pcbValue)
+             HSTMT hstmt,
+             SQLUSMALLINT icol,
+             SQLSMALLINT fCType,
+             PTR rgbValue,
+             SQLLEN cbValueMax,
+             SQLLEN FAR * pcbValue)
 {
    StatementClass *stmt = (StatementClass *) hstmt;
    CSTR func = "PGAPI_BindCol";
    ARDFields   *opts;
    GetDataInfo *gdata_info;
    BindInfoClass   *bookmark;
+   RETCODE     ret = SQL_SUCCESS;
 
    mylog("%s: entering...\n", func);
 
-   mylog("**** PGAPI_BindCol: stmt = %u, icol = %d\n", stmt, icol);
+   mylog("**** PGAPI_BindCol: stmt = %x, icol = %d\n", stmt, icol);
    mylog("**** : fCType=%d rgb=%x valusMax=%d pcb=%x\n", fCType, rgbValue, cbValueMax, pcbValue);
 
    if (!stmt)
@@ -162,12 +171,13 @@ PGAPI_BindCol(
    opts = SC_get_ARDF(stmt);
    if (stmt->status == STMT_EXECUTING)
    {
-       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't bind columns while statement is still executing.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't bind columns while statement is still executing.", func);
        return SQL_ERROR;
    }
 
+#define    return  DONT_CALL_RETURN_FROM_HERE ???
    SC_clear_error(stmt);
+   /* StartRollbackState(stmt); */
    /* If the bookmark column is being bound, then just save it */
    if (icol == 0)
    {
@@ -186,23 +196,24 @@ PGAPI_BindCol(
            switch (fCType)
            {
                case SQL_C_BOOKMARK:
+#if (ODBCVER >= 0x0300)
                case SQL_C_VARBOOKMARK:
-
+#endif /* ODBCVER */
                    break;
                default:
-                   SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Bind column 0 is not of type SQL_C_BOOKMARK");
-                    mylog("Bind column 0 is type %d not of type SQL_C_BOOKMARK\n", fCType);
-                   SC_log_error(func, "", stmt);
-                   return SQL_ERROR;
+                   SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Bind column 0 is not of type SQL_C_BOOKMARK", func);
+inolog("Bind column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
+                   ret = SQL_ERROR;
+                   goto cleanup;
            }
 
            bookmark = ARD_AllocBookmark(opts);
            bookmark->buffer = rgbValue;
-           bookmark->used = (Int4 *) pcbValue;
+           bookmark->used = pcbValue;
            bookmark->buflen = cbValueMax;
            bookmark->returntype = fCType;
        }
-       return SQL_SUCCESS;
+       goto cleanup;
    }
 
    /*
@@ -219,9 +230,9 @@ PGAPI_BindCol(
    /* check to see if the bindings were allocated */
    if (!opts->bindings)
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for bindings.");
-       SC_log_error(func, "", stmt);
-       return SQL_ERROR;
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for bindings.", func);
+       ret = SQL_ERROR;
+       goto cleanup;
    }
 
    /* use zero based col numbers from here out */
@@ -250,19 +261,24 @@ PGAPI_BindCol(
        /* ok, bind that column */
        opts->bindings[icol].buflen = cbValueMax;
        opts->bindings[icol].buffer = rgbValue;
-       opts->bindings[icol].used = (Int4 *) pcbValue;
+       opts->bindings[icol].used = pcbValue;
        opts->bindings[icol].returntype = fCType;
-
+#if (ODBCVER >= 0x0300)
        if (SQL_C_NUMERIC == fCType)
            opts->bindings[icol].precision = 32;
        else
+#endif /* ODBCVER */
            opts->bindings[icol].precision = 0;
        opts->bindings[icol].scale = 0;
 
-       mylog("       bound buffer[%d] = %u\n", icol, opts->bindings[icol].buffer);
+       mylog("       bound buffer[%d] = %x\n", icol, opts->bindings[icol].buffer);
    }
 
-   return SQL_SUCCESS;
+cleanup:
+#undef return
+   if (stmt->internal)
+       ret = DiscardStatementSvp(stmt, ret, FALSE);
+   return ret;
 }
 
 
@@ -275,19 +291,21 @@ PGAPI_BindCol(
  * data type (most likely varchar).
  */
 RETCODE        SQL_API
-PGAPI_DescribeParam(HSTMT hstmt,
-           SQLUSMALLINT ipar,
-           SQLSMALLINT *pfSqlType,
-           SQLUINTEGER *pcbColDef,
-           SQLSMALLINT *pibScale,
-           SQLSMALLINT *pfNullable)
+PGAPI_DescribeParam(
+                   HSTMT hstmt,
+                   SQLUSMALLINT ipar,
+                   SQLSMALLINT FAR * pfSqlType,
+                   SQLULEN FAR * pcbParamDef,
+                   SQLSMALLINT FAR * pibScale,
+                   SQLSMALLINT FAR * pfNullable)
 {
    StatementClass *stmt = (StatementClass *) hstmt;
    CSTR func = "PGAPI_DescribeParam";
    APDFields   *apdopts;
    IPDFields   *ipdopts;
+   RETCODE     ret = SQL_SUCCESS;
 
-   mylog("%s: entering...\n", func);
+   mylog("%s: entering...%d\n", func, ipar);
 
    if (!stmt)
    {
@@ -297,42 +315,81 @@ PGAPI_DescribeParam(HSTMT hstmt,
    SC_clear_error(stmt);
 
    apdopts = SC_get_APDF(stmt);
-   if ((ipar < 1) || (ipar > apdopts->allocated))
+   ipdopts = SC_get_IPDF(stmt);
+   /*if ((ipar < 1) || (ipar > ipdopts->allocated))*/
+   if ((ipar < 1) || (ipar > stmt->num_params))
    {
-       SC_set_error(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR, "Invalid parameter number for PGAPI_DescribeParam.");
-       SC_log_error(func, "", stmt);
+inolog("num_params=%d\n", stmt->num_params);
+       SC_set_error(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR, "Invalid parameter number for PGAPI_DescribeParam.", func);
        return SQL_ERROR;
    }
-   ipdopts = SC_get_IPDF(stmt);
+   extend_iparameter_bindings(ipdopts, stmt->num_params);
 
-   ipar--;
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
+   if (NOT_YET_PREPARED == stmt->prepared)
+   {
+       decideHowToPrepare(stmt);
+inolog("howTo=%d\n", SC_get_prepare_method(stmt));
+       switch (SC_get_prepare_method(stmt))
+       {
+           case USING_PARSE_REQUEST:
+           case USING_UNNAMED_PARSE_REQUEST:
+               if (ret = prepareParameters(stmt), SQL_ERROR == ret)
+                   goto cleanup;
+       }
+   }
 
+   ipar--;
    /*
     * This implementation is not very good, since it is supposed to
     * describe
     */
    /* parameter markers, not bound parameters.  */
    if (pfSqlType)
-       *pfSqlType = ipdopts->parameters[ipar].SQLType;
+   {
+inolog("[%d].SQLType=%d .PGType=%d\n", ipar, ipdopts->parameters[ipar].SQLType,
+ipdopts->parameters[ipar].PGType);
+       if (ipdopts->parameters[ipar].SQLType)
+           *pfSqlType = ipdopts->parameters[ipar].SQLType;
+       else if (ipdopts->parameters[ipar].PGType)
+           *pfSqlType = pgtype_to_concise_type(stmt, ipdopts->parameters[ipar].PGType, PG_STATIC);
+   }
 
-   if (pcbColDef)
-       *pcbColDef = ipdopts->parameters[ipar].column_size;
+   if (pcbParamDef)
+   {
+       *pcbParamDef = 0;
+       if (ipdopts->parameters[ipar].SQLType)
+           *pcbParamDef = ipdopts->parameters[ipar].column_size;
+       if (0 == *pcbParamDef && ipdopts->parameters[ipar].PGType)
+           *pcbParamDef = pgtype_column_size(stmt, ipdopts->parameters[ipar].PGType, PG_STATIC, PG_STATIC);
+   }
 
    if (pibScale)
-       *pibScale = ipdopts->parameters[ipar].decimal_digits;
+   {
+       *pibScale = 0;
+       if (ipdopts->parameters[ipar].SQLType)
+           *pibScale = ipdopts->parameters[ipar].decimal_digits;
+       else if (ipdopts->parameters[ipar].PGType)
+           *pibScale = pgtype_scale(stmt, ipdopts->parameters[ipar].PGType, -1);
+   }
 
    if (pfNullable)
        *pfNullable = pgtype_nullable(stmt, ipdopts->parameters[ipar].paramType);
-
-   return SQL_SUCCESS;
+cleanup:
+#undef return
+   if (stmt->internal)
+       ret = DiscardStatementSvp(stmt, ret, FALSE);
+   return ret;
 }
 
 
 /* Sets multiple values (arrays) for the set of parameter markers. */
 RETCODE        SQL_API
-PGAPI_ParamOptions(HSTMT hstmt,
-          SQLUINTEGER crow,
-          SQLUINTEGER *pirow)
+PGAPI_ParamOptions(
+                  HSTMT hstmt,
+                  SQLULEN crow,
+                  SQLULEN FAR * pirow)
 {
    CSTR func = "PGAPI_ParamOptions";
    StatementClass *stmt = (StatementClass *) hstmt;
@@ -359,12 +416,11 @@ PGAPI_ParamOptions(HSTMT hstmt,
 RETCODE        SQL_API
 PGAPI_NumParams(
                HSTMT hstmt,
-               SWORD FAR * pcpar)
+               SQLSMALLINT FAR * pcpar)
 {
    StatementClass *stmt = (StatementClass *) hstmt;
-   char        in_quote = FALSE;
-   unsigned int i;
    CSTR func = "PGAPI_NumParams";
+   char    literal_quote = LITERAL_QUOTE, identifier_quote = IDENTIFIER_QUOTE, escape_in_literal = ESCAPE_IN_LITERAL, dollar_quote = '$';
 
    mylog("%s: entering...\n", func);
 
@@ -378,34 +434,105 @@ PGAPI_NumParams(
        *pcpar = 0;
    else
    {
-       SC_log_error(func, "pcpar was null", stmt);
+       SC_set_error(stmt, STMT_EXEC_ERROR, "parameter count address is null", func);
        return SQL_ERROR;
    }
-
-
+inolog("num_params=%d,%d\n", stmt->num_params, stmt->proc_return);
    if (stmt->num_params >= 0)
        *pcpar = stmt->num_params;
    else if (!stmt->statement)
    {
        /* no statement has been allocated */
-       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "PGAPI_NumParams called with no statement ready.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "PGAPI_NumParams called with no statement ready.", func);
        return SQL_ERROR;
    }
    else
    {
-       for (i = 0; i < strlen(stmt->statement); i++)
+       const   char *sptr, *tag = NULL;
+       int taglen;
+       char    tchar, bchar;
+       char    in_literal = FALSE, in_identifier = FALSE,
+           in_dollar_quote = FALSE, in_escape = FALSE,
+           multi = FALSE, del_found = FALSE;
+       encoded_str encstr;
+
+       stmt->proc_return = 0;
+       make_encoded_str(&encstr, SC_get_conn(stmt), stmt->statement);
+       for (sptr = stmt->statement, bchar = '\0'; *sptr; sptr++)
        {
-           if (stmt->statement[i] == '?' && !in_quote)
-               (*pcpar)++;
+           tchar = encoded_nextchar(&encstr);
+           if (ENCODE_STATUS(encstr) != 0) /* multibyte char */
+           {
+               bchar = tchar;
+               continue;
+           }
+           if (!multi && del_found)
+           {
+               if (!isspace(tchar))
+                   multi = TRUE;
+           }
+           if (in_dollar_quote)
+           {
+               if (tchar == dollar_quote)
+               {
+                   if (strncmp(sptr, tag, taglen) == 0)
+                   {
+                       in_dollar_quote = FALSE;
+                       tag = NULL;
+                       sptr += taglen;
+                       sptr--;
+                   }
+               }
+           }
+           else if (in_literal)
+           {
+               if (in_escape)
+                   in_escape = FALSE;
+               else if (tchar == escape_in_literal)
+                   in_escape = TRUE;
+               else if (tchar == literal_quote)
+                   in_literal = FALSE;
+           }
+           else if (in_identifier)
+           {
+               if (tchar == identifier_quote)
+                   in_identifier = FALSE;
+           }
            else
            {
-               if (stmt->statement[i] == '\'')
-                   in_quote = (in_quote ? FALSE : TRUE);
+               if (tchar == '?')
+               {
+                   if (0 == *pcpar && bchar == '{')
+                       stmt->proc_return = 1;
+                   (*pcpar)++;
+               }
+               else if (tchar == ';')
+                   del_found = TRUE;
+               else if (tchar == dollar_quote)
+               {
+                   char    *dollar_next;
+
+                   in_dollar_quote = TRUE;
+                   tag = sptr;
+                   taglen = 0; 
+                   if (dollar_next = strchr(sptr + 1, dollar_quote))
+                   {
+                       taglen = dollar_next - sptr + 1;
+                       sptr = dollar_next;
+                   }
+               }
+               else if (tchar == literal_quote)
+                   in_literal = TRUE;
+               else if (tchar == identifier_quote)
+                   in_identifier = TRUE;
+               if (!isspace(tchar))
+                   bchar = tchar;
            }
        }
        stmt->num_params = *pcpar;
+       stmt->multi_statement = multi;
    }
+inolog("num_params=%d,%d\n", stmt->num_params, stmt->proc_return);
    return SQL_SUCCESS;
 }
 
@@ -439,7 +566,7 @@ extend_parameter_bindings(APDFields *self, int num_params)
    CSTR func = "extend_parameter_bindings";
    ParameterInfoClass *new_bindings;
 
-   mylog("%s: entering ... self=%u, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
+   mylog("%s: entering ... self=%x, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
 
    /*
     * if we have too few, allocate room for more, and copy the old
@@ -472,7 +599,7 @@ extend_iparameter_bindings(IPDFields *self, int num_params)
    CSTR func = "extend_iparameter_bindings";
    ParameterImplClass *new_bindings;
 
-   mylog("%s: entering ... self=%u, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
+   mylog("%s: entering ... self=%x, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
 
    /*
     * if we have too few, allocate room for more, and copy the old
@@ -504,7 +631,7 @@ reset_a_parameter_binding(APDFields *self, int ipar)
 {
    CSTR func = "reset_a_parameter_binding";
 
-   mylog("%s: entering ... self=%u, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar);
+   mylog("%s: entering ... self=%x, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar);
 
    if (ipar < 1 || ipar > self->allocated)
        return;
@@ -524,18 +651,64 @@ reset_a_iparameter_binding(IPDFields *self, int ipar)
 {
    CSTR func = "reset_a_iparameter_binding";
 
-   mylog("%s: entering ... self=%u, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar);
+   mylog("%s: entering ... self=%x, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar);
 
    if (ipar < 1 || ipar > self->allocated)
        return;
 
    ipar--;
+   NULL_THE_NAME(self->parameters[ipar].paramName);
    self->parameters[ipar].paramType = 0;
    self->parameters[ipar].SQLType = 0;
    self->parameters[ipar].column_size = 0;
    self->parameters[ipar].decimal_digits = 0;
    self->parameters[ipar].precision = 0;
    self->parameters[ipar].scale = 0;
+   self->parameters[ipar].PGType = 0;
+}
+
+int
+CountParameters(const StatementClass *self, Int2 *inputCount, Int2 *ioCount, Int2 *outputCount)
+{
+   CSTR func = "CountParameters";
+   IPDFields   *ipdopts = SC_get_IPDF(self);
+   int i, num_params, valid_count;
+
+   if (inputCount)
+       *inputCount = 0;
+   if (ioCount)
+       *ioCount = 0;
+   if (outputCount)
+       *outputCount = 0;
+   if (!ipdopts)   return -1;
+   num_params = self->num_params;
+   if (ipdopts->allocated < num_params)
+       num_params = ipdopts->allocated;
+   for (i = 0, valid_count = 0; i < num_params; i++)
+   {
+       if (SQL_PARAM_OUTPUT == ipdopts->parameters[i].paramType)
+       {
+           if (outputCount)
+           {
+               (*outputCount)++;
+               valid_count++;
+           }
+       }
+       else if (SQL_PARAM_INPUT_OUTPUT == ipdopts->parameters[i].paramType)
+       {
+           if (ioCount)
+           {
+               (*ioCount)++;
+               valid_count++;
+           }
+       }
+       else if (inputCount)
+       {
+            (*inputCount)++;
+           valid_count++;
+       }
+   }
+   return valid_count;
 }
 
 /*
@@ -564,7 +737,7 @@ PDATA_free_params(PutDataInfo *pdata, char option)
 {
    int         i;
 
-   mylog("PDATA_free_params:  ENTER, self=%d\n", pdata);
+   mylog("PDATA_free_params:  ENTER, self=%x\n", pdata);
 
    if (!pdata->pdata)
        return;
@@ -599,7 +772,7 @@ PDATA_free_params(PutDataInfo *pdata, char option)
 void
 IPD_free_params(IPDFields *ipdopts, char option)
 {
-   mylog("IPD_free_params:  ENTER, self=%d\n", ipdopts);
+   mylog("IPD_free_params:  ENTER, self=%x\n", ipdopts);
 
    if (!ipdopts->parameters)
        return;
@@ -620,7 +793,7 @@ extend_column_bindings(ARDFields *self, int num_columns)
    BindInfoClass *new_bindings;
    int         i;
 
-   mylog("%s: entering ... self=%u, bindings_allocated=%d, num_columns=%d\n", func, self, self->allocated, num_columns);
+   mylog("%s: entering ... self=%x, bindings_allocated=%d, num_columns=%d\n", func, self, self->allocated, num_columns);
 
    /*
     * if we have too few, allocate room for more, and copy the old
@@ -673,7 +846,7 @@ reset_a_column_binding(ARDFields *self, int icol)
    CSTR func = "reset_a_column_binding";
    BindInfoClass   *bookmark;
 
-   mylog("%s: entering ... self=%u, bindings_allocated=%d, icol=%d\n", func, self, self->allocated, icol);
+   mylog("%s: entering ... self=%x, bindings_allocated=%d, icol=%d\n", func, self, self->allocated, icol);
 
    if (icol > self->allocated)
        return;
@@ -703,7 +876,7 @@ void    ARD_unbind_cols(ARDFields *self, BOOL freeall)
 {
    Int2    lf;
 
-    mylog("ARD_unbind_cols freeall=%d allocated=%d bindings=%x\n", freeall, self->allocated, self->bindings);
+inolog("ARD_unbind_cols freeall=%d allocated=%d bindings=%x", freeall, self->allocated, self->bindings);
    for (lf = 1; lf <= self->allocated; lf++)
        reset_a_column_binding(self, lf);
    if (freeall)
@@ -718,7 +891,7 @@ void    GDATA_unbind_cols(GetDataInfo *self, BOOL freeall)
 {
    Int2    lf;
 
-    mylog("GDATA_unbind_cols freeall=%d allocated=%d gdata=%x\n", freeall, self->allocated, self->gdata);
+inolog("GDATA_unbind_cols freeall=%d allocated=%d gdata=%x", freeall, self->allocated, self->gdata);
    if (self->fdata.ttlbuf)
    {
        free(self->fdata.ttlbuf);
@@ -772,7 +945,7 @@ extend_getdata_info(GetDataInfo *self, int num_columns, BOOL shrink)
    GetDataClass    *new_gdata;
    int         i;
 
-   mylog("%s: entering ... self=%u, gdata_allocated=%d, num_columns=%d\n", func, self, self->allocated, num_columns);
+   mylog("%s: entering ... self=%x, gdata_allocated=%d, num_columns=%d\n", func, self, self->allocated, num_columns);
 
    /*
     * if we have too few, allocate room for more, and copy the old
@@ -848,7 +1021,7 @@ extend_putdata_info(PutDataInfo *self, int num_params, BOOL shrink)
    CSTR func = "extend_putdata_info";
    PutDataClass    *new_pdata;
 
-   mylog("%s: entering ... self=%u, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
+   mylog("%s: entering ... self=%x, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
 
    /*
     * if we have too few, allocate room for more, and copy the old
@@ -856,6 +1029,11 @@ extend_putdata_info(PutDataInfo *self, int num_params, BOOL shrink)
     */
    if (self->allocated < num_params)
    {
+       if (self->allocated <= 0 && self->pdata)
+       {
+           mylog("??? pdata is not null while allocated == 0\n");
+           self->pdata = NULL; 
+       }
        new_pdata = (PutDataClass *) realloc(self->pdata, sizeof(PutDataClass) * num_params);
        if (!new_pdata)
        {
@@ -904,3 +1082,34 @@ void  reset_a_putdata_info(PutDataInfo *pdata_info, int ipar)
    }
    pdata_info->pdata[ipar].lobj_oid = 0;
 }
+
+void SC_param_next(const StatementClass *stmt, int *param_number, ParameterInfoClass **apara, ParameterImplClass **ipara)
+{
+   int next;
+   IPDFields   *ipdopts = SC_get_IPDF(stmt);
+
+   if (*param_number < 0)
+       next = stmt->proc_return;
+   else
+       next = *param_number + 1;
+   if (stmt->discard_output_params)
+   {
+       for (;next < ipdopts->allocated && SQL_PARAM_OUTPUT == ipdopts->parameters[next].paramType; next++) ;
+   }
+   *param_number = next;
+   if (ipara)
+   {
+       if (next < ipdopts->allocated)
+           *ipara = ipdopts->parameters + next;
+       else
+           *ipara = NULL;
+   }
+   if (apara)
+   {
+       APDFields   *apdopts = SC_get_APDF(stmt);
+       if (next < apdopts->allocated)
+           *apara = apdopts->parameters + next;
+       else
+           *apara = NULL;
+   }
+}
diff --git a/bind.h b/bind.h
index e7d5b15ef43ea97580d6012d4cca72226e9ef614..b67ef20a068e2b9f9f34041e40016f4525ccce83 100644 (file)
--- a/bind.h
+++ b/bind.h
 #define __BIND_H__
 
 #include "psqlodbc.h"
-#include <libpq-fe.h>
+#include "descriptor.h"
 
 /*
  * BindInfoClass -- stores information about a bound column
  */
 struct BindInfoClass_
 {
-   Int4    buflen;         /* size of buffer */
+   SQLLEN  buflen;         /* size of buffer */
    char    *buffer;        /* pointer to the buffer */
-   Int4    *used;          /* used space in the buffer (for strings
+   SQLLEN  *used;          /* used space in the buffer (for strings
                     * not counting the '\0') */
    Int2    returntype;     /* kind of conversion to be applied when
                     * returning (SQL_C_DEFAULT,
@@ -32,9 +32,9 @@ struct BindInfoClass_
 typedef struct
 {
    char    *ttlbuf;        /* to save the large result */
-   Int4    ttlbuflen;      /* the buffer length */
-   Int4    ttlbufused;     /* used length of the buffer */
-   Int4    data_left;      /* amount of data left to read
+   SQLLEN  ttlbuflen;      /* the buffer length */
+   SQLLEN  ttlbufused;     /* used length of the buffer */
+   SQLLEN  data_left;      /* amount of data left to read
                     * (SQLGetData) */
 }  GetDataClass;
 
@@ -43,9 +43,9 @@ typedef struct
  */
 struct ParameterInfoClass_
 {
-   Int4    buflen;
+   SQLLEN  buflen;
    char    *buffer;
-   Int4    *used;
+   SQLLEN  *used;
    Int2    CType;
    Int2    precision;  /* the precision for numeric or timestamp type */
    Int2    scale;      /* the scale for numeric type */
@@ -55,7 +55,7 @@ struct ParameterInfoClass_
 
 typedef struct 
 {
-   Int4    *EXEC_used; /* amount of data */
+   SQLLEN  *EXEC_used; /* amount of data */
    char    *EXEC_buffer;   /* the data */
    Oid lobj_oid;
 }  PutDataClass;
@@ -65,10 +65,11 @@ typedef struct
  */
 struct ParameterImplClass_
 {
+   pgNAME      paramName;  /* this is unavailable even in 8.1 */
    Int2        paramType;
    Int2        SQLType;
    Int4        PGType;
-   UInt4       column_size;
+   SQLULEN     column_size;
    Int2        decimal_digits;
    Int2        precision;  /* the precision for numeric or timestamp type */
    Int2        scale;      /* the scale for numeric type */
@@ -92,6 +93,7 @@ void  extend_parameter_bindings(APDFields *opts, int num_params);
 void   extend_iparameter_bindings(IPDFields *opts, int num_params);
 void   reset_a_parameter_binding(APDFields *opts, int ipar);
 void   reset_a_iparameter_binding(IPDFields *opts, int ipar);
+int    CountParameters(const StatementClass *stmt, Int2 *inCount, Int2 *ioCount, Int2 *outputCount);
 void   GetDataInfoInitialize(GetDataInfo *gdata);
 void   extend_getdata_info(GetDataInfo *gdata, int num_columns, BOOL shrink);
 void   reset_a_getdata_info(GetDataInfo *gdata, int icol);
@@ -100,5 +102,9 @@ void    PutDataInfoInitialize(PutDataInfo *pdata);
 void   extend_putdata_info(PutDataInfo *pdata, int num_params, BOOL shrink);
 void   reset_a_putdata_info(PutDataInfo *pdata, int ipar);
 void   PDATA_free_params(PutDataInfo *pdata, char option);
+void   SC_param_next(const StatementClass*, int *param_number, ParameterInfoClass **, ParameterImplClass **);
+
+RETCODE       prepareParameters(StatementClass *stmt);
+void   decideHowToPrepare(StatementClass *stmt);
 
 #endif
diff --git a/catfunc.h b/catfunc.h
new file mode 100644 (file)
index 0000000..09ad69d
--- /dev/null
+++ b/catfunc.h
@@ -0,0 +1,93 @@
+/* File:           catfunc.h
+ *
+ * Description:        See "info.c"
+ *
+ * Comments:       See "notice.txt" for copyright and license information.
+ *
+ */
+
+#ifndef __CATFUNC_H__
+#define __CATFUNC_H__
+
+#include "psqlodbc.h"
+
+/* SQLColumns field position   */
+enum {
+   COLUMNS_CATALOG_NAME    =   0
+   ,COLUMNS_SCHEMA_NAME
+   ,COLUMNS_TABLE_NAME
+   ,COLUMNS_COLUMN_NAME
+   ,COLUMNS_DATA_TYPE
+   ,COLUMNS_TYPE_NAME
+   ,COLUMNS_PRECISION
+   ,COLUMNS_LENGTH
+   ,COLUMNS_SCALE
+   ,COLUMNS_RADIX
+   ,COLUMNS_NULLABLE
+   ,COLUMNS_REMARKS
+#if (ODBCVER >= 0x0300)
+   ,COLUMNS_COLUMN_DEF
+   ,COLUMNS_SQL_DATA_TYPE
+   ,COLUMNS_SQL_DATETIME_SUB
+   ,COLUMNS_CHAR_OCTET_LENGTH
+   ,COLUMNS_ORDINAL_POSITION
+   ,COLUMNS_IS_NULLABLE
+#endif /* ODBCVER */
+   ,COLUMNS_DISPLAY_SIZE
+   ,COLUMNS_FIELD_TYPE
+   ,COLUMNS_AUTO_INCREMENT
+   ,COLUMNS_LAST = COLUMNS_AUTO_INCREMENT
+};
+/* SQLForeignKeys field position   */
+enum {
+   FKS_PKTABLE_CAT =   0
+   ,FKS_PKTABLE_SCHEM
+   ,FKS_PKTABLE_NAME
+   ,FKS_PKCOLUMN_NAME
+   ,FKS_FKTABLE_CAT
+   ,FKS_FKTABLE_SCHEM
+   ,FKS_FKTABLE_NAME
+   ,FKS_FKCOLUMN_NAME
+   ,FKS_KEY_SEQ
+   ,FKS_UPDATE_RULE
+   ,FKS_DELETE_RULE
+   ,FKS_FK_NAME
+   ,FKS_PK_NAME
+#if (ODBCVER >= 0x0300)
+   ,FKS_DEFERRABILITY
+#endif /* ODBCVER */
+   ,FKS_TRIGGER_NAME
+   ,FKS_LAST = FKS_TRIGGER_NAME
+};
+/* SQLColAttribute */
+enum {
+   COLATTR_DESC_COUNT = -1
+   ,COLATTR_DESC_AUTO_UNIQUE_VALUE = 0
+   ,COLATTR_DESC_BASE_COLUMN_NAME
+   ,COLATTR_DESC_BASE_TABLE_NAME
+   ,COLATTR_DESC_CASE_SENSITIVE
+   ,COLATTR_DESC_CATALOG_NAME
+   ,COLATTR_DESC_CONCISE_TYPE
+   ,COLATTR_DESC_DISPLAY_SIZE
+   ,COLATTR_DESC_FIXED_PREC_SCALE
+   ,COLATTR_DESC_LABEL
+   ,COLATTR_DESC_LENGTH
+   ,COLATTR_DESC_LITERAL_PREFIX
+   ,COLATTR_DESC_LITERAL_SUFFIX
+   ,COLATTR_DESC_LOCAL_TYPE_NAME
+   ,COLATTR_DESC_NAME
+   ,COLATTR_DESC_NULLABLE
+   ,COLATTR_DESC_NUM_PREX_RADIX
+   ,COLATTR_DESC_OCTET_LENGTH
+   ,COLATTR_DESC_PRECISION
+   ,COLATTR_DESC_SCALE
+   ,COLATTR_DESC_SCHEMA_NAME
+   ,COLATTR_DESC_SEARCHABLE
+   ,COLATTR_DESC_TABLE_NAME
+   ,COLATTR_DESC_TYPE
+   ,COLATTR_DESC_TYPE_NAME
+   ,COLATTR_DESC_UNNAMED
+   ,COLATTR_DESC_UNSIGNED
+   ,COLATTR_DESC_UPDATABLE
+};
+#endif /* __CARFUNC_H__ */
index c0ddf0c7894f3833c399d0c0af4f6794374f2f8f..32acbf8311389c8d06e0eecc1cf388d44978612d 100644 (file)
@@ -14,7 +14,9 @@
 
 #include "pgtypes.h"
 #include "columninfo.h"
+
 #include "connection.h"
+#include "socket.h"
 #include <stdlib.h>
 #include <string.h>
 #include "pgapifunc.h"
@@ -34,6 +36,8 @@ CI_Constructor()
        rv->adtsize = NULL;
        rv->display_size = NULL;
        rv->atttypmod = NULL;
+       rv->relid = NULL;
+       rv->attid = NULL;
    }
 
    return rv;
@@ -48,44 +52,142 @@ CI_Destructor(ColumnInfoClass *self)
    free(self);
 }
 
+
+/*
+ * Read in field descriptions.
+ * If self is not null, then also store the information.
+ * If self is null, then just read, don't store.
+ */
+char
+CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn)
+{
+   CSTR        func = "CI_read_fields";
+   Int2        lf;
+   int         new_num_fields;
+   Oid     new_adtid, new_relid = 0, new_attid = 0;
+   Int2        new_adtsize;
+   Int4        new_atttypmod = -1;
+
+   /* COLUMN_NAME_STORAGE_LEN may be sufficient but for safety */
+   char        new_field_name[2 * COLUMN_NAME_STORAGE_LEN + 1];
+   SocketClass *sock;
+   ConnInfo   *ci;
+
+   sock = CC_get_socket(conn);
+   ci = &conn->connInfo;
+
+   /* at first read in the number of fields that are in the query */
+   new_num_fields = (Int2) SOCK_get_int(sock, sizeof(Int2));
+
+   mylog("num_fields = %d\n", new_num_fields);
+
+   if (self)
+       /* according to that allocate memory */
+       CI_set_num_fields(self, new_num_fields, PROTOCOL_74(ci));
+
+   /* now read in the descriptions */
+   for (lf = 0; lf < new_num_fields; lf++)
+   {
+       SOCK_get_string(sock, new_field_name, 2 * COLUMN_NAME_STORAGE_LEN);
+       if (PROTOCOL_74(ci))    /* tableid & columnid */
+       {
+           new_relid = SOCK_get_int(sock, sizeof(Int4));
+           new_attid = SOCK_get_int(sock, sizeof(Int2));
+       }
+       new_adtid = (Oid) SOCK_get_int(sock, 4);
+       new_adtsize = (Int2) SOCK_get_int(sock, 2);
+
+       /* If 6.4 protocol, then read the atttypmod field */
+       if (PG_VERSION_GE(conn, 6.4))
+       {
+           mylog("READING ATTTYPMOD\n");
+           new_atttypmod = (Int4) SOCK_get_int(sock, 4);
+
+           /* Subtract the header length */
+           switch (new_adtid)
+           {
+               case PG_TYPE_DATETIME:
+               case PG_TYPE_TIMESTAMP_NO_TMZONE:
+               case PG_TYPE_TIME:
+               case PG_TYPE_TIME_WITH_TMZONE:
+                   break;
+               default:
+                   new_atttypmod -= 4;
+           }
+           if (new_atttypmod < 0)
+               new_atttypmod = -1;
+           if (PROTOCOL_74(ci))    /* format */
+               SOCK_get_int(sock, sizeof(Int2));
+
+       }
+
+       mylog("%s: fieldname='%s', adtid=%d, adtsize=%d, atttypmod=%d (rel,att)=(%d,%d)\n", func, new_field_name, new_adtid, new_adtsize, new_atttypmod, new_relid, new_attid);
+
+       if (self)
+           CI_set_field_info(self, lf, new_field_name, new_adtid, new_adtsize, new_atttypmod, new_relid, new_attid);
+   }
+
+   return (SOCK_get_errcode(sock) == 0);
+}
+
+
 void
 CI_free_memory(ColumnInfoClass *self)
 {
    register Int2 lf;
    int         num_fields = self->num_fields;
 
-   for (lf = 0; lf < num_fields; lf++)
+   if (self->name)
    {
-       if (self->name[lf])
+       for (lf = 0; lf < num_fields; lf++)
        {
-           free(self->name[lf]);
-           self->name[lf] = NULL;
+           if (self->name[lf])
+           {
+               free(self->name[lf]);
+               self->name[lf] = NULL;
+           }
        }
+       free(self->name);
+       self->name = NULL;
    }
-
    /* Safe to call even if null */
    self->num_fields = 0;
-   if (self->name)
-       free(self->name);
-   self->name = NULL;
+
    if (self->adtid)
+   {
        free(self->adtid);
-   self->adtid = NULL;
+       self->adtid = NULL;
+   }
    if (self->adtsize)
+   {
        free(self->adtsize);
-   self->adtsize = NULL;
+       self->adtsize = NULL;
+   }
    if (self->display_size)
+   {
        free(self->display_size);
-   self->display_size = NULL;
-
+       self->display_size = NULL;
+   }
    if (self->atttypmod)
+   {
        free(self->atttypmod);
-   self->atttypmod = NULL;
+       self->atttypmod = NULL;
+   }
+   if (self->relid)
+   {
+       free(self->relid);
+       self->relid = NULL;
+   }
+   if (self->attid)
+   {
+       free(self->attid);
+       self->attid = NULL;
+   }
 }
 
 
 void
-CI_set_num_fields(ColumnInfoClass *self, int new_num_fields)
+CI_set_num_fields(ColumnInfoClass *self, int new_num_fields, BOOL allocrelatt)
 {
    CI_free_memory(self);       /* always safe to call */
 
@@ -97,12 +199,18 @@ CI_set_num_fields(ColumnInfoClass *self, int new_num_fields)
    self->adtsize = (Int2 *) malloc(sizeof(Int2) * self->num_fields);
    self->display_size = (Int2 *) malloc(sizeof(Int2) * self->num_fields);
    self->atttypmod = (Int4 *) malloc(sizeof(Int4) * self->num_fields);
+   if (allocrelatt)
+   {
+       self->relid = (Oid *) malloc(sizeof(Oid) * self->num_fields);
+       self->attid = (Oid *) malloc(sizeof(Oid) * self->num_fields);
+   }
 }
 
 
 void
 CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
-                 Oid new_adtid, Int2 new_adtsize, Int4 new_atttypmod)
+       Oid new_adtid, Int2 new_adtsize, Int4 new_atttypmod,
+       Oid new_relid, Oid new_attid)
 {
    /* check bounds */
    if ((field_num < 0) || (field_num >= self->num_fields))
@@ -115,4 +223,8 @@ CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
    self->atttypmod[field_num] = new_atttypmod;
 
    self->display_size[field_num] = 0;
+   if (self->relid)
+       self->relid[field_num] = new_relid;
+   if (self->attid)
+       self->attid[field_num] = new_attid;
 }
index bd0455c70ba0b0fc7ce8378c6103ff6d359e4bed..85ced66f3030be7a9e819ef750a2cc6b9dab9d9a 100644 (file)
@@ -10,7 +10,6 @@
 #define __COLUMNINFO_H__
 
 #include "psqlodbc.h"
-#include <libpq-fe.h>
 
 struct ColumnInfoClass_
 {
@@ -20,6 +19,8 @@ struct ColumnInfoClass_
    Int2       *adtsize;        /* list type sizes */
    Int2       *display_size;   /* the display size (longest row) */
    Int4       *atttypmod;      /* the length of bpchar/varchar */
+   Oid    *relid;      /* list of relation ids */
+   Oid    *attid;      /* list of attribute ids */
 };
 
 #define CI_get_num_fields(self)            (self->num_fields)
@@ -32,11 +33,13 @@ struct ColumnInfoClass_
 ColumnInfoClass *CI_Constructor(void);
 void       CI_Destructor(ColumnInfoClass *self);
 void       CI_free_memory(ColumnInfoClass *self);
+char       CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn);
 
 /* functions for setting up the fields from within the program, */
 /* without reading from a socket */
-void       CI_set_num_fields(ColumnInfoClass *self, int new_num_fields);
+void       CI_set_num_fields(ColumnInfoClass *self, int new_num_fields, BOOL);
 void CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
-                 Oid new_adtid, Int2 new_adtsize, Int4 atttypmod);
+       Oid new_adtid, Int2 new_adtsize, Int4 atttypmod,
+       Oid new_relid, Oid new_attid);
 
 #endif
index 849d764eefc4cb4c2c848717c2fe348db0f61670..52e6f3f397e39115ccaa729cb7a8268cd4695bad 100644 (file)
@@ -1,11 +1,12 @@
 # Process this file with autoconf to produce a configure script.
-AC_INIT(psqlodbc, 08.01.0200, [pgsql-odbc@postgresql.org])
+AC_INIT(psqlodbc, 07.03.0262, [pgsql-odbc@postgresql.org])
 AC_PREREQ(2.52)
 AM_INIT_AUTOMAKE
 AC_CONFIG_SRCDIR([bind.c])
 AM_CONFIG_HEADER([config.h])
 AM_MAINTAINER_MODE
 
+
 AC_DEFINE(DRIVER_CURSOR_IMPLEMENT, 1,
           [Define to 1 to build with driver cursors option.])
 
@@ -34,13 +35,11 @@ if test "$with_unixodbc" != yes && test "$with_iodbc" != yes; then
                              [AC_MSG_ERROR([no suitable ODBC driver manager found])])])
 fi
 
-
 if test "$with_unixodbc" = yes; then
   AC_DEFINE(WITH_UNIXODBC, 1, [Define to 1 to build with unixODBC support])
   AC_DEFINE(SQL_WCHART_CONVERT, [], [Define to use wchar_t as SQLWCHAR in unixODBC])
 fi
 
-
 if test "$with_iodbc" = yes; then
   AC_DEFINE(WITH_IODBC, 1, [Define to 1 to build with iODBC support])
 fi
@@ -48,24 +47,18 @@ fi
 #
 # Default odbc version number (--with-odbcver), default 0x0300
 #
-
 AC_MSG_CHECKING([for ODBC version number])
 PGAC_ARG_REQ(with, odbcver, [  --with-odbcver=VERSION  change default ODBC version number [[0x0300]]],
              [],
              [with_odbcver=0x0300])
 AC_MSG_RESULT([$with_odbcver])
-
 AC_DEFINE_UNQUOTED(ODBCVER, [$with_odbcver], [Define to ODBC version (--with-odbcver)])
 
 # to implement the Unicode driver   
 PGAC_ARG_BOOL(enable, unicode, yes,     
-   [  --disable-unicode       build non-Unicode driver],    
+   [  --enable-unicode        build ODBC driver for Unicode [[yes]]],   
    [AC_DEFINE(UNICODE_SUPPORT, 1,   
        [Define to 1 to build with Unicode support (--enable-unicode)])      
-    AC_DEFINE(UNICODE, [],      
-       [Define to use wide APIs])   
-    AC_DEFINE(SQL_NOUNICODEMAP, [],     
-       [Define to disable mapping SQL* to SQL*W])   
     AC_CHECK_FUNCS(iswascii)])      
     
 AM_CONDITIONAL(enable_unicode, [test x"$enable_unicode" = xyes])
@@ -90,7 +83,6 @@ PGAC_ARG_BOOL(enable, pthreads, no,
         [AC_DEFINE(PGS_REENTRANT_API_1, 1, [Define if you have 5 parameter gethostbyname_r])],
         [AC_DEFINE(PGS_REENTRANT_API_2, 1, [Define if you have 6 parameter gethostbyname_r])])
      fi
-
      AC_CHECK_FUNCS(localtime_r strtok_r pthread_mutexattr_settype)
      if test x"$ac_cv_func_pthread_mutexattr_settype" = xyes; then
    AC_TRY_COMPILE([#include <pthread.h>],
@@ -102,7 +94,6 @@ PGAC_ARG_BOOL(enable, pthreads, no,
      fi
     ])
 
-
 AC_PROG_CC
 
 AC_LIBTOOL_WIN32_DLL
@@ -123,20 +114,19 @@ AC_C_CONST
 AC_TYPE_SIZE_T
 AC_STRUCT_TM
 
+
 #
 # Find libpq headers and libraries
 #
 AC_PATH_PROGS(PG_CONFIG, pg_config)
-AC_ARG_VAR(PG_CONFIG, [path to pg_config program])
 if test -z "$PG_CONFIG" ; then
   AC_MSG_ERROR([pg_config not found])
 fi
-
 pg_includedir=`$PG_CONFIG --includedir`
-
 pg_libdir=`$PG_CONFIG --libdir`
 CPPFLAGS="$CPPFLAGS -I$pg_includedir"
 LDFLAGS="$LDFLAGS -L$pg_libdir"
 
+
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT
index 49dddfe73b32c43cea486f51e9ffd369f2f3f0a6..c78b0d65afe6e4bbcac768d24b17d64ba7c1936b 100644 (file)
@@ -14,6 +14,8 @@
  */
 /* Multibyte support   Eiji Tokuya 2001-03-15 */
 
+#include "connection.h"
+
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
 #endif /* WIN32 */
 
 #include "environ.h"
+#include "socket.h"
 #include "statement.h"
 #include "qresult.h"
+#include "lobj.h"
 #include "dlg_specific.h"
+#include "loadlib.h"
 
 #include "multibyte.h"
 
@@ -38,9 +43,6 @@
 
 extern GLOBAL_VALUES globals;
 
-#include "connection.h"
-#include "pgtypes.h"
-#include <libpq-fe.h>
 
 RETCODE        SQL_API
 PGAPI_AllocConnect(
@@ -54,7 +56,7 @@ PGAPI_AllocConnect(
    mylog("%s: entering...\n", func);
 
    conn = CC_Constructor();
-   mylog("**** %s: henv = %u, conn = %u\n", func, henv, conn);
+   mylog("**** %s: henv = %x, conn = %x\n", func, henv, conn);
 
    if (!conn)
    {
@@ -85,16 +87,17 @@ PGAPI_AllocConnect(
 RETCODE        SQL_API
 PGAPI_Connect(
              HDBC hdbc,
-             UCHAR FAR * szDSN,
-             SWORD cbDSN,
-             UCHAR FAR * szUID,
-             SWORD cbUID,
-             UCHAR FAR * szAuthStr,
-             SWORD cbAuthStr)
+             const SQLCHAR FAR * szDSN,
+             SQLSMALLINT cbDSN,
+             const SQLCHAR FAR * szUID,
+             SQLSMALLINT cbUID,
+             const SQLCHAR FAR * szAuthStr,
+             SQLSMALLINT cbAuthStr)
 {
    ConnectionClass *conn = (ConnectionClass *) hdbc;
    ConnInfo   *ci;
    CSTR func = "PGAPI_Connect";
+   RETCODE ret = SQL_SUCCESS;
 
    mylog("%s: entering...\n", func);
 
@@ -112,6 +115,8 @@ PGAPI_Connect(
    memcpy(&ci->drivers, &globals, sizeof(globals));
    getDSNinfo(ci, CONN_OVERWRITE);
    logs_on_off(1, ci->drivers.debug, ci->drivers.commlog);
+   /* initialize pg_version from connInfo.protocol    */
+   CC_initialize_pg_version(conn);
 
    /*
     * override values from DSN info with UID and authStr(pwd) This only
@@ -123,37 +128,36 @@ PGAPI_Connect(
    /* fill in any defaults */
    getDSNdefaults(ci);
 
-   qlog("conn = %u, %s(DSN='%s', UID='%s', PWD='%s')\n", conn, func, ci->dsn, ci->username, ci->password ? "xxxxx" : "");
+   qlog("conn = %x, %s(DSN='%s', UID='%s', PWD='%s')\n", conn, func, ci->dsn, ci->username, ci->password ? "xxxxx" : "");
 
    if (CC_connect(conn, AUTH_REQ_OK, NULL) <= 0)
    {
        /* Error messages are filled in */
        CC_log_error(func, "Error on CC_connect", conn);
-       return SQL_ERROR;
+       ret = SQL_ERROR;
    }
 
-   mylog("%s: returning...\n", func);
+   mylog("%s: returning..%d.\n", func, ret);
 
-   return SQL_SUCCESS;
+   return ret;
 }
 
 
 RETCODE        SQL_API
 PGAPI_BrowseConnect(
-                   HDBC hdbc,
-                   UCHAR FAR * szConnStrIn,
-                   SWORD cbConnStrIn,
-                   UCHAR FAR * szConnStrOut,
-                   SWORD cbConnStrOutMax,
-                   SWORD FAR * pcbConnStrOut)
+               HDBC hdbc,
+               const SQLCHAR FAR * szConnStrIn,
+               SQLSMALLINT cbConnStrIn,
+               SQLCHAR FAR * szConnStrOut,
+               SQLSMALLINT cbConnStrOutMax,
+               SQLSMALLINT FAR * pcbConnStrOut)
 {
    CSTR func = "PGAPI_BrowseConnect";
    ConnectionClass *conn = (ConnectionClass *) hdbc;
 
    mylog("%s: entering...\n", func);
 
-   CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "not implemented");
-   CC_log_error(func, "Function not implemented", conn);
+   CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Function not implemented", func);
    return SQL_ERROR;
 }
 
@@ -175,12 +179,11 @@ PGAPI_Disconnect(
        return SQL_INVALID_HANDLE;
    }
 
-   qlog("conn=%u, %s\n", conn, func);
+   qlog("conn=%x, %s\n", conn, func);
 
    if (conn->status == CONN_EXECUTING)
    {
-       CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed");
-       CC_log_error(func, "", conn);
+       CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed", func);
        return SQL_ERROR;
    }
 
@@ -205,7 +208,7 @@ PGAPI_FreeConnect(
    CSTR func = "PGAPI_FreeConnect";
 
    mylog("%s: entering...\n", func);
-   mylog("**** in %s: hdbc=%u\n", func, hdbc);
+   mylog("**** in %s: hdbc=%x\n", func, hdbc);
 
    if (!conn)
    {
@@ -216,8 +219,7 @@ PGAPI_FreeConnect(
    /* Remove the connection from the environment */
    if (!EN_remove_connection(conn->henv, conn))
    {
-       CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed");
-       CC_log_error(func, "", conn);
+       CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed", func);
        return SQL_ERROR;
    }
 
@@ -240,8 +242,141 @@ CC_conninfo_init(ConnInfo *conninfo)
        conninfo->int8_as = -101;
        conninfo->bytea_as_longvarbinary = -1;
        conninfo->use_server_side_prepare = -1;
+       conninfo->lower_case_identifier = -1;
+       conninfo->rollback_on_error = -1;
+#ifdef _HANDLE_ENLIST_IN_DTC_
+       conninfo->xa_opt = -1;
+       conninfo->autocommit_normal = 0;
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
        memcpy(&(conninfo->drivers), &globals, sizeof(globals));
 }
+/*
+ *     IMPLEMENTATION CONNECTION CLASS
+ */
+ConnectionClass *
+CC_Constructor()
+{
+   ConnectionClass *rv, *retrv = NULL;
+
+   rv = (ConnectionClass *) calloc(sizeof(ConnectionClass), 1);
+
+   if (rv != NULL)
+   {
+       // rv->henv = NULL;     /* not yet associated with an environment */
+
+       // rv->__error_message = NULL;
+       // rv->__error_number = 0;
+       // rv->sqlstate[0] = '\0';
+       // rv->errormsg_created = FALSE;
+
+       rv->status = CONN_NOT_CONNECTED;
+       rv->transact_status = CONN_IN_AUTOCOMMIT;       /* autocommit by default */
+
+       CC_conninfo_init(&(rv->connInfo));
+       rv->sock = SOCK_Constructor(rv);
+       if (!rv->sock)
+           goto cleanup;
+
+       rv->stmts = (StatementClass **) malloc(sizeof(StatementClass *) * STMT_INCREMENT);
+       if (!rv->stmts)
+           goto cleanup;
+       memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT);
+
+       rv->num_stmts = STMT_INCREMENT;
+#if (ODBCVER >= 0x0300)
+       rv->descs = (DescriptorClass **) malloc(sizeof(DescriptorClass *) * STMT_INCREMENT);
+       if (!rv->descs)
+           goto cleanup;
+       memset(rv->descs, 0, sizeof(DescriptorClass *) * STMT_INCREMENT);
+
+       rv->num_descs = STMT_INCREMENT;
+#endif /* ODBCVER */
+
+       rv->lobj_type = PG_TYPE_LO_UNDEFINED;
+
+       // rv->ncursors = 0;
+       // rv->ntables = 0;
+       // rv->col_info = NULL;
+
+       // rv->translation_option = 0;
+       // rv->translation_handle = NULL;
+       // rv->DataSourceToDriver = NULL;
+       // rv->DriverToDataSource = NULL;
+       rv->driver_version = ODBCVER;
+       // memset(rv->pg_version, 0, sizeof(rv->pg_version));
+       // rv->pg_version_number = .0;
+       // rv->pg_version_major = 0;
+       // rv->pg_version_minor = 0;
+       // rv->ms_jet = 0;
+       // rv->unicode = 0;
+       // rv->result_uncommitted = 0;
+       // rv->schema_support = 0;
+       rv->isolation = SQL_TXN_READ_COMMITTED;
+       // rv->original_client_encoding = NULL;
+       // rv->current_client_encoding = NULL;
+       // rv->server_encoding = NULL;
+       // rv->current_schema = NULL;
+       // rv->num_discardp = 0;
+       // rv->discardp = NULL;
+       rv->mb_maxbyte_per_char = 1;
+       rv->max_identifier_length = -1;
+
+       /* Initialize statement options to defaults */
+       /* Statements under this conn will inherit these options */
+
+       InitializeStatementOptions(&rv->stmtOptions);
+       InitializeARDFields(&rv->ardOptions);
+       InitializeAPDFields(&rv->apdOptions);
+#ifdef _HANDLE_ENLIST_IN_DTC_
+       // rv->asdum = NULL;
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
+       INIT_CONN_CS(rv);
+       retrv = rv;
+   }
+
+cleanup:
+   if (rv && !retrv)
+       CC_Destructor(rv);
+   return retrv;
+}
+
+
+char
+CC_Destructor(ConnectionClass *self)
+{
+   mylog("enter CC_Destructor, self=%x\n", self);
+
+   if (self->status == CONN_EXECUTING)
+       return 0;
+
+   CC_cleanup(self);           /* cleanup socket and statements */
+
+   mylog("after CC_Cleanup\n");
+
+   /* Free up statement holders */
+   if (self->stmts)
+   {
+       free(self->stmts);
+       self->stmts = NULL;
+   }
+#if (ODBCVER >= 0x0300)
+   if (self->descs)
+   {
+       free(self->descs);
+       self->descs = NULL;
+   }
+#endif /* ODBCVER */
+   mylog("after free statement holders\n");
+
+   if (self->__error_message)
+       free(self->__error_message);
+   DELETE_CONN_CS(self);
+   free(self);
+
+   mylog("exit CC_Destructor\n");
+
+   return 1;
+}
 
 
 /* Return how many cursors are opened on this connection */
@@ -251,13 +386,14 @@ CC_cursor_count(ConnectionClass *self)
    StatementClass *stmt;
    int         i,
                count = 0;
+   QResultClass        *res;
 
-   mylog("CC_cursor_count: self=%u, num_stmts=%d\n", self, self->num_stmts);
+   mylog("CC_cursor_count: self=%x, num_stmts=%d\n", self, self->num_stmts);
 
    for (i = 0; i < self->num_stmts; i++)
    {
        stmt = self->stmts[i];
-       if (stmt && SC_get_Result(stmt) && SC_get_Result(stmt)->cursor)
+       if (stmt && (res = SC_get_Result(stmt)) && QR_get_cursor(res))
            count++;
    }
 
@@ -272,10 +408,12 @@ CC_clear_error(ConnectionClass *self)
 {
    self->__error_number = 0;
    if (self->__error_message)
+   {
        free(self->__error_message);
-   self->__error_message = NULL;
+       self->__error_message = NULL;
+   }
+   self->sqlstate[0] = '\0';
    self->errormsg_created = FALSE;
-   self->__sqlstate[0] = '\0';
 }
 
 
@@ -288,16 +426,11 @@ CC_begin(ConnectionClass *self)
    char    ret = TRUE;
    if (!CC_is_in_trans(self))
    {
-       QResultClass *res = CC_send_query(self, "BEGIN", NULL, CLEAR_RESULT_ON_ABORT);
+       QResultClass *res = CC_send_query(self, "BEGIN", NULL, 0, NULL);
        mylog("CC_begin:  sending BEGIN!\n");
 
-       if (res != NULL)
-       {
-           ret = QR_command_maybe_successful(res);
-           QR_Destructor(res);
-       }
-       else
-           return FALSE;
+       ret = QR_command_maybe_successful(res);
+       QR_Destructor(res);
    }
 
    return ret;
@@ -310,18 +443,13 @@ CC_begin(ConnectionClass *self)
 char
 CC_commit(ConnectionClass *self)
 {
-   char    ret = FALSE;
+   char    ret = TRUE;
    if (CC_is_in_trans(self))
    {
-       QResultClass *res = CC_send_query(self, "COMMIT", NULL, CLEAR_RESULT_ON_ABORT);
+       QResultClass *res = CC_send_query(self, "COMMIT", NULL, 0, NULL);
        mylog("CC_commit:  sending COMMIT!\n");
-       if (res != NULL)
-       {
-           ret = QR_command_maybe_successful(res);
-           QR_Destructor(res);
-       }
-       else
-           return FALSE;
+       ret = QR_command_maybe_successful(res);
+       QR_Destructor(res);
    }
 
    return ret;
@@ -334,26 +462,147 @@ CC_commit(ConnectionClass *self)
 char
 CC_abort(ConnectionClass *self)
 {
+   char    ret = TRUE;
    if (CC_is_in_trans(self))
    {
-       QResultClass *res = CC_send_query(self, "ROLLBACK", NULL, CLEAR_RESULT_ON_ABORT);
+       QResultClass *res = CC_send_query(self, "ROLLBACK", NULL, 0, NULL);
        mylog("CC_abort:  sending ABORT!\n");
-       if (res != NULL)
-           QR_Destructor(res);
-       else
-           return FALSE;
+       ret = QR_command_maybe_successful(res);
+       QR_Destructor(res);
    }
 
-   return TRUE;
+   return ret;
 }
 
 
+/* This is called by SQLDisconnect also */
+char
+CC_cleanup(ConnectionClass *self)
+{
+   int         i;
+   StatementClass *stmt;
+   DescriptorClass *desc;
+
+   if (self->status == CONN_EXECUTING)
+       return FALSE;
+
+   mylog("in CC_Cleanup, self=%x\n", self);
+
+   /* Cancel an ongoing transaction */
+   /* We are always in the middle of a transaction, */
+   /* even if we are in auto commit. */
+   if (self->sock)
+   {
+       CC_abort(self);
+
+       mylog("after CC_abort\n");
+
+       /* This actually closes the connection to the dbase */
+       SOCK_Destructor(self->sock);
+       self->sock = NULL;
+   }
+
+   mylog("after SOCK destructor\n");
+
+   /* Free all the stmts on this connection */
+   for (i = 0; i < self->num_stmts; i++)
+   {
+       stmt = self->stmts[i];
+       if (stmt)
+       {
+           stmt->hdbc = NULL;  /* prevent any more dbase interactions */
+
+           SC_Destructor(stmt);
+
+           self->stmts[i] = NULL;
+       }
+   }
+#if (ODBCVER >= 0x0300)
+   /* Free all the descs on this connection */
+   for (i = 0; i < self->num_descs; i++)
+   {
+       desc = self->descs[i];
+       if (desc)
+       {
+           DC_get_conn(desc) = NULL;   /* prevent any more dbase interactions */
+           DC_Destructor(desc);
+           free(desc);
+           self->descs[i] = NULL;
+       }
+   }
+#endif /* ODBCVER */
+
+   /* Check for translation dll */
+#ifdef WIN32
+   if (self->translation_handle)
+   {
+       FreeLibrary(self->translation_handle);
+       self->translation_handle = NULL;
+   }
+#endif
+
+   self->status = CONN_NOT_CONNECTED;
+   self->transact_status = CONN_IN_AUTOCOMMIT;
+   CC_conninfo_init(&(self->connInfo));
+   if (self->original_client_encoding)
+   {
+       free(self->original_client_encoding);
+       self->original_client_encoding = NULL;
+   }
+   if (self->current_client_encoding)
+   {
+       free(self->current_client_encoding);
+       self->current_client_encoding = NULL;
+   }
+   if (self->server_encoding)
+   {
+       free(self->server_encoding);
+       self->server_encoding = NULL;
+   }
+   if (self->current_schema)
+   {
+       free(self->current_schema);
+       self->current_schema = NULL;
+   }
+   /* Free cached table info */
+   if (self->col_info)
+   {
+       for (i = 0; i < self->ntables; i++)
+       {
+           if (self->col_info[i]->result)  /* Free the SQLColumns result structure */
+               QR_Destructor(self->col_info[i]->result);
+
+           NULL_THE_NAME(self->col_info[i]->schema_name);
+           NULL_THE_NAME(self->col_info[i]->table_name);
+           free(self->col_info[i]);
+       }
+       free(self->col_info);
+       self->col_info = NULL;
+   }
+   self->ntables = 0;
+   if (self->num_discardp > 0 && self->discardp)
+   {
+       for (i = 0; i < self->num_discardp; i++)
+           free(self->discardp[i]);
+       self->num_discardp = 0;
+   }
+   if (self->discardp)
+   {
+       free(self->discardp);
+       self->discardp = NULL;
+   }
+
+   mylog("exit CC_Cleanup\n");
+   return TRUE;
+}
+
 
 int
 CC_set_translation(ConnectionClass *self)
 {
 
 #ifdef WIN32
+   CSTR    func = "CC_set_translation";
 
    if (self->translation_handle != NULL)
    {
@@ -369,7 +618,7 @@ CC_set_translation(ConnectionClass *self)
 
    if (self->translation_handle == NULL)
    {
-       CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Could not load the translation DLL.");
+       CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Could not load the translation DLL.", func);
        return FALSE;
    }
 
@@ -383,1185 +632,2244 @@ CC_set_translation(ConnectionClass *self)
 
    if (self->DataSourceToDriver == NULL || self->DriverToDataSource == NULL)
    {
-       CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Could not find translation DLL functions.");
+       CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Could not find translation DLL functions.", func);
        return FALSE;
    }
 #endif
    return TRUE;
 }
 
+static int
+md5_auth_send(ConnectionClass *self, const char *salt)
+{
+   char    *pwd1 = NULL, *pwd2 = NULL;
+   ConnInfo   *ci = &(self->connInfo);
+   SocketClass *sock = self->sock;
 
-char
-CC_add_statement(ConnectionClass *self, StatementClass *stmt)
+inolog("md5 pwd=%s user=%s\n", ci->password, ci->username);
+   if (!(pwd1 = malloc(MD5_PASSWD_LEN + 1)))
+       return 1;
+   if (!EncryptMD5(ci->password, ci->username, strlen(ci->username), pwd1))
+   {
+       free(pwd1);
+       return 1;
+   } 
+   if (!(pwd2 = malloc(MD5_PASSWD_LEN + 1)))
+   {
+       free(pwd1);
+       return 1;
+   } 
+   if (!EncryptMD5(pwd1 + strlen("md5"), salt, 4, pwd2))
+   {
+       free(pwd2);
+       free(pwd1);
+       return 1;
+   }
+   free(pwd1);
+   if (PROTOCOL_74(&(self->connInfo)))
 {
-   int         i;
+inolog("putting p\n");
+       SOCK_put_char(sock, 'p');
+}
+   SOCK_put_int(sock, 4 + (int) strlen(pwd2) + 1, 4);
+   SOCK_put_n_char(sock, pwd2, (int) strlen(pwd2) + 1);
+   SOCK_flush_output(sock);
+   free(pwd2);
+   return 0; 
+}
 
-   mylog("CC_add_statement: self=%u, stmt=%u\n", self, stmt);
+int
+EatReadyForQuery(ConnectionClass *conn)
+{
+   int id;
 
-   for (i = 0; i < self->num_stmts; i++)
+   if (PROTOCOL_74(&(conn->connInfo)))
    {
-       if (!self->stmts[i])
+       BOOL    is_in_error_trans = CC_is_in_error_trans(conn);
+       switch (id = SOCK_get_char(conn->sock))
        {
-           stmt->hdbc = self;
-           self->stmts[i] = stmt;
-           return TRUE;
+           case 'I':
+               if (CC_is_in_trans(conn))
+               {
+                   if (is_in_error_trans)
+                       CC_on_abort(conn, NO_TRANS);
+                   else
+                       CC_on_commit(conn);
+               }
+               break;
+           case 'T':
+               CC_set_in_trans(conn);
+               CC_set_no_error_trans(conn);
+               if (is_in_error_trans)
+                   CC_on_abort_partial(conn);
+               break;
+           case 'E':
+               CC_set_in_error_trans(conn);
+               break;  
        }
    }
-
-   /* no more room -- allocate more memory */
-   self->stmts = (StatementClass **) realloc(self->stmts, sizeof(StatementClass *) * (STMT_INCREMENT + self->num_stmts));
-   if (!self->stmts)
-       return FALSE;
-
-   memset(&self->stmts[self->num_stmts], 0, sizeof(StatementClass *) * STMT_INCREMENT);
-
-   stmt->hdbc = self;
-   self->stmts[self->num_stmts] = stmt;
-
-   self->num_stmts += STMT_INCREMENT;
-
-   return TRUE;
+   return id;  
 }
 
-
-char
-CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
+int
+handle_error_message(ConnectionClass *self, char *msgbuf, int buflen, char *sqlstate, const char *comment, QResultClass *res)
 {
-   int         i;
+   BOOL    new_format = FALSE, msg_truncated = FALSE, truncated;
+   SocketClass *sock = self->sock;
+   char    msgbuffer[ERROR_MSG_LENGTH];
+   UDWORD  abort_opt;
 
-   if (stmt->status == STMT_EXECUTING)
-       return FALSE;
-   for (i = 0; i < self->num_stmts; i++)
+inolog("handle_error_message prptocol=%s\n", self->connInfo.protocol);
+   if (PROTOCOL_74(&(self->connInfo)))
+       new_format = TRUE;
+
+inolog("new_format=%d\n", new_format);
+   if (new_format)
    {
-       if (self->stmts[i] == stmt)
+       msgbuf[0] = '\0';
+       for (;;)
        {
-           self->stmts[i] = NULL;
-           return TRUE;
+           truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+           if (!msgbuffer[0])
+               break;
+
+           mylog("%s: 'E' - %s\n", comment, msgbuffer);
+           qlog("ERROR from backend during %s: '%s'\n", comment, msgbuffer);
+           switch (msgbuffer[0])
+           {
+               case 'S':
+                   strncat(msgbuf, msgbuffer + 1, buflen);
+                   strncat(msgbuf, ": ", buflen);
+                   buflen -= (int) (strlen(msgbuffer) + 1);
+                   break;
+               case 'M':
+                   strncat(msgbuf, msgbuffer + 1, buflen);
+                   msg_truncated = truncated;
+                   break;
+               case 'C':
+                   if (sqlstate)
+                       strcpy(sqlstate, msgbuffer + 1);
+                   break;
+           }
+           while (truncated)
+               truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
        }
    }
+   else
+   {
+       msg_truncated = SOCK_get_string(sock, msgbuf, buflen);
 
-   return FALSE;
-}
+       /* Remove a newline */
+       if (msgbuf[0] != '\0' && msgbuf[(int)strlen(msgbuf) - 1] == '\n')
+           msgbuf[(int)strlen(msgbuf) - 1] = '\0';
 
+       mylog("%s: 'E' - %s\n", comment, msgbuf);
+       qlog("ERROR from backend during %s: '%s'\n", comment, msgbuf);
+       for (truncated = msg_truncated; truncated;)
+           truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+   }
+   abort_opt = 0;
+   if (!strncmp(msgbuffer, "FATAL", 5))
+   {
+       CC_set_errornumber(self, CONNECTION_SERVER_REPORTED_ERROR);
+       abort_opt = CONN_DEAD;
+   }
+   else
+   {
+       CC_set_errornumber(self, CONNECTION_SERVER_REPORTED_WARNING);
+       if (CC_is_in_trans(self))
+           CC_set_in_error_trans(self);
+   }
+   if (0 != abort_opt
+#ifdef _LEGACY_MODE_
+       || TRUE
+#endif /* _LEGACY_NODE_ */
+      )
+       CC_on_abort(self, abort_opt);
+   if (res)
+   {
+       QR_set_rstatus(res, PGRES_FATAL_ERROR);
+       QR_set_message(res, msgbuf);
+       QR_set_aborted(res, TRUE);
+   }
 
-void
-CC_set_error(ConnectionClass *self, int number, const char *message)
-{
-   if (self->__error_message)
-       free(self->__error_message);
-   self->__error_number = number;
-   self->__error_message = message ? strdup(message) : NULL;
+   return msg_truncated;
 }
 
-
-void
-CC_set_errormsg(ConnectionClass *self, const char *message)
+int
+handle_notice_message(ConnectionClass *self, char *msgbuf, int buflen, char *sqlstate, const char *comment, QResultClass *res)
 {
-   if (self->__error_message)
-       free(self->__error_message);
-   self->__error_message = message ? strdup(message) : NULL;
-}
+   BOOL    new_format = FALSE, msg_truncated = FALSE, truncated;
+   SocketClass *sock = self->sock;
+   char    msgbuffer[ERROR_MSG_LENGTH];
 
+   if (PROTOCOL_74(&(self->connInfo)))
+       new_format = TRUE;
 
-char
-CC_get_error(ConnectionClass *self, int *number, char **message)
-{
-   int         rv;
-   char *msgcrt;
+   if (new_format)
+   {
+       msgbuf[0] = '\0';
+       for (;;)
+       {
+           truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+           if (!msgbuffer[0])
+               break;
 
-   mylog("enter CC_get_error\n");
+           mylog("%s: 'N' - %s\n", comment, msgbuffer);
+           qlog("NOTICE from backend during %s: '%s'\n", comment, msgbuffer);
+           switch (msgbuffer[0])
+           {
+               case 'S':
+                   strncat(msgbuf, msgbuffer + 1, buflen);
+                   strncat(msgbuf, ": ", buflen);
+                   buflen -= (strlen(msgbuffer) + 1);
+                   break;
+               case 'M':
+                   strncat(msgbuf, msgbuffer + 1, buflen);
+                   msg_truncated = truncated;
+                   break;
+               case 'C':
+                   if (sqlstate && !sqlstate[0] && strcmp(msgbuffer + 1, "00000"))
+                       strcpy(sqlstate, msgbuffer + 1);
+                   break;
+           } 
+       }
+       while (truncated)
+           truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+   }
+   else
+   {
+       msg_truncated = SOCK_get_string(sock, msgbuf, buflen);
 
-   /* Create a very informative errormsg if it hasn't been done yet. */
-   if (!self->errormsg_created)
+       /* Remove a newline */
+       if (msgbuf[0] != '\0' && msgbuf[strlen(msgbuf) - 1] == '\n')
+           msgbuf[strlen(msgbuf) - 1] = '\0';
+
+       mylog("%s: 'N' - %s\n", comment, msgbuf);
+       qlog("NOTICE from backend during %s: '%s'\n", comment, msgbuf);
+       for (truncated = msg_truncated; truncated;)
+           truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+   }
+   if (res)
    {
-       msgcrt = CC_create_errormsg(self);
-       if (self->__error_message)
-           free(self->__error_message);
-       self->__error_message = msgcrt;
-       self->errormsg_created = TRUE;
+       if (QR_command_successful(res))
+           QR_set_rstatus(res, PGRES_NONFATAL_ERROR);
+       QR_set_notice(res, msgbuf);  /* will dup this string */
    }
 
-   if (CC_get_errornumber(self))
+   return msg_truncated;
+}
+
+void   getParameterValues(ConnectionClass *conn)
+{
+   SocketClass *sock = conn->sock;
+   /* ERROR_MSG_LENGTH is suffcient */
+   char msgbuffer[ERROR_MSG_LENGTH + 1];
+   
+   SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+inolog("parameter name=%s\n", msgbuffer);
+   if (stricmp(msgbuffer, "server_encoding") == 0)
    {
-       *number = CC_get_errornumber(self);
-       *message = CC_get_errormsg(self);
+       SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+       if (conn->server_encoding)
+           free(conn->server_encoding);
+       conn->server_encoding = strdup(msgbuffer);
    }
-   rv = (CC_get_errornumber(self) != 0);
+   else if (stricmp(msgbuffer, "client_encoding") == 0)
+   {
+       SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+       if (conn->current_client_encoding)
+           free(conn->current_client_encoding);
+       conn->current_client_encoding = strdup(msgbuffer);
+   }
+   else if (stricmp(msgbuffer, "server_version") == 0)
+   {
+       char    szVersion[32];
+       int major, minor;
 
-   self->__error_number = 0;       /* clear the error */
+       SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+       strncpy(conn->pg_version, msgbuffer, sizeof(conn->pg_version));
+       strcpy(szVersion, "0.0");
+       if (sscanf(conn->pg_version, "%d.%d", &major, &minor) >= 2)
+       {
+           snprintf(szVersion, sizeof(szVersion), "%d.%d", major, minor);
+           conn->pg_version_major = major;
+           conn->pg_version_minor = minor;
+       }
+       conn->pg_version_number = (float) atof(szVersion);
+       if (PG_VERSION_GE(conn, 7.3))
+           conn->schema_support = 1;
 
-   mylog("exit CC_get_error\n");
+       mylog("Got the PostgreSQL version string: '%s'\n", conn->pg_version);
+       mylog("Extracted PostgreSQL version number: '%1.1f'\n", conn->pg_version_number);
+       qlog("    [ PostgreSQL version string = '%s' ]\n", conn->pg_version);
+       qlog("    [ PostgreSQL version number = '%1.1f' ]\n", conn->pg_version_number);
+   }
+   else
+       SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
 
-   return rv;
+inolog("parameter value=%s\n", msgbuffer);
 }
 
-void CC_set_sqlstate(ConnectionClass *self, const char *sqlstate)
+static int protocol3_opts_array(ConnectionClass *self, const char *opts[][2], BOOL libpqopt, int dim_opts)
 {
-    if (sqlstate)
-        snprintf(self->__sqlstate, SQLSTATE_LENGTH, "%s", sqlstate);
-    else
-        self->__sqlstate[0] = '\0';
+   SocketClass *sock = self->sock;
+   ConnInfo    *ci = &(self->connInfo);
+   const   char    *enc = NULL;
+   int cnt;
+   BOOL    set_client_encode = FALSE;
+
+   cnt = 0;
+   if (libpqopt && ci->server[0])
+   {
+       opts[cnt][0] = "host";      opts[cnt++][1] = ci->server;
+   }
+   if (libpqopt && ci->port[0])
+   {
+       opts[cnt][0] = "port";      opts[cnt++][1] = ci->port;
+   }
+   if (ci->database[0])
+   {
+       if (libpqopt)
+       {
+           opts[cnt][0] = "dbname";    opts[cnt++][1] = ci->database;
+       }
+       else
+       {
+           opts[cnt][0] = "database";  opts[cnt++][1] = ci->database;
+       }
+   }
+   if (ci->username[0])
+   {
+       opts[cnt][0] = "user";      opts[cnt++][1] = ci->username;
+   }
+   if (libpqopt)
+   {
+       if (ci->sslmode[0])
+       {
+           opts[cnt][0] = "sslmode";   opts[cnt++][1] = ci->sslmode;
+       }
+       if (ci->password[0])
+       {
+           opts[cnt][0] = "password";  opts[cnt++][1] = ci->password;
+       }
+   }
+   else
+   {
+       /* DateStyle */
+       opts[cnt][0] = "DateStyle"; opts[cnt++][1] = "ISO";
+       /* extra_float_digits */
+       opts[cnt][0] = "extra_float_digits";    opts[cnt++][1] = "2";
+       /* geqo */
+       opts[cnt][0] = "geqo";
+       if (ci->drivers.disable_optimizer)
+           opts[cnt++][1] = "off";
+       else
+           opts[cnt++][1] = "on";
+       /* client_encoding */
+       enc = get_environment_encoding(self, NULL);
+       if (enc)
+       {
+           opts[cnt][0] = "client_encoding"; opts[cnt++][1] = enc;
+       }
+   }
+
+   return cnt;
 }
 
-char *CC_get_sqlstate(ConnectionClass *self)
+static int protocol3_packet_build(ConnectionClass *self)
 {
-    return self->__sqlstate;
+   CSTR    func = "protocol3_packet_build";
+   SocketClass *sock = self->sock;
+   ConnInfo    *ci = &(self->connInfo);
+   Int4    slen;
+   char    *packet, *ppacket;
+   ProtocolVersion pversion;
+   const   char    *opts[20][2], *enc = NULL;
+   int cnt, i;
+   BOOL    set_client_encode = FALSE;
+
+   cnt = protocol3_opts_array(self, opts, FALSE, sizeof(opts) / sizeof(opts[0]));
+
+   slen =  sizeof(ProtocolVersion);
+   for (i = 0; i < cnt; i++)
+   {
+       slen += (strlen(opts[i][0]) + 1);
+       slen += (strlen(opts[i][1]) + 1);
+   }
+   slen++;
+               
+   if (packet = malloc(slen), !packet)
+   {
+       CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not allocate a startup packet", func);
+       return 0;
+   }
+
+   mylog("sizeof startup packet = %d\n", slen);
+
+   sock->pversion = PG_PROTOCOL_LATEST;
+   /* Send length of Authentication Block */
+   SOCK_put_int(sock, slen + 4, 4);
+
+   ppacket = packet;
+   pversion = (ProtocolVersion) htonl(sock->pversion);
+   memcpy(ppacket, &pversion, sizeof(pversion));
+   ppacket += sizeof(pversion);
+   for (i = 0; i < cnt; i++)
+   { 
+       strcpy(ppacket, opts[i][0]);
+       ppacket += (strlen(opts[i][0]) + 1);
+       strcpy(ppacket, opts[i][1]);
+       ppacket += (strlen(opts[i][1]) + 1);
+   }
+   *ppacket = '\0';
+
+   SOCK_put_n_char(sock, packet, slen);
+   SOCK_flush_output(sock);
+   free(packet);
+
+   return 1;
 }
 
-static void CC_clear_cursors(ConnectionClass *self, BOOL allcursors)
+static char    *protocol3_opts_build(ConnectionClass *self)
 {
-   int i;
-   StatementClass  *stmt;
-   QResultClass    *res;
+   CSTR    func = "protocol3_opts_build";
+   ConnInfo    *ci = &(self->connInfo);
+   Int4    slen;
+   char    *conninfo, *ppacket;
+   const   char    *opts[20][2];
+   int cnt, i;
+   BOOL    blankExist;
 
-   for (i = 0; i < self->num_stmts; i++)
+   cnt = protocol3_opts_array(self, opts, TRUE, sizeof(opts) / sizeof(opts[0]));
+
+   slen =  sizeof(ProtocolVersion);
+   for (i = 0, slen = 0; i < cnt; i++)
    {
-       stmt = self->stmts[i];
-       if (stmt && (res = SC_get_Result(stmt)) &&
-           res->cursor && res->cursor[0])
+       slen += (strlen(opts[i][0]) + 2 + 2); /* add 2 bytes for safety (literal quotes) */
+       slen += strlen(opts[i][1]);
+   }
+   slen++;
+               
+   if (conninfo = malloc(slen), !conninfo)
+   {
+       CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not allocate a connectdb option", func);
+       return 0;
+   }
+
+   mylog("sizeof connectdb option = %d\n", slen);
+
+   for (i = 0, ppacket = conninfo; i < cnt; i++)
+   { 
+       sprintf(ppacket, " %s=", opts[i][0]);
+       ppacket += (strlen(opts[i][0]) + 2);
+       blankExist = FALSE;
+       if (strchr(opts[i][1], ' '))
+           blankExist = TRUE;
+       if (blankExist)
        {
-       /*
-        * non-holdable cursors are automatically closed
-        * at commit time.
-        * all cursors are automatically closed
-        * at rollback time.
-        */
-           if (res->cursor)
-           {
-               free(res->cursor);
-               res->cursor = NULL;
-           }
+           *ppacket = '\'';
+           ppacket++;
+       }
+       strcpy(ppacket, opts[i][1]);
+       ppacket += strlen(opts[i][1]);
+       if (blankExist)
+       {
+           *ppacket = '\'';
+           ppacket++;
        }
    }
+   *ppacket = '\0';
+inolog("return conninfo=%s(%d)\n", conninfo, strlen(conninfo));
+   return conninfo;
 }
 
-void   CC_on_commit(ConnectionClass *conn)
+static char CC_initial_log(ConnectionClass *self, const char *func)
 {
-   if (CC_is_in_trans(conn))
+   const ConnInfo  *ci = &self->connInfo;
+   char    *encoding;
+
+   qlog("Global Options: Version='%s', fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
+        POSTGRESDRIVERVERSION,
+        ci->drivers.fetch_max,
+        ci->drivers.socket_buffersize,
+        ci->drivers.unknown_sizes,
+        ci->drivers.max_varchar_size,
+        ci->drivers.max_longvarchar_size);
+   qlog("                disable_optimizer=%d, ksqo=%d, unique_index=%d, use_declarefetch=%d\n",
+        ci->drivers.disable_optimizer,
+        ci->drivers.ksqo,
+        ci->drivers.unique_index,
+        ci->drivers.use_declarefetch);
+   qlog("                text_as_longvarchar=%d, unknowns_as_longvarchar=%d, bools_as_char=%d NAMEDATALEN=%d\n",
+        ci->drivers.text_as_longvarchar,
+        ci->drivers.unknowns_as_longvarchar,
+        ci->drivers.bools_as_char,
+        TABLE_NAME_STORAGE_LEN);
+
+   encoding = check_client_encoding(ci->conn_settings);
+   if (encoding && strcmp(encoding, "OTHER"))
+       self->original_client_encoding = strdup(encoding);
+   else
    {
-#ifdef DRIVER_CURSOR_IMPLEMENT
-       if (conn->result_uncommitted)
-           ProcessRollback(conn, FALSE);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
-       CC_set_no_trans(conn);
-       CC_set_no_manual_trans(conn);
+       encoding = check_client_encoding(ci->drivers.conn_settings);
+       if (encoding && strcmp(encoding, "OTHER"))
+           self->original_client_encoding = strdup(encoding);
+   }
+   if (self->original_client_encoding)
+       self->ccsc = pg_CS_code(self->original_client_encoding);
+   qlog("                extra_systable_prefixes='%s', conn_settings='%s' conn_encoding='%s'\n",
+        ci->drivers.extra_systable_prefixes,
+        ci->drivers.conn_settings,
+        encoding ? encoding : "");
+   if (self->status != CONN_NOT_CONNECTED)
+   {
+       CC_set_error(self, CONN_OPENDB_ERROR, "Already connected.", func);
+       return 0;
+   }
+
+   if (ci->port[0] == '\0' ||
+#ifdef WIN32
+       ci->server[0] == '\0' ||
+#endif /* WIN32 */
+       ci->database[0] == '\0')
+   {
+       CC_set_error(self, CONN_INIREAD_ERROR, "Missing server name, port, or database name in call to CC_connect.", func);
+       return 0;
    }
-   conn->result_uncommitted = 0;
-   CC_clear_cursors(conn, TRUE);
-   CC_discard_marked_plans(conn);
-}
 
+   mylog("%s: DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n", func, ci->dsn, ci->server, ci->port, ci->database, ci->username, ci->password ? "xxxxx" : "");
 
-char
-CC_send_settings(ConnectionClass *self)
+   return 1;
+}
+
+static char    CC_setenv(ConnectionClass *self);
+static int LIBPQ_connect(ConnectionClass *self);
+static char
+LIBPQ_CC_connect(ConnectionClass *self, char password_req, char *salt_para)
 {
-   /* char ini_query[MAX_MESSAGE_LEN]; */
    ConnInfo   *ci = &(self->connInfo);
+   int     ret;
+   CSTR        func = "LIBPQ_CC_connect";
 
-/* QResultClass *res; */
-   HSTMT       hstmt;
-   StatementClass *stmt;
-   RETCODE     result;
-   char        status = TRUE;
-   char       *cs,
-              *ptr;
-#ifdef HAVE_STRTOK_R
-   char    *last;
-#endif /* HAVE_STRTOK_R */
-   CSTR func = "CC_send_settings";
+   mylog("%s: entering...\n", func);
 
+   if (password_req == AUTH_REQ_OK) /* not yet connected */
+   {
+       if (0 == CC_initial_log(self, func))
+           return 0;
+   }
 
-   mylog("%s: entering...\n", func);
+   if (ret = LIBPQ_connect(self), ret <= 0)
+       return ret;
+   CC_setenv(self);
 
-/*
- * This function must use the local odbc API functions since the odbc state
- * has not transitioned to "connected" yet.
- */
+   return 1;
+}
 
-   result = PGAPI_AllocStmt(self, &hstmt);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-       return FALSE;
-   stmt = (StatementClass *) hstmt;
+static char
+original_CC_connect(ConnectionClass *self, char password_req, char *salt_para)
+{
+   StartupPacket sp;
+   StartupPacket6_2 sp62;
+   QResultClass *res;
+   SocketClass *sock;
+   ConnInfo   *ci = &(self->connInfo);
+   int         areq = -1;
+   int         beresp;
+   char        msgbuffer[ERROR_MSG_LENGTH];
+   char        salt[5], notice[512];
+   CSTR        func = "original_connect";
+   // char    *encoding;
+   BOOL    startPacketReceived = FALSE;
 
-   stmt->internal = TRUE;      /* ensure no BEGIN/COMMIT/ABORT stuff */
+   mylog("%s: entering...\n", func);
 
-   /* Set the Datestyle to the format the driver expects it to be in */
-   result = PGAPI_ExecDirect(hstmt, "set DateStyle to 'ISO'", SQL_NTS, 0);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-       status = FALSE;
+   if (password_req != AUTH_REQ_OK)
 
-   mylog("%s: result %d, status %d from set DateStyle\n", func, result, status);
+       sock = self->sock;      /* already connected, just authenticate */
 
-   /* Disable genetic optimizer based on global flag */
-   if (ci->drivers.disable_optimizer)
+   else
    {
-       result = PGAPI_ExecDirect(hstmt, "set geqo to 'OFF'", SQL_NTS, 0);
-       if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-           status = FALSE;
+       if (0 == CC_initial_log(self, func))
+           return 0;
 
-       mylog("%s: result %d, status %d from set geqo\n", func, result, status);
+another_version_retry:
 
-   }
+       /*
+        * If the socket was closed for some reason (like a SQLDisconnect,
+        * but no SQLFreeConnect then create a socket now.
+        */
+       if (!self->sock)
+       {
+           self->sock = SOCK_Constructor(self);
+           if (!self->sock)
+           {
+               CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not construct a socket to the server", func);
+               return 0;
+           }
+       }
 
-   /* KSQO (not applicable to 7.1+ - DJP 21/06/2002) */
-   if (ci->drivers.ksqo && PG_VERSION_LT(self, 7.1))
-   {
-       result = PGAPI_ExecDirect(hstmt, "set ksqo to 'ON'", SQL_NTS, 0);
-       if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-           status = FALSE;
+       sock = self->sock;
 
-       mylog("%s: result %d, status %d from set ksqo\n", func, result, status);
+       mylog("connecting to the server socket...\n");
 
-   }
+       SOCK_connect_to(sock, (short) atoi(ci->port), ci->server);
+       if (SOCK_get_errcode(sock) != 0)
+       {
+           CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not connect to the server", func);
+           return 0;
+       }
+       mylog("connection to the server socket succeeded.\n");
 
-   /* extra_float_digits (applicable since 7.4) */
-   if (PG_VERSION_GT(self, 7.3))
-   {
-       result = PGAPI_ExecDirect(hstmt, "set extra_float_digits to 2", SQL_NTS, 0);
-       if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-           status = FALSE;
+inolog("protocol=%s version=%d,%d\n", ci->protocol, self->pg_version_major, self->pg_version_minor);
+       if (PROTOCOL_62(ci))
+       {
+           sock->reverse = TRUE;       /* make put_int and get_int work
+                                        * for 6.2 */
+
+           memset(&sp62, 0, sizeof(StartupPacket6_2));
+           sock->pversion = PG_PROTOCOL_62;
+           SOCK_put_int(sock, htonl(4 + sizeof(StartupPacket6_2)), 4);
+           sp62.authtype = htonl(NO_AUTHENTICATION);
+           strncpy(sp62.database, ci->database, PATH_SIZE);
+           strncpy(sp62.user, ci->username, USRNAMEDATALEN);
+           SOCK_put_n_char(sock, (char *) &sp62, sizeof(StartupPacket6_2));
+           SOCK_flush_output(sock);
+       }
+       else if (PROTOCOL_74(ci))
+       {
+           if (!protocol3_packet_build(self))
+               return 0;
+       }
+       else
+       {
+           memset(&sp, 0, sizeof(StartupPacket));
 
-       mylog("%s: result %d, status %d from set extra_float_digits\n", func, result, status);
+           mylog("sizeof startup packet = %d\n", sizeof(StartupPacket));
 
-   }
+           if (PROTOCOL_63(ci))
+               sock->pversion = PG_PROTOCOL_63;
+           else
+               sock->pversion = PG_PROTOCOL_64;
+           /* Send length of Authentication Block */
+           SOCK_put_int(sock, 4 + sizeof(StartupPacket), 4);
 
-   /* Global settings */
-   if (ci->drivers.conn_settings[0] != '\0')
-   {
-       cs = strdup(ci->drivers.conn_settings);
-#ifdef HAVE_STRTOK_R
-       ptr = strtok_r(cs, ";", &last);
-#else
-       ptr = strtok(cs, ";");
-#endif /* HAVE_STRTOK_R */
-       while (ptr)
-       {
-           result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS, 0);
-           if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-               status = FALSE;
+           sp.protoVersion = (ProtocolVersion) htonl(sock->pversion);
 
-           mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr);
+           strncpy(sp.database, ci->database, SM_DATABASE);
+           strncpy(sp.user, ci->username, SM_USER);
 
-#ifdef HAVE_STRTOK_R
-           ptr = strtok_r(NULL, ";", &last);
-#else
-           ptr = strtok(NULL, ";");
-#endif /* HAVE_STRTOK_R */
+           SOCK_put_n_char(sock, (char *) &sp, sizeof(StartupPacket));
+           SOCK_flush_output(sock);
        }
 
-       free(cs);
+       mylog("sent the authentication block.\n");
+
+       if (sock->errornumber != 0)
+       {
+           CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Sending the authentication packet failed", func);
+           return 0;
+       }
+       mylog("sent the authentication block successfully.\n");
    }
 
-   /* Per Datasource settings */
-   if (ci->conn_settings[0] != '\0')
+
+   mylog("gonna do authentication\n");
+
+
+   /*
+    * Now get the authentication request from backend
+    */
+
+   if (!PROTOCOL_62(ci))
    {
-       cs = strdup(ci->conn_settings);
-#ifdef HAVE_STRTOK_R
-       ptr = strtok_r(cs, ";", &last);
-#else
-       ptr = strtok(cs, ";");
-#endif /* HAVE_STRTOK_R */
-       while (ptr)
+       BOOL        before_64 = PG_VERSION_LT(self, 6.4),
+                   ReadyForQuery = FALSE, retry = FALSE;
+       uint32  leng;
+
+       do
        {
-           result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS, 0);
-           if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-               status = FALSE;
+           if (password_req != AUTH_REQ_OK)
+               beresp = 'R';
+           else
+           {
+               beresp = SOCK_get_char(sock);
+               mylog("auth got '%c'\n", beresp);
+               if (PROTOCOL_74(ci))
+               {
+                   if (beresp != 'E' || startPacketReceived)
+                   {
+                       leng = SOCK_get_int(sock, 4);
+inolog("leng=%d\n", leng);
+                   }
+                   else
+                       strcpy(ci->protocol, PG74REJECTED);
+               }
+               startPacketReceived = TRUE;
+           }
 
-           mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr);
+           switch (beresp)
+           {
+               case 'E':
+inolog("Ekita\n");
+                   handle_error_message(self, msgbuffer, sizeof(msgbuffer), self->sqlstate, func, NULL);
+                   CC_set_error(self, CONN_INVALID_AUTHENTICATION, msgbuffer, func);
+                   qlog("ERROR from backend during authentication: '%s'\n", msgbuffer);
+                   if (strnicmp(msgbuffer, "Unsupported frontend protocol", 29) == 0)
+                       retry = TRUE;
+                   else if (strncmp(msgbuffer, "FATAL:", 6) == 0 &&
+                        strnicmp(msgbuffer + 8, "unsupported frontend protocol", 29) == 0)
+                       retry = TRUE;
+                   if (retry)
+                   {           /* retry older version */
+                       if (PROTOCOL_63(ci))
+                           strcpy(ci->protocol, PG62);
+                       else if (PROTOCOL_64(ci))
+                           strcpy(ci->protocol, PG63);
+                       else 
+                           strcpy(ci->protocol, PG64);
+                       SOCK_Destructor(sock);
+                       self->sock = (SocketClass *) 0;
+                       CC_initialize_pg_version(self);
+                       goto another_version_retry;
+                   }
 
-#ifdef HAVE_STRTOK_R
-           ptr = strtok_r(NULL, ";", &last);
-#else
-           ptr = strtok(NULL, ";");
-#endif /* HAVE_STRTOK_R */
-       }
+                   return 0;
+               case 'R':
+
+                   if (password_req != AUTH_REQ_OK)
+                   {
+                       mylog("in 'R' password_req=%s\n", ci->password);
+                       areq = password_req;
+                       if (salt_para)
+                           memcpy(salt, salt_para, sizeof(salt));
+                       password_req = AUTH_REQ_OK;
+                   }
+                   else
+                   {
+
+                       areq = SOCK_get_int(sock, 4);
+                       if (areq == AUTH_REQ_MD5)
+                           SOCK_get_n_char(sock, salt, 4);
+                       else if (areq == AUTH_REQ_CRYPT)
+                           SOCK_get_n_char(sock, salt, 2);
+
+                       mylog("areq = %d\n", areq);
+                   }
+                   switch (areq)
+                   {
+                       case AUTH_REQ_OK:
+                           break;
+
+                       case AUTH_REQ_KRB4:
+                           CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Kerberos 4 authentication not supported", func);
+                           return 0;
+
+                       case AUTH_REQ_KRB5:
+                           CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Kerberos 5 authentication not supported", func);
+                           return 0;
+
+                       case AUTH_REQ_PASSWORD:
+                           mylog("in AUTH_REQ_PASSWORD\n");
+
+                           if (ci->password[0] == '\0')
+                           {
+                               CC_set_error(self, CONNECTION_NEED_PASSWORD, "A password is required for this connection.", func);
+                               return -areq;       /* need password */
+                           }
+
+                           mylog("past need password\n");
+
+                           SOCK_put_int(sock, 4 + strlen(ci->password) + 1, 4);
+                           SOCK_put_n_char(sock, ci->password, strlen(ci->password) + 1);
+                           SOCK_flush_output(sock);
+
+                           mylog("past flush\n");
+                           break;
+
+                       case AUTH_REQ_CRYPT:
+                           CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Password crypt authentication not supported", func);
+                           return 0;
+                       case AUTH_REQ_MD5:
+                           mylog("in AUTH_REQ_MD5\n");
+                           if (ci->password[0] == '\0')
+                           {
+                               CC_set_error(self, CONNECTION_NEED_PASSWORD, "A password is required for this connection.", func);
+                               if (salt_para)
+                                   memcpy(salt_para, salt, sizeof(salt));
+                               return -areq; /* need password */
+                           }
+                           if (md5_auth_send(self, salt))
+                           {
+                               CC_set_error(self, CONN_INVALID_AUTHENTICATION, "md5 hashing failed", func);
+                               return 0;
+                           }
+                           break;
+
+                       case AUTH_REQ_SCM_CREDS:
+                           CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Unix socket credential authentication not supported", func);
+                           return 0;
+
+                       default:
+                           CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Unknown authentication type", func);
+                           return 0;
+                   }
+                   break;
+               case 'S': /* parameter status */
+                   getParameterValues(self);
+                   break;
+               case 'K':       /* Secret key (6.4 protocol) */
+                   self->be_pid = SOCK_get_int(sock, 4);       /* pid */
+                   self->be_key = SOCK_get_int(sock, 4);       /* key */
 
-       free(cs);
+                   break;
+               case 'Z':       /* Backend is ready for new query (6.4) */
+                   EatReadyForQuery(self);
+                   ReadyForQuery = TRUE;
+                   break;
+               case 'N':   /* Notices may come */
+                   handle_notice_message(self, notice, sizeof(notice), self->sqlstate, "CC_connect", NULL);
+                   break;
+               default:
+                   CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Unexpected protocol character during authentication", func);
+                   return 0;
+           }
+
+           /*
+            * There were no ReadyForQuery responce before 6.4.
+            */
+           if (before_64 && areq == AUTH_REQ_OK)
+               ReadyForQuery = TRUE;
+       } while (!ReadyForQuery);
    }
 
 
-   PGAPI_FreeStmt(hstmt, SQL_DROP);
+   CC_clear_error(self);       /* clear any password error */
 
-   return status;
-}
+   /*
+    * send an empty query in order to find out whether the specified
+    * database really exists on the server machine
+    */
+   if (!PROTOCOL_74(ci))
+   {
+       mylog("sending an empty query...\n");
 
+       res = CC_send_query(self, " ", NULL, 0, NULL);
+       if (res == NULL ||
+           (QR_get_rstatus(res) != PGRES_EMPTY_QUERY &&
+            QR_command_nonfatal(res)))
+       {
+           CC_set_error(self, CONNECTION_NO_SUCH_DATABASE, "The database does not exist on the server\nor user authentication failed.", func);
+           QR_Destructor(res);
+       return 0;
+       }
+       QR_Destructor(res);
 
-/*
- * This function is just a hack to get the oid of our Large Object oid type.
- * If a real Large Object oid type is made part of Postgres, this function
- * will go away and the define 'PG_TYPE_LO' will be updated.
- */
-void
-CC_lookup_lo(ConnectionClass *self)
+       mylog("empty query seems to be OK.\n");
+   }
+
+   /* 
+    * Get the version number first so we can check it before
+    * sending options that are now obsolete. DJP 21/06/2002
+    */
+inolog("CC_lookup_pg_version\n");
+   if (!PROTOCOL_74(ci))
+   {
+       CC_lookup_pg_version(self); /* Get PostgreSQL version for
+                          SQLGetInfo use */
+       CC_setenv(self);
+   }
+
+   return 1;
+}  
+
+char
+CC_connect(ConnectionClass *self, char password_req, char *salt_para)
 {
-   HSTMT       hstmt;
-   StatementClass *stmt;
-   RETCODE     result;
-   CSTR func = "CC_lookup_lo";
+   // StartupPacket sp;
+   // StartupPacket6_2 sp62;
+   // QResultClass *res;
+   // SocketClass *sock;
+   ConnInfo   *ci = &(self->connInfo);
+   // int          areq = -1;
+   // int          beresp;
+   // char     msgbuffer[ERROR_MSG_LENGTH];
+   // char     salt[5], notice[512];
+   CSTR        func = "CC_connect";
+   char       ret;
+   // char    *encoding;
+   // BOOL startPacketReceived = FALSE;
+   BOOL    usessl = TRUE;
 
    mylog("%s: entering...\n", func);
 
-/*
- * This function must use the local odbc API functions since the odbc state
- * has not transitioned to "connected" yet.
- */
-   result = PGAPI_AllocStmt(self, &hstmt);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-       return;
-   stmt = (StatementClass *) hstmt;
+   mylog("sslmode=%s\n", self->connInfo.sslmode);
+   if (self->connInfo.sslmode[0] != 'd')
+       ret = LIBPQ_CC_connect(self, password_req, salt_para);
+   else
+       ret = original_CC_connect(self, password_req, salt_para);
+   if (ret <= 0)
+       return ret;
 
-   result = PGAPI_ExecDirect(hstmt, "select oid from pg_type where typname='" PG_TYPE_LO_NAME "'", SQL_NTS, 0);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+   CC_set_translation(self);
+
+   /*
+    * Send any initial settings
+    */
+
+   /*
+    * Since these functions allocate statements, and since the connection
+    * is not established yet, it would violate odbc state transition
+    * rules.  Therefore, these functions call the corresponding local
+    * function instead.
+    */
+inolog("CC_send_settings\n");
+   CC_send_settings(self);
+
+   CC_clear_error(self);           /* clear any error */
+   CC_lookup_lo(self);         /* a hack to get the oid of
+                          our large object oid type */
+
+   /*
+    *  Multibyte handling is available ?
+    */
+   if (PG_VERSION_GE(self, 6.4))
    {
-       PGAPI_FreeStmt(hstmt, SQL_DROP);
-       return;
+       CC_lookup_characterset(self);
+       if (CC_get_errornumber(self) != 0)
+           return 0;
+#ifdef UNICODE_SUPPORT
+       if (self->unicode)
+       {
+           if (!self->original_client_encoding ||
+               (stricmp(self->original_client_encoding, "UNICODE") &&
+               stricmp(self->original_client_encoding, "UTF8")))
+           {
+               QResultClass    *res;
+               if (PG_VERSION_LT(self, 7.1))
+               {
+                   CC_set_error(self, CONN_NOT_IMPLEMENTED_ERROR, "UTF-8 conversion isn't implemented before 7.1", func);
+                   return 0;
+               }
+               if (self->original_client_encoding)
+                   free(self->original_client_encoding);
+               self->original_client_encoding = NULL;
+               if (res = CC_send_query(self, "set client_encoding to 'UTF8'", NULL, 0, NULL), QR_command_maybe_successful(res))
+               {
+                   self->original_client_encoding = strdup("UNICODE");
+                   self->ccsc = pg_CS_code(self->original_client_encoding);
+               }
+               QR_Destructor(res);
+           }
+       }
+#else
+       {
+       }
+#endif /* UNICODE_SUPPORT */
    }
-
-   result = PGAPI_Fetch(hstmt);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+#ifdef UNICODE_SUPPORT
+   else if (self->unicode)
    {
-       PGAPI_FreeStmt(hstmt, SQL_DROP);
-       return;
+       CC_set_error(self, CONN_NOT_IMPLEMENTED_ERROR, "Unicode isn't supported before 6.4", func);
+       return 0;
+   }
+#endif /* UNICODE_SUPPORT */
+   ci->updatable_cursors = DISALLOW_UPDATABLE_CURSORS; 
+   if (ci->allow_keyset &&
+       PG_VERSION_GE(self, 7.0)) /* Tid scan since 7.0 */
+   {
+       if (ci->drivers.lie || !ci->drivers.use_declarefetch)
+           ci->updatable_cursors |= (ALLOW_STATIC_CURSORS | ALLOW_KEYSET_DRIVEN_CURSORS | ALLOW_BULK_OPERATIONS | SENSE_SELF_OPERATIONS);
+       else
+       {
+           if (PG_VERSION_GE(self, 7.4)) /* HOLDABLE CURSORS since 7.4 */
+               ci->updatable_cursors |= (ALLOW_STATIC_CURSORS | SENSE_SELF_OPERATIONS);
+       }
    }
 
-   result = PGAPI_GetData(hstmt, 1, SQL_C_SLONG, &self->lobj_type, sizeof(self->lobj_type), NULL);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+   CC_clear_error(self);       /* clear any initial command errors */
+   self->status = CONN_CONNECTED;
+
+   mylog("%s: returning...\n", func);
+
+   return 1;
+}
+
+
+char
+CC_add_statement(ConnectionClass *self, StatementClass *stmt)
+{
+   int         i;
+
+   mylog("CC_add_statement: self=%x, stmt=%x\n", self, stmt);
+
+   for (i = 0; i < self->num_stmts; i++)
    {
-       PGAPI_FreeStmt(hstmt, SQL_DROP);
-       return;
+       if (!self->stmts[i])
+       {
+           stmt->hdbc = self;
+           self->stmts[i] = stmt;
+           return TRUE;
+       }
    }
 
-   mylog("Got the large object oid: %d\n", self->lobj_type);
-   qlog("    [ Large Object oid = %d ]\n", self->lobj_type);
+   /* no more room -- allocate more memory */
+   self->stmts = (StatementClass **) realloc(self->stmts, sizeof(StatementClass *) * (STMT_INCREMENT + self->num_stmts));
+   if (!self->stmts)
+       return FALSE;
 
-   result = PGAPI_FreeStmt(hstmt, SQL_DROP);
+   memset(&self->stmts[self->num_stmts], 0, sizeof(StatementClass *) * STMT_INCREMENT);
+
+   stmt->hdbc = self;
+   self->stmts[self->num_stmts] = stmt;
+
+   self->num_stmts += STMT_INCREMENT;
+
+   return TRUE;
+}
+
+
+char
+CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
+{
+   int         i;
+
+   for (i = 0; i < self->num_stmts; i++)
+   {
+       if (self->stmts[i] == stmt && stmt->status != STMT_EXECUTING)
+       {
+           self->stmts[i] = NULL;
+           return TRUE;
+       }
+   }
+
+   return FALSE;
 }
 
+int    CC_get_max_idlen(ConnectionClass *self)
+{
+   int len = self->max_identifier_length;
+
+   if  (len < 0)
+   {
+       QResultClass    *res;
+
+       res = CC_send_query(self, "show max_identifier_length", NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+       if (QR_command_maybe_successful(res))
+           len = self->max_identifier_length = atoi(res->command);
+       QR_Destructor(res);
+   }
+mylog("max_identifier_length=%d\n", len);
+   return len < 0 ? 0 : len; 
+}
 
 /*
- * This function gets the version of PostgreSQL that we're connected to.
- * This is used to return the correct info in SQLGetInfo
- * DJP - 25-1-2001
+ * Create a more informative error message by concatenating the connection
+ * error message with its socket error message.
  */
+char *
+CC_create_errormsg(ConnectionClass *self)
+{
+   SocketClass *sock = self->sock;
+   int         pos;
+   char     msg[4096];
+
+   mylog("enter CC_create_errormsg\n");
+
+   msg[0] = '\0';
+
+   if (CC_get_errormsg(self))
+       strncpy(msg, CC_get_errormsg(self), sizeof(msg));
+
+   mylog("msg = '%s'\n", msg);
+
+   if (sock && sock->errormsg && sock->errormsg[0] != '\0')
+   {
+       pos = strlen(msg);
+       snprintf(&msg[pos], sizeof(msg) - pos, ";\n%s", sock->errormsg);
+   }
+
+   mylog("exit CC_create_errormsg\n");
+   return msg ? strdup(msg) : NULL;
+}
+
+
 void
-CC_lookup_pg_version(ConnectionClass *self)
+CC_set_error(ConnectionClass *self, int number, const char *message, const char *func)
 {
-   HSTMT       hstmt;
-   StatementClass *stmt;
-   RETCODE     result;
-   char        szVersion[32];
-   int         major,
-               minor;
-   CSTR        func = "CC_lookup_pg_version";
+   if (self->__error_message)
+       free(self->__error_message);
+   self->__error_number = number;
+   self->__error_message = message ? strdup(message) : NULL;
+   if (func && number != 0)
+       CC_log_error(func, "", self); 
+}
 
-   mylog("%s: entering...\n", func);
 
-/*
- * This function must use the local odbc API functions since the odbc state
- * has not transitioned to "connected" yet.
- */
-   result = PGAPI_AllocStmt(self, &hstmt);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-       return;
-   stmt = (StatementClass *) hstmt;
+void
+CC_set_errormsg(ConnectionClass *self, const char *message)
+{
+   if (self->__error_message)
+       free(self->__error_message);
+   self->__error_message = message ? strdup(message) : NULL;
+}
 
-   /* get the server's version if possible  */
-   result = PGAPI_ExecDirect(hstmt, "select version()", SQL_NTS, 0);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-   {
-       PGAPI_FreeStmt(hstmt, SQL_DROP);
-       return;
-   }
 
-   result = PGAPI_Fetch(hstmt);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-   {
-       PGAPI_FreeStmt(hstmt, SQL_DROP);
-       return;
-   }
+char
+CC_get_error(ConnectionClass *self, int *number, char **message)
+{
+   int         rv;
+   char *msgcrt;
 
-   result = PGAPI_GetData(hstmt, 1, SQL_C_CHAR, self->pg_version, MAX_INFO_STRING, NULL);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+   mylog("enter CC_get_error\n");
+
+   /* Create a very informative errormsg if it hasn't been done yet. */
+   if (!self->errormsg_created)
    {
-       PGAPI_FreeStmt(hstmt, SQL_DROP);
-       return;
+       msgcrt = CC_create_errormsg(self);
+       if (self->__error_message)
+           free(self->__error_message);
+       self->__error_message = msgcrt;
+       self->errormsg_created = TRUE;
    }
 
-   /*
-    * Extract the Major and Minor numbers from the string. This assumes
-    * the string starts 'Postgresql X.X'
-    */
-   strcpy(szVersion, "0.0");
-   if (sscanf(self->pg_version, "%*s %d.%d", &major, &minor) >= 2)
+   if (CC_get_errornumber(self))
    {
-       sprintf(szVersion, "%d.%d", major, minor);
-       self->pg_version_major = major;
-       self->pg_version_minor = minor;
+       *number = CC_get_errornumber(self);
+       *message = CC_get_errormsg(self);
    }
-   self->pg_version_number = (float) atof(szVersion);
-   if (PG_VERSION_GE(self, 7.3))
-       self->schema_support = 1;
-
-   mylog("Got the PostgreSQL version string: '%s'\n", self->pg_version);
-   mylog("Extracted PostgreSQL version number: '%1.1f'\n", self->pg_version_number);
-   qlog("    [ PostgreSQL version string = '%s' ]\n", self->pg_version);
-   qlog("    [ PostgreSQL version number = '%1.1f' ]\n", self->pg_version_number);
+   rv = (CC_get_errornumber(self) != 0);
 
-   result = PGAPI_FreeStmt(hstmt, SQL_DROP);
-}
+   self->__error_number = 0;       /* clear the error */
 
-int
-CC_get_max_query_len(const ConnectionClass *conn)
-{
-   int         value;
+   mylog("exit CC_get_error\n");
 
-   /* Long Queries in 7.0+ */
-   if (PG_VERSION_GE(conn, 7.0))
-       value = 0 /* MAX_STATEMENT_LEN */ ;
-   /* Prior to 7.0 we used 2*BLCKSZ */
-   else if (PG_VERSION_GE(conn, 6.5))
-       value = (2 * BLCKSZ);
-   else
-       /* Prior to 6.5 we used BLCKSZ */
-       value = BLCKSZ;
-   return value;
+   return rv;
 }
 
-/*
- * This doesn't really return the CURRENT SCHEMA
- * but there's no alternative.
- */
-const char *
-CC_get_current_schema(ConnectionClass *conn)
+
+static void CC_clear_cursors(ConnectionClass *self, BOOL on_abort)
 {
-   if (!conn->current_schema && conn->schema_support)
-   {
-       QResultClass    *res;
+   int i;
+   StatementClass  *stmt;
+   QResultClass    *res;
 
-       if (res = CC_send_query(conn, "select current_schema()", NULL, CLEAR_RESULT_ON_ABORT), res)
+   if (!self->ncursors)
+       return;
+   for (i = 0; i < self->num_stmts; i++)
+   {
+       stmt = self->stmts[i];
+       if (stmt && (res = SC_get_Result(stmt)) &&
+           QR_get_cursor(res))
        {
-           if (QR_get_num_total_tuples(res) == 1)
-               conn->current_schema = strdup(QR_get_value_backend_row(res, 0, 0));
-           QR_Destructor(res);
+           if ((on_abort && !QR_is_permanent(res)) ||
+               !QR_is_withhold(res))
+           /*
+            * non-holdable cursors are automatically closed
+            * at commit time.
+            * all non-permanent cursors are automatically closed
+            * at rollback time.
+            */ 
+               QR_set_cursor(res, NULL);
+           else if (!QR_is_permanent(res))
+           {
+               QResultClass    *wres;
+               char    cmd[64];
+
+               snprintf(cmd, sizeof(cmd), "MOVE 0 in \"%s\"", QR_get_cursor(res));
+               wres = CC_send_query(self, cmd, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+               if (QR_command_maybe_successful(wres))
+                   QR_set_permanent(res);
+               else
+                   QR_set_cursor(res, NULL);
+               QR_Destructor(wres);
+           }
        }
    }
-   return (const char *) conn->current_schema;
 }
-
-int    CC_mark_a_plan_to_discard(ConnectionClass *conn, const char *plan)
+   
+void   CC_on_commit(ConnectionClass *conn)
 {
-   int cnt = conn->num_discardp + 1;
-   char    *pname;
-
-   CC_REALLOC_return_with_error(conn->discardp, char *,
-       (cnt * sizeof(char *)), conn, "Couldn't alloc discardp.", -1) 
-   CC_MALLOC_return_with_error(pname, char, (strlen(plan) + 1),
-       conn, "Couldn't alloc discardp mem.", -1)
-   strcpy(pname, plan);
-   conn->discardp[conn->num_discardp++] = pname; 
-   return 1;
+   if (CC_is_in_trans(conn))
+   {
+       CC_set_no_trans(conn);
+       CC_set_no_manual_trans(conn);
+   }
+   CC_clear_cursors(conn, FALSE);
+   CC_discard_marked_objects(conn);
+   if (conn->result_uncommitted)
+   {
+       ProcessRollback(conn, FALSE, FALSE);
+       conn->result_uncommitted = 0;
+   }
 }
-int    CC_discard_marked_plans(ConnectionClass *conn)
+void   CC_on_abort(ConnectionClass *conn, UDWORD opt)
 {
-   int i, cnt;
-   QResultClass *res;
-   char    cmd[32];
+   BOOL    set_no_trans = FALSE;
 
-   if ((cnt = conn->num_discardp) <= 0)
-       return 0;
-   for (i = cnt - 1; i >= 0; i--)
+mylog("CC_on_abort in\n");
+   if (0 != (opt & CONN_DEAD)) /* CONN_DEAD implies NO_TRANS also */
+       opt |= NO_TRANS;
+   if (CC_is_in_trans(conn))
    {
-       sprintf(cmd, "DEALLOCATE \"%s\"", conn->discardp[i]);
-       res = CC_send_query(conn, cmd, NULL, CLEAR_RESULT_ON_ABORT);
-       if (res)
+       if (0 != (opt & NO_TRANS))
        {
-           QR_Destructor(res);
-           free(conn->discardp[i]);
-           conn->num_discardp--;
+           CC_set_no_trans(conn);
+           CC_set_no_manual_trans(conn);
+           set_no_trans = TRUE;
        }
-       else
-           return -1;
    }
-   return 1;
+   CC_clear_cursors(conn, TRUE);
+   if (0 != (opt & CONN_DEAD))
+   {
+       conn->status = CONN_DOWN;
+       if (conn->sock)
+       {
+           SOCK_Destructor(conn->sock);
+           conn->sock = NULL;
+       }
+   }
+   else if (set_no_trans)
+       CC_discard_marked_objects(conn);
+   if (conn->result_uncommitted)
+   {
+       ProcessRollback(conn, TRUE, FALSE);
+       conn->result_uncommitted = 0;
+   }
 }
 
-
-static void
-CC_handle_notice(void *arg, const char *msg)
+void   CC_on_abort_partial(ConnectionClass *conn)
 {
-       QResultClass    *qres;
-
-       qres = (QResultClass*)(arg);
-
-       if (qres == NULL)
-       {
-           /* Log the notice to stderr and any logs 'cos */
-           /* there's not much else we can do with it.   */
-           fprintf(stderr, "NOTICE from backend outside of a query: '%s'\n", msg);
-           mylog("~~~ NOTICE: '%s'\n", msg);
-           qlog("NOTICE from backend outside of a query: '%s'\n", msg);
-           return;
-       }
-
-       if (QR_command_successful(qres))
-       {
-               QR_set_status(qres, PGRES_NONFATAL_ERROR);
-               QR_set_notice(qres, msg);       /* will dup this string */
-               mylog("~~~ NOTICE: '%s'\n", msg);
-               qlog("NOTICE from backend during send_query: '%s'\n", msg);
-       }
+mylog("CC_on_abort_partial in\n");
+   ProcessRollback(conn, TRUE, TRUE);
+   CC_discard_marked_objects(conn);
 }
 
 /*
- * Connection class implementation using libpq.
- * Memory Allocation for PGconn is handled by libpq.
+ * The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
+ * the same existing QResultClass (this occurs when the tuple cache is depleted and
+ * needs to be re-filled).
+ *
+ * The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
+ * (i.e., C3326857) for SQL select statements.  This cursor is then used in future
+ * 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
  */
-ConnectionClass *
-CC_Constructor()
+QResultClass *
+CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag, StatementClass *stmt)
 {
-   ConnectionClass *rv;
-
-   rv = (ConnectionClass *) malloc(sizeof(ConnectionClass));
-
-   if (rv != NULL)
-   {
-       rv->henv = NULL;        /* not yet associated with an environment */
-
-       rv->__error_message = NULL;
-       rv->__error_number = 0;
-       rv->errormsg_created = FALSE;
-       rv->__sqlstate[0] = '\0';
-
-       rv->status = CONN_NOT_CONNECTED;
-       rv->transact_status = CONN_IN_AUTOCOMMIT;       /* autocommit by default */
-
-       CC_conninfo_init(&(rv->connInfo));
-       rv->stmts = (StatementClass **) malloc(sizeof(StatementClass *) * STMT_INCREMENT);
-       if (!rv->stmts)
-        {
-            free(rv);
-           return NULL;
-        }
-       memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT);
-
-       rv->num_stmts = STMT_INCREMENT;
-       rv->descs = (DescriptorClass **) malloc(sizeof(DescriptorClass *) * STMT_INCREMENT);
-       if (!rv->descs)
-        {
-            free(rv->stmts);
-            free(rv);
-           return NULL;
-        }
-       memset(rv->descs, 0, sizeof(DescriptorClass *) * STMT_INCREMENT);
-
-       rv->num_descs = STMT_INCREMENT;
-
-       rv->lobj_type = PG_TYPE_LO_UNDEFINED;
+   CSTR    func = "CC_send_query";
+   QResultClass *cmdres = NULL,
+              *retres = NULL,
+              *res = NULL;
+   BOOL    ignore_abort_on_conn = ((flag & IGNORE_ABORT_ON_CONN) != 0),
+       create_keyset = ((flag & CREATE_KEYSET) != 0),
+       issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self)),
+       rollback_on_error, query_rollback;
+
+   char        swallow, *wq, *ptr;
+   const char *per_query_svp = "_per_query_svp_";
+   int         id;
+   SocketClass *sock = self->sock;
+   int         maxlen,
+               empty_reqs;
+   BOOL        msg_truncated,
+               ReadyToReturn = FALSE,
+               query_completed = FALSE,
+               before_64 = PG_VERSION_LT(self, 6.4),
+               aborted = FALSE,
+               used_passed_result_object = FALSE,
+           discard_next_begin = FALSE,
+           discard_next_savepoint = FALSE,
+           consider_rollback;
+   Int4        response_length;
+   UInt4       leng;
+   ConnInfo    *ci = &(self->connInfo);
+   int     func_cs_count = 0;
 
-       rv->ntables = 0;
-       rv->col_info = NULL;
+   /* ERROR_MSG_LENGTH is suffcient */
+   char msgbuffer[ERROR_MSG_LENGTH + 1];
 
-       rv->translation_option = 0;
-       rv->translation_handle = NULL;
-       rv->DataSourceToDriver = NULL;
-       rv->DriverToDataSource = NULL;
-       rv->driver_version = ODBCVER;
-       memset(rv->pg_version, 0, sizeof(rv->pg_version));
-       rv->pg_version_number = .0;
-       rv->pg_version_major = 0;
-       rv->pg_version_minor = 0;
-       rv->ms_jet = 0;
-       rv->unicode = 0;
-       rv->result_uncommitted = 0;
-       rv->schema_support = 0;
-       rv->isolation = SQL_TXN_READ_COMMITTED;
-       rv->client_encoding = NULL;
-       rv->server_encoding = NULL;
-       rv->current_schema = NULL;
-       rv->num_discardp = 0;
-       rv->discardp = NULL;
-       rv->pgconn = NULL;
+   /* QR_set_command() dups this string so doesn't need static */
+   char        cmdbuffer[ERROR_MSG_LENGTH + 1];
 
-       /* Initialize statement options to defaults */
-       /* Statements under this conn will inherit these options */
+   mylog("send_query(): conn=%x, query='%s'\n", self, query);
+   qlog("conn=%x, query='%s'\n", self, query);
 
-       InitializeStatementOptions(&rv->stmtOptions);
-       InitializeARDFields(&rv->ardOptions);
-       InitializeAPDFields(&rv->apdOptions);
-       INIT_CONN_CS(rv);
+   if (!self->sock)
+   {
+       CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query(connection dead)", func);
+       CC_on_abort(self, CONN_DEAD);
+       return NULL;
    }
-   return rv;
-}
-
-
-char
-CC_Destructor(ConnectionClass *self)
-{
-   mylog("enter CC_Destructor, self=%u\n", self);
-
-   if (self->status == CONN_EXECUTING)
-       return 0;
 
-   CC_cleanup(self);           /* cleanup libpq connection class and statements */
+   /* Indicate that we are sending a query to the backend */
+   maxlen = CC_get_max_query_len(self);
+   if (maxlen > 0 && maxlen < (int) strlen(query) + 1)
+   {
+       CC_set_error(self, CONNECTION_MSG_TOO_LONG, "Query string is too long", func);
+       return NULL;
+   }
 
-   mylog("after CC_Cleanup\n");
+   if ((NULL == query) || (query[0] == '\0'))
+       return NULL;
 
-   /* Free up statement holders */
-   if (self->stmts)
+   if (SOCK_get_errcode(sock) != 0)
    {
-       free(self->stmts);
-       self->stmts = NULL;
+       CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend", func);
+       CC_on_abort(self, CONN_DEAD);
+       return NULL;
    }
 
-   if (self->descs)
+   rollback_on_error = (flag & ROLLBACK_ON_ERROR) != 0;
+#define    return DONT_CALL_RETURN_FROM_HERE???
+   ENTER_INNER_CONN_CS(self, func_cs_count);
+   consider_rollback = (issue_begin || (CC_is_in_trans(self) && !CC_is_in_error_trans(self)) || strnicmp(query, "begin", 5) == 0);
+   if (rollback_on_error)
+       rollback_on_error = consider_rollback;
+   query_rollback = (rollback_on_error && PG_VERSION_GE(self, 8.0));
+   if (!query_rollback && consider_rollback )
    {
-       free(self->descs);
-       self->descs = NULL;
+       if (stmt)
+       {
+           StatementClass  *astmt = SC_get_ancestor(stmt);
+           if (!SC_accessed_db(astmt))
+           {
+               if (SQL_ERROR == SetStatementSvp(astmt))
+               {
+                   SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal savepoint error", func);
+                   goto cleanup;
+               }
+           }
+       }
    }
 
-   mylog("after free statement holders\n");
+   SOCK_put_char(sock, 'Q');
+   if (SOCK_get_errcode(sock) != 0)
+   {
+       CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend", func);
+       CC_on_abort(self, CONN_DEAD);
+       goto cleanup;
+   }
 
-   if (self->__error_message)
-       free(self->__error_message);
-   DELETE_CONN_CS(self);
-   free(self);
+   if (PROTOCOL_74(ci))
+   {
+       leng = strlen(query);
+       if (issue_begin)
+           leng += strlen("BEGIN;");
+       if (query_rollback)
+           leng += (10 + strlen(per_query_svp) + 1);
+       leng++;
+       SOCK_put_int(sock, leng + 4, 4);
+inolog("leng=%d\n", leng);
+   }
+   if (issue_begin)
+   {
+       SOCK_put_n_char(sock, "BEGIN;", 6);
+       discard_next_begin = TRUE;
+   }
+   if (query_rollback)
+   {
+       char cmd[64];
 
-   mylog("exit CC_Destructor\n");
+       snprintf(cmd, sizeof(cmd), "SAVEPOINT %s;", per_query_svp);
+       SOCK_put_n_char(sock, cmd, strlen(cmd));
+       discard_next_savepoint = TRUE;
+   }
+   SOCK_put_string(sock, query);
+   SOCK_flush_output(sock);
 
-   return 1;
-}
+   if (SOCK_get_errcode(sock) != 0)
+   {
+       CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend", func);
+       CC_on_abort(self, CONN_DEAD);
+       goto cleanup;
+   }
 
-/* This is called by SQLDisconnect also */
-char
-CC_cleanup(ConnectionClass *self)
-{
-   int         i;
-   StatementClass *stmt;
-   DescriptorClass *desc;
+   mylog("send_query: done sending query\n");
+   empty_reqs = 0;
+   for (wq = query; isspace((UCHAR) *wq); wq++)
+       ;
+   if (*wq == '\0')
+       empty_reqs = 1;
+   cmdres = qi ? qi->result_in : NULL;
+   if (cmdres)
+       used_passed_result_object = TRUE;
+   else
+   {
+       cmdres = QR_Constructor();
+       if (!cmdres)
+       {
+           CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.", func);
+           goto cleanup;
+       }
+   }
+   res = cmdres;
+   while (!ReadyToReturn)
+   {
+       /* what type of message is coming now ? */
+       id = SOCK_get_id(sock);
 
-   if (self->status == CONN_EXECUTING)
-       return FALSE;
+       if ((SOCK_get_errcode(sock) != 0) || (id == EOF))
+       {
+           CC_set_error(self, CONNECTION_NO_RESPONSE, "No response from the backend", func);
 
-   mylog("in CC_Cleanup, self=%u\n", self);
+           mylog("send_query: 'id' - %s\n", CC_get_errormsg(self));
+           CC_on_abort(self, CONN_DEAD);
+           ReadyToReturn = TRUE;
+           retres = NULL;
+           break;
+       }
 
-   /* Cancel an ongoing transaction */
-   /* We are always in the middle of a transaction, */
-   /* even if we are in auto commit. */
-   if (self->pgconn)
-   {
-       CC_abort(self);
+       mylog("send_query: got id = '%c'\n", id);
 
-       mylog("after CC_abort\n");
+       response_length = SOCK_get_response_length(sock);
+inolog("send_query response_length=%d\n", response_length);
+       switch (id)
+       {
+           case 'A':           /* Asynchronous Messages are ignored */
+               (void) SOCK_get_int(sock, 4);   /* id of notification */
+               SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
+               /* name of the relation the message comes from */
+               break;
+           case 'C':           /* portal query command, no tuples
+                                * returned */
+               /* read in the return message from the backend */
+               SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
+               if (SOCK_get_errcode(sock) != 0)
+               {
+                   CC_set_error(self, CONNECTION_NO_RESPONSE, "No response from backend while receiving a portal query command", func);
+                   mylog("send_query: 'C' - %s\n", CC_get_errormsg(self));
+                   CC_on_abort(self, CONN_DEAD);
+                   ReadyToReturn = TRUE;
+                   retres = NULL;
+               }
+               else
+               {
+                   mylog("send_query: ok - 'C' - %s\n", cmdbuffer);
+
+                   if (query_completed)    /* allow for "show" style notices */
+                   {
+                       res->next = QR_Constructor();
+                       res = res->next;
+                   } 
+
+                   mylog("send_query: setting cmdbuffer = '%s'\n", cmdbuffer);
+
+                   trim(cmdbuffer); /* get rid of trailing space */ 
+                   if (strnicmp(cmdbuffer, "BEGIN", 5) == 0)
+                   {
+                       CC_set_in_trans(self);
+                       if (discard_next_begin) /* disicard the automatically issued BEGIN */
+                       {
+                           discard_next_begin = FALSE;
+                           continue; /* discard the result */
+                       }
+                   }
+                   else if (strnicmp(cmdbuffer, "SAVEPOINT", 9) == 0)
+                   {
+                       if (discard_next_savepoint)
+                       {
+inolog("Discarded the first SAVEPOINT\n");
+                           discard_next_savepoint = FALSE;
+                           continue; /* discard the result */
+                       }
+                   }
+                   else
+                   {
+                       if (strnicmp(cmdbuffer, "ROLLBACK", 8) == 0)
+                       {
+                           if (PROTOCOL_74(&(self->connInfo)))
+                               CC_set_in_error_trans(self); /* mark the transaction error in case of manual rollback */
+                           else
+                               CC_on_abort(self, NO_TRANS);
+                       }
+                       else if (!PROTOCOL_74(&(self->connInfo)))
+                       {
+                           if (strnicmp(cmdbuffer, "COMMIT", 6) == 0)
+                               CC_on_commit(self);
+                           else if (strnicmp(cmdbuffer, "END", 3) == 0)
+                               CC_on_commit(self);
+                           else if (strnicmp(cmdbuffer, "ABORT", 5) == 0)
+                               CC_on_abort(self, NO_TRANS);
+                       }
+                       else
+                       {
+                           ptr = strrchr(cmdbuffer, ' ');
+                           if (ptr)
+                               res->recent_processed_row_count = atoi(ptr + 1);
+                           else
+                               res->recent_processed_row_count = -1;
+                       }
+                   }
+
+                   if (QR_command_successful(res))
+                       QR_set_rstatus(res, PGRES_COMMAND_OK);
+                   QR_set_command(res, cmdbuffer);
+                   query_completed = TRUE;
+                   mylog("send_query: returning res = %x\n", res);
+                   if (!before_64)
+                       break;
+
+                   /*
+                    * (Quotation from the original comments) since
+                    * backend may produce more than one result for some
+                    * commands we need to poll until clear so we send an
+                    * empty query, and keep reading out of the pipe until
+                    * an 'I' is received
+                    */
+
+                   if (empty_reqs == 0)
+                   {
+                       SOCK_put_string(sock, "Q ");
+                       SOCK_flush_output(sock);
+                       empty_reqs++;
+                   }
+               }
+               break;
+           case 'Z':           /* Backend is ready for new query (6.4) */
+               if (empty_reqs == 0)
+               {
+                   ReadyToReturn = TRUE;
+                   if (aborted || query_completed)
+                       retres = cmdres;
+                   else
+                       ReadyToReturn = FALSE;
+               }
+               EatReadyForQuery(self);
+               break;
+           case 'N':           /* NOTICE: */
+               msg_truncated = handle_notice_message(self, cmdbuffer, sizeof(cmdbuffer), res->sqlstate, "send_query", res);
+               break;      /* dont return a result -- continue
+                                * reading */
+
+           case 'I':           /* The server sends an empty query */
+               /* There is a closing '\0' following the 'I', so we eat it */
+               if (PROTOCOL_74(ci) && 0 == response_length)
+                   swallow = '\0';
+               else
+                   swallow = SOCK_get_char(sock);
+               if ((swallow != '\0') || SOCK_get_errcode(sock) != 0)
+               {
+                   CC_set_errornumber(self, CONNECTION_BACKEND_CRAZY);
+                   QR_set_message(res, "Unexpected protocol character from backend (send_query - I)");
+                   QR_set_rstatus(res, PGRES_FATAL_ERROR);
+                   ReadyToReturn = TRUE;
+                   retres = cmdres;
+                   break;
+               }
+               else
+               {
+                   /* We return the empty query */
+                   QR_set_rstatus(res, PGRES_EMPTY_QUERY);
+               }
+               if (empty_reqs > 0)
+               {
+                   if (--empty_reqs == 0)
+                       query_completed = TRUE;
+               }
+               break;
+           case 'E':
+               msg_truncated = handle_error_message(self, msgbuffer, sizeof(msgbuffer), res->sqlstate, "send_query", res);
 
-       /* This closes the connection to the database */
-       LIBPQ_Destructor(self->pgconn);
-       self->pgconn = NULL;
-   }
+               /* We should report that an error occured. Zoltan */
+               aborted = TRUE;
 
-   mylog("after LIBPQ destructor\n");
+               query_completed = TRUE;
+               break;
 
-   /* Free all the stmts on this connection */
-   for (i = 0; i < self->num_stmts; i++)
-   {
-       stmt = self->stmts[i];
-       if (stmt)
-       {
-           stmt->hdbc = NULL;  /* prevent any more dbase interactions */
+           case 'P':           /* get the Portal name */
+               SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
+               break;
+           case 'T':           /* Tuple results start here */
+               if (query_completed)
+               {
+                   res->next = QR_Constructor();
+                   if (!res->next)
+                   {
+                       CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.", func);
+                       ReadyToReturn = TRUE;
+                       retres = NULL;
+                       break;
+                   }
+                   if (create_keyset)
+                   {
+                       QR_set_haskeyset(res->next);
+                       if (stmt)
+                           res->num_key_fields = stmt->num_key_fields;
+                   }
+                   mylog("send_query: 'T' no result_in: res = %x\n", res->next);
+                   res = res->next;
+
+                   if (qi)
+                       QR_set_cache_size(res, qi->row_size);
+               }
+               if (!used_passed_result_object)
+               {
+                   const char *cursor = qi ? qi->cursor : NULL;
+                   if (create_keyset)
+                   {
+                       QR_set_haskeyset(res);
+                       if (stmt)
+                           res->num_key_fields = stmt->num_key_fields;
+                       if (cursor && cursor[0])
+                           QR_set_synchronize_keys(res);
+                   }
+                   if (!QR_fetch_tuples(res, self, cursor))
+                   {
+                       CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(res), func);
+                       ReadyToReturn = TRUE;
+                       if (PGRES_FATAL_ERROR == QR_get_rstatus(res))
+                           retres = cmdres;
+                       else
+                           retres = NULL;
+                       break;
+                   }
+                   query_completed = TRUE;
+               }
+               else
+               {               /* next fetch, so reuse an existing result */
+
+                   /*
+                    * called from QR_next_tuple and must return
+                    * immediately.
+                    */
+                   ReadyToReturn = TRUE;
+                   if (!QR_fetch_tuples(res, NULL, NULL))
+                   {
+                       CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(res), func);
+                       retres = NULL;
+                       break;
+                   }
+                   retres = cmdres;
+               }
+               break;
+           case 'D':           /* Copy in command began successfully */
+               if (query_completed)
+               {
+                   res->next = QR_Constructor();
+                   res = res->next;
+               }
+               QR_set_rstatus(res, PGRES_COPY_IN);
+               ReadyToReturn = TRUE;
+               retres = cmdres;
+               break;
+           case 'B':           /* Copy out command began successfully */
+               if (query_completed)
+               {
+                   res->next = QR_Constructor();
+                   res = res->next;
+               }
+               QR_set_rstatus(res, PGRES_COPY_OUT);
+               ReadyToReturn = TRUE;
+               retres = cmdres;
+               break;
+           case 'S':       /* parameter status */
+               getParameterValues(self);
+               break;
+           case 's':       /* portal suspended */
+               QR_set_no_fetching_tuples(res);
+               break;
+           default:
+               /* skip the unexpecte response if possible */
+               if (response_length >= 0)
+                   break;
+               CC_set_error(self, CONNECTION_BACKEND_CRAZY, "Unexpected protocol character from backend (send_query)", func);
+               CC_on_abort(self, CONN_DEAD);
 
-           SC_Destructor(stmt);
+               mylog("send_query: error - %s\n", CC_get_errormsg(self));
+               ReadyToReturn = TRUE;
+               retres = NULL;
+               break;
+       }
 
-           self->stmts[i] = NULL;
+       if (CONN_DOWN == self->status)
+           break;
+       /*
+        * There was no ReadyForQuery response before 6.4.
+        */
+       if (before_64)
+       {
+           if (empty_reqs == 0 && query_completed)
+               break;
        }
    }
 
-   /* Free all the descs on this connection */
-   for (i = 0; i < self->num_descs; i++)
+cleanup:
+   if (rollback_on_error && CC_is_in_trans(self) && !discard_next_savepoint)
    {
-       desc = self->descs[i];
-       if (desc)
+       char    cmd[64];
+
+       cmd[0] = '\0'; 
+       if (query_rollback)
        {
-           DC_get_conn(desc) = NULL;   /* prevent any more dbase interactions */
-           DC_Destructor(desc);
-           free(desc);
-           self->descs[i] = NULL;
+           if (CC_is_in_error_trans(self))
+               snprintf(cmd, sizeof(cmd), "ROLLBACK TO %s;", per_query_svp);
+           snprintf(cmd, sizeof(cmd), "%sRELEASE %s", cmd, per_query_svp);
        }
+       else if (CC_is_in_error_trans(self))
+           strcpy(cmd, "ROLLBACK");
+       if (cmd[0])
+           QR_Destructor(CC_send_query(self, cmd, NULL, IGNORE_ABORT_ON_CONN, NULL));
    }
 
-   /* Check for translation dll */
-#ifdef WIN32
-   if (self->translation_handle)
-   {
-       FreeLibrary(self->translation_handle);
-       self->translation_handle = NULL;
-   }
-#endif
+   CLEANUP_FUNC_CONN_CS(func_cs_count, self);
+#undef return
+   /*
+    * Break before being ready to return.
+    */
+   if (!ReadyToReturn)
+       retres = cmdres;
 
-   self->status = CONN_NOT_CONNECTED;
-   self->transact_status = CONN_IN_AUTOCOMMIT;
-   CC_conninfo_init(&(self->connInfo));
-   if (self->client_encoding)
+   /*
+    * Cleanup garbage results before returning.
+    */
+   if (cmdres && retres != cmdres && !used_passed_result_object)
+       QR_Destructor(cmdres);
+   /*
+    * Cleanup the aborted result if specified
+    */
+   if (retres)
    {
-       free(self->client_encoding);
-       self->client_encoding = NULL;
+       if (aborted)
+       {
+           /** if (ignore_abort_on_conn)
+           {
+               if (!used_passed_result_object)
+               {
+                   QR_Destructor(retres);
+                   retres = NULL;
+               }
+           } **/
+           if (retres)
+           {
+               /*
+                *  discard results other than errors.
+                */
+               QResultClass    *qres;
+               for (qres = retres; qres->next; qres = retres)
+               {
+                   if (QR_get_aborted(qres))
+                       break;
+                   retres = qres->next;
+                   qres->next = NULL;
+                   QR_Destructor(qres);
+               }
+               /*
+                *  If error message isn't set
+                */
+               if (ignore_abort_on_conn)
+                   CC_set_errornumber(self, 0);
+               else if (retres)
+               {
+                   if ((!CC_get_errormsg(self) || !CC_get_errormsg(self)[0]))
+                       CC_set_errormsg(self, QR_get_message(retres));
+                   if (!self->sqlstate[0])
+                       strcpy(self->sqlstate, retres->sqlstate);
+               }
+           }
+       }
    }
-   if (self->server_encoding)
+   return retres;
+}
+
+
+int
+CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *args, int nargs)
+{
+   CSTR    func = "CC_send_function";
+   char        id,
+               c,
+               done;
+   SocketClass *sock = self->sock;
+
+   /* ERROR_MSG_LENGTH is sufficient */
+   char msgbuffer[ERROR_MSG_LENGTH + 1];
+   int         i;
+   int         ret = TRUE;
+   UInt4           leng;
+   Int4            response_length;
+   ConnInfo        *ci;
+   int         func_cs_count = 0; 
+
+   mylog("send_function(): conn=%x, fnid=%d, result_is_int=%d, nargs=%d\n", self, fnid, result_is_int, nargs);
+
+   if (!self->sock)
    {
-       free(self->server_encoding);
-       self->server_encoding = NULL;
+       CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send function(connection dead)", func);
+       CC_on_abort(self, CONN_DEAD);
+       return FALSE;
    }
-   if (self->current_schema)
+
+   if (SOCK_get_errcode(sock) != 0)
    {
-       free(self->current_schema);
-       self->current_schema = NULL;
+       CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send function to backend", func);
+       CC_on_abort(self, CONN_DEAD);
+       return FALSE;
    }
-   /* Free cached table info */
-   if (self->col_info)
+
+#define    return DONT_CALL_RETURN_FROM_HERE???
+   ENTER_INNER_CONN_CS(self, func_cs_count);
+   ci = &(self->connInfo);
+   if (PROTOCOL_74(ci))
    {
-       for (i = 0; i < self->ntables; i++)
+       leng = 4 + sizeof(uint32) + 2 + 2
+           + sizeof(uint16);
+       for (i = 0; i < nargs; i++)
        {
-           if (self->col_info[i]->result)  /* Free the SQLColumns result structure */
-               QR_Destructor(self->col_info[i]->result);
-
-           if (self->col_info[i]->schema)
-               free(self->col_info[i]->schema);
-           free(self->col_info[i]);
+           leng += 4;
+           if (args[i].len >= 0)
+           {
+               if (args[i].isint)
+                   leng += 4;
+               else
+                   leng += args[i].len;
+           }
        }
-       free(self->col_info);
-       self->col_info = NULL;
+       leng += 2;
+       SOCK_put_char(sock, 'F');
+       SOCK_put_int(sock, leng, 4);
    }
-   self->ntables = 0;
-   if (self->num_discardp > 0 && self->discardp)
+   else
+   SOCK_put_string(sock, "F ");
+   if (SOCK_get_errcode(sock) != 0)
    {
-       for (i = 0; i < self->num_discardp; i++)
-           free(self->discardp[i]);
-       self->num_discardp = 0;
+       CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send function to backend", func);
+       CC_on_abort(self, CONN_DEAD);
+       ret = FALSE;
+       goto cleanup;
    }
-   if (self->discardp)
+
+   SOCK_put_int(sock, fnid, 4);
+   if (PROTOCOL_74(ci))
    {
-       free(self->discardp);
-       self->discardp = NULL;
+       SOCK_put_int(sock, 1, 2); /* # of formats */
+       SOCK_put_int(sock, 1, 2); /* the format is binary */
+       SOCK_put_int(sock, nargs, 2);
    }
+   else
+   SOCK_put_int(sock, nargs, 4);
 
-   mylog("exit CC_Cleanup\n");
-   return TRUE;
-}
+   mylog("send_function: done sending function\n");
 
+   for (i = 0; i < nargs; ++i)
+   {
+       mylog("  arg[%d]: len = %d, isint = %d, integer = %d, ptr = %x\n", i, args[i].len, args[i].isint, args[i].u.integer, args[i].u.ptr);
 
-char
-CC_connect(ConnectionClass *self, char password_req, char *salt_para)
-{
-   /* ignore salt_para for now */
-   /* QResultClass *res; */
-   PGconn *pgconn;
-   ConnInfo   *ci = &(self->connInfo);
-   int         connect_return;
-   char       *encoding;
-   /* char    *conninfo; */
-   CSTR        func = "CC_connect";
+       SOCK_put_int(sock, args[i].len, 4);
+       if (args[i].isint)
+           SOCK_put_int(sock, args[i].u.integer, 4);
+       else
+           SOCK_put_n_char(sock, (char *) args[i].u.ptr, args[i].len);
 
-   mylog("%s: entering...\n", func);
+   }
 
-   if (password_req != AUTH_REQ_OK)
+   if (PROTOCOL_74(ci))
+       SOCK_put_int(sock, 1, 2); /* result format is binary */
+   mylog("    done sending args\n");
 
-       /* already connected, just authenticate */
-       pgconn = self->pgconn;
+   SOCK_flush_output(sock);
+   mylog("  after flush output\n");
 
-   else
+   done = FALSE;
+   while (!done)
    {
-       qlog("Global Options: Version='%s', fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
-            POSTGRESDRIVERVERSION,
-            ci->drivers.fetch_max,
-            ci->drivers.unknown_sizes,
-            ci->drivers.max_varchar_size,
-            ci->drivers.max_longvarchar_size);
-       qlog("                disable_optimizer=%d, ksqo=%d, unique_index=%d, use_declarefetch=%d\n",
-            ci->drivers.disable_optimizer,
-            ci->drivers.ksqo,
-            ci->drivers.unique_index,
-            ci->drivers.use_declarefetch);
-       qlog("                text_as_longvarchar=%d, unknowns_as_longvarchar=%d, bools_as_char=%d NAMEDATALEN=%d\n",
-            ci->drivers.text_as_longvarchar,
-            ci->drivers.unknowns_as_longvarchar,
-            ci->drivers.bools_as_char,
-            TABLE_NAME_STORAGE_LEN);
-
-       encoding = check_client_encoding(ci->conn_settings);
-       if (encoding && strcmp(encoding, "OTHER"))
-           self->client_encoding = strdup(encoding);
-       else
-       {
-           encoding = check_client_encoding(ci->drivers.conn_settings);
-           if (encoding && strcmp(encoding, "OTHER"))
-               self->client_encoding = strdup(encoding);
-       }
-       if (self->client_encoding)
-           self->ccsc = pg_CS_code(self->client_encoding);
-       qlog("                extra_systable_prefixes='%s', conn_settings='%s' conn_encoding='%s'\n",
-            ci->drivers.extra_systable_prefixes,
-            ci->drivers.conn_settings,
-            encoding ? encoding : "");
-
-       if (self->status != CONN_NOT_CONNECTED)
-       {
-           CC_set_error(self, CONN_OPENDB_ERROR, "Already connected.");
-           return 0;
-       }
+       id = SOCK_get_id(sock);
+       mylog("   got id = %c\n", id);
+       response_length = SOCK_get_response_length(sock);
+inolog("send_func response_length=%d\n", response_length);
 
-       if (ci->port[0] == '\0' ||
-#ifdef WIN32
-           ci->server[0] == '\0' ||
-#endif /* WIN32 */
-           ci->database[0] == '\0')
+       switch (id)
        {
-           CC_set_error(self, CONN_INIREAD_ERROR, "Missing server name, port, or database name in call to CC_connect.");
-           return 0;
-       }
+           case 'G':
+               if (PROTOCOL_74(ci))
+               {
+                   done = TRUE;
+                   ret = FALSE;
+                   break;
+               }
+           case 'V':
+               if ('V' == id)
+                   if (!PROTOCOL_74(ci))
+                       break;
+               *actual_result_len = SOCK_get_int(sock, 4);
+               if (-1 != *actual_result_len)
+               {
+                   if (result_is_int)
+                       *((int *) result_buf) = SOCK_get_int(sock, 4);
+                   else
+                       SOCK_get_n_char(sock, (char *) result_buf, *actual_result_len);
+
+                   mylog("  after get result\n");
+               }
+               if (!PROTOCOL_74(ci))
+               {
+                   c = SOCK_get_char(sock); /* get the last '0' */ 
+                   mylog("   after get 0\n");
+               }
+               done = TRUE; 
+               break;          /* ok */
 
-       mylog("CC_connect(): DSN = '%s', server = '%s', port = '%s', sslmode = '%s',"
-             " database = '%s', username = '%s',"
-             " password='%s'\n", ci->dsn, ci->server, ci->port, ci->sslmode,
-             ci->database, ci->username, ci->password ? "xxxxx" : "");
+           case 'N':
+               handle_notice_message(self, msgbuffer, sizeof(msgbuffer), NULL, "send_function", NULL);
+               /* continue reading */
+               break;
 
+           case 'E':
+               handle_error_message(self, msgbuffer, sizeof(msgbuffer), NULL, "send_function", NULL); 
+               CC_set_errormsg(self, msgbuffer);
+#ifdef _LEGACY_MODE_
+               CC_on_abort(self, 0);
+#endif /* _LEGACY_MODE_ */
+
+               mylog("send_function(V): 'E' - %s\n", CC_get_errormsg(self));
+               qlog("ERROR from backend during send_function: '%s'\n", CC_get_errormsg(self));
+               done = TRUE;
+               ret = FALSE;
+               break;
 
-       mylog("connecting to the server \n");
+           case 'Z':
+               EatReadyForQuery(self);
+               break;
 
-       connect_return = LIBPQ_connect(self);
-       if(0 == connect_return)
-            return 0;
+           case '0':           /* empty result */
+               done = TRUE;
+               break;
 
-       mylog("connection to the database succeeded.\n");
+           default:
+               /* skip the unexpected response if possible */
+               if (response_length >= 0)
+                   break;
+               CC_set_error(self, CONNECTION_BACKEND_CRAZY, "Unexpected protocol character from backend (send_function, args)", func);
+               CC_on_abort(self, CONN_DEAD);
 
+               mylog("send_function: error - %s\n", CC_get_errormsg(self));
+               done = TRUE;
+               ret = FALSE;
+               break;
+       }
    }
 
-   CC_clear_error(self);       /* clear any password error */
+cleanup:
+#undef return
+   CLEANUP_FUNC_CONN_CS(func_cs_count, self);
+   return ret;
+}
 
-   CC_set_translation(self);
 
-   /*
-    * Send any initial settings
-    */
+static char
+CC_setenv(ConnectionClass *self)
+{
+   ConnInfo   *ci = &(self->connInfo);
 
-   /*
-    * Get the version number first so we can check it before sending options
-    * that are now obsolete. DJP 21/06/2002
-    */
+/* QResultClass *res; */
+   HSTMT       hstmt;
+   StatementClass *stmt;
+   RETCODE     result;
+   char        status = TRUE;
+#ifdef HAVE_STRTOK_R
+   char    *last;
+#endif /* HAVE_STRTOK_R */
+   CSTR func = "CC_setenv";
 
-   CC_lookup_pg_version(self);     /* Get PostgreSQL version for
-                          SQLGetInfo use */
-   /*
-    * Since these functions allocate statements, and since the connection
-    * is not established yet, it would violate odbc state transition
-    * rules.  Therefore, these functions call the corresponding local
-    * function instead.
-    */
-   CC_send_settings(self);
-   CC_clear_error(self);           /* clear any error */
-   CC_lookup_lo(self);         /* a hack to get the oid of
-                          our large object oid type */
 
-   /*
-    *  Multibyte handling is available ?
-    */
-   if (PG_VERSION_GE(self, 6.4))
+   mylog("%s: entering...\n", func);
+
+/*
+ * This function must use the local odbc API functions since the odbc state
+ * has not transitioned to "connected" yet.
+ */
+
+   result = PGAPI_AllocStmt(self, &hstmt);
+   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+       return FALSE;
+   stmt = (StatementClass *) hstmt;
+
+   stmt->internal = TRUE;      /* ensure no BEGIN/COMMIT/ABORT stuff */
+
+   /* Set the Datestyle to the format the driver expects it to be in */
+   result = PGAPI_ExecDirect(hstmt, "set DateStyle to 'ISO'", SQL_NTS, 0);
+   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+       status = FALSE;
+
+   mylog("%s: result %d, status %d from set DateStyle\n", func, result, status);
+   /* Disable genetic optimizer based on global flag */
+   if (ci->drivers.disable_optimizer)
    {
-       CC_lookup_characterset(self);
-       if (CC_get_errornumber(self) != 0)
-           return 0;
-#ifdef UNICODE_SUPPORT
-       if (self->unicode)
-       {
-           if (!self->client_encoding ||
-               stricmp(self->client_encoding, "UNICODE"))
-           {
-               QResultClass    *res;
-               if (PG_VERSION_LT(self, 7.1))
-               {
-                   CC_set_error(self, CONN_NOT_IMPLEMENTED_ERROR, "UTF-8 conversion isn't implemented before 7.1");
-                   return 0;
-               }
-               if (self->client_encoding)
-                   free(self->client_encoding);
-               self->client_encoding = NULL;
-               res = LIBPQ_execute_query(self,"set client_encoding to 'UTF8'");
-               if (res)
-               {
-                   self->client_encoding = strdup("UNICODE");
-                   self->ccsc = pg_CS_code(self->client_encoding);
-                   QR_Destructor(res);
+       result = PGAPI_ExecDirect(hstmt, "set geqo to 'OFF'", SQL_NTS, 0);
+       if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+           status = FALSE;
+
+       mylog("%s: result %d, status %d from set geqo\n", func, result, status);
 
-               }
-           }
-       }
-#else   
-       {    
-       }    
-#endif /* UNICODE_SUPPORT */    
    }
-#ifdef UNICODE_SUPPORT
-   else if (self->unicode)
+
+   /* KSQO (not applicable to 7.1+ - DJP 21/06/2002) */
+   if (ci->drivers.ksqo && PG_VERSION_LT(self, 7.1))
    {
-       CC_set_error(self, CONN_NOT_IMPLEMENTED_ERROR, "Unicode isn't supported before 6.4");
-       return 0;
+       result = PGAPI_ExecDirect(hstmt, "set ksqo to 'ON'", SQL_NTS, 0);
+       if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+           status = FALSE;
+
+       mylog("%s: result %d, status %d from set ksqo\n", func, result, status);
+
    }
-#endif /* UNICODE_SUPPORT */
-   ci->updatable_cursors = 0;
-#ifdef DRIVER_CURSOR_IMPLEMENT
-   if (!ci->drivers.use_declarefetch &&
-       PG_VERSION_GE(self, 7.0)) /* Tid scan since 7.0 */
-       ci->updatable_cursors = ci->allow_keyset;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
 
-   if (!CC_is_in_autocommit(self))
-       CC_commit(self);
+   /* extra_float_digits (applicable since 7.4) */
+   if (PG_VERSION_GT(self, 7.3))
+   {
+       result = PGAPI_ExecDirect(hstmt, "set extra_float_digits to 2", SQL_NTS, 0);
+       if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+           status = FALSE;
 
-   CC_clear_error(self);       /* clear any initial command errors */
-   self->status = CONN_CONNECTED;
+       mylog("%s: result %d, status %d from set extra_float_digits\n", func, result, status);
 
-   mylog("%s: returning...\n", func);
+   }
 
-   return 1;
+   PGAPI_FreeStmt(hstmt, SQL_DROP);
 
+   return status;
 }
 
-
-/*
- * Create a more informative error message by concatenating the connection
- * error message with its libpq error message.
- */
-char *
-CC_create_errormsg(ConnectionClass *self)
+char
+CC_send_settings(ConnectionClass *self)
 {
-   char     msg[4096];
-
-   mylog("enter CC_create_errormsg\n");
+   /* char ini_query[MAX_MESSAGE_LEN]; */
+   ConnInfo   *ci = &(self->connInfo);
 
-   msg[0] = '\0';
+/* QResultClass *res; */
+   HSTMT       hstmt;
+   StatementClass *stmt;
+   RETCODE     result;
+   char        status = TRUE;
+   char       *cs,
+              *ptr;
+#ifdef HAVE_STRTOK_R
+   char    *last;
+#endif /* HAVE_STRTOK_R */
+   CSTR func = "CC_send_settings";
 
-   if (CC_get_errormsg(self))
-       strncpy(msg, CC_get_errormsg(self), sizeof(msg));
 
-   mylog("msg = '%s'\n", msg);
+   mylog("%s: entering...\n", func);
 
-   mylog("exit CC_create_errormsg\n");
-   return msg ? strdup(msg) : NULL;
-}
+/*
+ * This function must use the local odbc API functions since the odbc state
+ * has not transitioned to "connected" yet.
+ */
 
+   result = PGAPI_AllocStmt(self, &hstmt);
+   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+       return FALSE;
+   stmt = (StatementClass *) hstmt;
 
-void   CC_on_abort(ConnectionClass *conn, UDWORD opt)
-{
-   BOOL    set_no_trans = FALSE;
+   stmt->internal = TRUE;      /* ensure no BEGIN/COMMIT/ABORT stuff */
 
-   if (0 != (opt & CONN_DEAD))
-       opt |= NO_TRANS;
-   if (CC_is_in_trans(conn))
+   /* Global settings */
+   if (ci->drivers.conn_settings[0] != '\0')
    {
-#ifdef DRIVER_CURSOR_IMPLEMENT
-       if (conn->result_uncommitted)
-           ProcessRollback(conn, TRUE);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
-       if (0 != (opt & NO_TRANS))
+       cs = strdup(ci->drivers.conn_settings);
+#ifdef HAVE_STRTOK_R
+       ptr = strtok_r(cs, ";", &last);
+#else
+       ptr = strtok(cs, ";");
+#endif /* HAVE_STRTOK_R */
+       while (ptr)
        {
-           CC_set_no_trans(conn);
-           CC_set_no_manual_trans(conn);
-           set_no_trans = TRUE;
+           result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS, 0);
+           if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+               status = FALSE;
+
+           mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr);
+
+#ifdef HAVE_STRTOK_R
+           ptr = strtok_r(NULL, ";", &last);
+#else
+           ptr = strtok(NULL, ";");
+#endif /* HAVE_STRTOK_R */
        }
+
+       free(cs);
    }
-   CC_clear_cursors(conn, TRUE);
-   if (0 != (opt & CONN_DEAD))
+
+   /* Per Datasource settings */
+   if (ci->conn_settings[0] != '\0')
    {
-       conn->status = CONN_DOWN;
-       if (conn->pgconn)
+       cs = strdup(ci->conn_settings);
+#ifdef HAVE_STRTOK_R
+       ptr = strtok_r(cs, ";", &last);
+#else
+       ptr = strtok(cs, ";");
+#endif /* HAVE_STRTOK_R */
+       while (ptr)
        {
-           LIBPQ_Destructor(conn->pgconn);
-           conn->pgconn = NULL;
+           result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS, 0);
+           if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+               status = FALSE;
+
+           mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr);
+
+#ifdef HAVE_STRTOK_R
+           ptr = strtok_r(NULL, ";", &last);
+#else
+           ptr = strtok(NULL, ";");
+#endif /* HAVE_STRTOK_R */
        }
+
+       free(cs);
    }
-   else if (set_no_trans)
-       CC_discard_marked_plans(conn);
-   conn->result_uncommitted = 0;
+
+
+   PGAPI_FreeStmt(hstmt, SQL_DROP);
+
+   return status;
 }
 
+
 /*
- * The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
- * the same existing QResultClass (this occurs when the tuple cache is depleted and
- * needs to be re-filled).
- *
- * The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
- * (i.e., C3326857) for SQL select statements.  This cursor is then used in future
- * 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
+ * This function is just a hack to get the oid of our Large Object oid type.
+ * If a real Large Object oid type is made part of Postgres, this function
+ * will go away and the define 'PG_TYPE_LO' will be updated.
  */
-QResultClass *
-CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
+void
+CC_lookup_lo(ConnectionClass *self)
 {
-   QResultClass *cmdres = NULL,
-                *retres = NULL,
-                *res ;
-   BOOL    clear_result_on_abort = ((flag & CLEAR_RESULT_ON_ABORT) != 0),
-           create_keyset = ((flag & CREATE_KEYSET) != 0),
-           issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self));
-   PGconn *pgconn = self->pgconn;
-   int         maxlen;
-   BOOL        used_passed_result_object = FALSE;
-   int     func_cs_count = 0;
-
+   QResultClass    *res;
+   CSTR func = "CC_lookup_lo";
 
-   mylog("send_query(): conn=%u, query='%s'\n", self, query);
-   qlog("conn=%u, query='%s'\n", self, query);
+   mylog("%s: entering...\n", func);
 
-   if (!self->pgconn)
-   {
-       CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query(connection dead)");
-       CC_on_abort(self, NO_TRANS);
-       return NULL;
-   }
-   /* Indicate that we are sending a query to the backend */
-   maxlen = CC_get_max_query_len(self);
-   if (maxlen > 0 && maxlen < (int) strlen(query) + 1)
+   if (PG_VERSION_GE(self, 7.4))
+       res = CC_send_query(self, "select oid, typbasetype from pg_type where oid = '"  PG_TYPE_LO_NAME "'::regtype::oid", 
+           NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL);
+   else
+       res = CC_send_query(self, "select oid from pg_type where typname='" PG_TYPE_LO_NAME "'",
+           NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL);
+   if (QR_command_maybe_successful(res) && QR_get_num_cached_tuples(res) > 0)
    {
-       CC_set_error(self, CONNECTION_MSG_TOO_LONG, "Query string is too long");
-       return NULL;
-   }
-
-   if ((NULL == query) || (query[0] == '\0'))
-       return NULL;
+       UInt4   basetype;
 
-#define    return DONT_CALL_RETURN_FROM_HERE???
-   ENTER_INNER_CONN_CS(self, func_cs_count);
+       self->lobj_type = atoi(QR_get_value_backend_row(res, 0, 0));
+       basetype = atoi(QR_get_value_backend_row(res, 0, 1));
+       if (PG_TYPE_OID == basetype)
+           self->lo_is_domain = 1;
+       else if (0 != basetype)
+           self->lobj_type = 0;
+   }
+   QR_Destructor(res);
+   mylog("Got the large object oid: %d\n", self->lobj_type);
+   qlog("    [ Large Object oid = %d ]\n", self->lobj_type);
+   return;
+}
 
-   if (issue_begin)
-    {
-       res = LIBPQ_execute_query(self,"BEGIN");
-       if ((!res) || (res->status != PGRES_COMMAND_OK))
-       {
-           CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend");
-           CC_on_abort(self, NO_TRANS | CONN_DEAD);
-           QR_Destructor(res);
-           res = NULL;
-           goto cleanup;
-       }
-    }
-    
-   res = LIBPQ_execute_query(self,query);
 
-   if(!res)
+/*
+ * This function initializes the version of PostgreSQL from
+ * connInfo.protocol that we're connected to.
+ * h-inoue 01-2-2001
+ */
+void
+CC_initialize_pg_version(ConnectionClass *self)
+{
+   strcpy(self->pg_version, self->connInfo.protocol);
+   if (PROTOCOL_62(&self->connInfo))
    {
-       goto cleanup;
+       self->pg_version_number = (float) 6.2;
+       self->pg_version_major = 6;
+       self->pg_version_minor = 2;
    }
-#ifdef NOT_USED
-   else if ((res->status == PGRES_EMPTY_QUERY) || (res->status == PGRES_FATAL_ERROR) ||
-            (res->status == PGRES_BAD_RESPONSE))
+   else if (PROTOCOL_63(&self->connInfo))
    {
-       mylog("send_query: failed -> abort\n");
-       QR_set_aborted(res, TRUE);
-       QR_Destructor(res);
-        res = NULL;
-       goto cleanup;
+       self->pg_version_number = (float) 6.3;
+       self->pg_version_major = 6;
+       self->pg_version_minor = 3;
    }
-#endif /* NOT_USED */
-   else if  (res->status == PGRES_COMMAND_OK)
+   else if (PROTOCOL_64(&self->connInfo))
    {
-       mylog("send_query: done sending command\n");
-       goto cleanup;
+       self->pg_version_number = (float) 6.4;
+       self->pg_version_major = 6;
+       self->pg_version_minor = 4;
    }
    else
    {
-       mylog("send_query: done sending query with status: %i\n",res->status);
-
-       cmdres = qi ? qi->result_in : NULL;
-       if (cmdres)
-           used_passed_result_object = TRUE;
-       if (!used_passed_result_object)
-       {
-           if ((res->status == PGRES_EMPTY_QUERY) || (res->status == PGRES_BAD_RESPONSE))
-           {
-               mylog("send_query: sending query failed -> abort\n");
-               QR_set_aborted(res, TRUE);
-               QR_Destructor(res);
-               res = NULL;
-               goto cleanup;
-           }
-           else if (res->status == PGRES_FATAL_ERROR)
-           {
-               mylog("send_query: sended query failed -> abort\n");
-               QR_set_aborted(res, TRUE);
-               goto cleanup;
-           }
-           if (create_keyset)
-               QR_set_haskeyset(res->next);
-           if (!QR_fetch_tuples(res, self, qi ? qi->cursor : NULL))
-           {
-               CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(res));
-           }
-       }
-       else
-       {
-           /* next fetch, so reuse an existing result */
-           mylog("send_query: next fetch -> reuse result\n");
-           if (!QR_fetch_tuples(res, NULL, NULL))
-           {
-               CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(res));
-               if (PGRES_FATAL_ERROR == QR_get_status(res))
-               {
-                   QR_set_aborted(res, TRUE);
-                   retres = cmdres;
-               }
-           }
-       }
-   }
-
-cleanup:
-   CLEANUP_FUNC_CONN_CS(func_cs_count, self);
-#undef return
-   /*
-    * Cleanup the aborted result if specified
-    */
-   if (retres)
-   {
-       /*
-        *  discard results other than errors.
-        */
-       QResultClass    *qres;
-       for (qres = retres; qres->next; qres = retres)
-       {
-           if (QR_get_aborted(qres))
-               break;
-           retres = qres->next;
-           qres->next = NULL;
-           QR_Destructor(qres);
-       }
-       /*
-        *  If error message isn't set
-        */
-       if (retres && (!CC_get_errormsg(self) || !CC_get_errormsg(self)[0]))
-           CC_set_errormsg(self, QR_get_message(retres));
+       self->pg_version_number = (float) 7.4;
+       self->pg_version_major = 7;
+       self->pg_version_minor = 4;
    }
-   return res;
 }
 
-int
-CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *args, int nargs)
+
+/*
+ * This function gets the version of PostgreSQL that we're connected to.
+ * This is used to return the correct info in SQLGetInfo
+ * DJP - 25-1-2001
+ */
+void
+CC_lookup_pg_version(ConnectionClass *self)
 {
-   char            done;
+   HSTMT       hstmt;
+   StatementClass *stmt;
+   RETCODE     result;
+   char        szVersion[32];
+   int         major,
+               minor;
+   CSTR        func = "CC_lookup_pg_version";
 
-   mylog("send_function(): conn=%u, fnid=%d, result_is_int=%d, nargs=%d\n", self, fnid, result_is_int, nargs);
+   mylog("%s: entering...\n", func);
+
+/*
+ * This function must use the local odbc API functions since the odbc state
+ * has not transitioned to "connected" yet.
+ */
+   result = PGAPI_AllocStmt(self, &hstmt);
+   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+       return;
+   stmt = (StatementClass *) hstmt;
 
-   if (!self->pgconn)
+   /* get the server's version if possible  */
+   result = PGAPI_ExecDirect(hstmt, "select version()", SQL_NTS, 0);
+   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send function(connection dead)");
-       CC_on_abort(self, NO_TRANS);
-       return FALSE;
+       PGAPI_FreeStmt(hstmt, SQL_DROP);
+       return;
    }
 
-   mylog("send_function: done sending function\n");
+   result = PGAPI_Fetch(hstmt);
+   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+   {
+       PGAPI_FreeStmt(hstmt, SQL_DROP);
+       return;
+   }
 
-   /* Need to implement this */
+   result = PGAPI_GetData(hstmt, 1, SQL_C_CHAR, self->pg_version, MAX_INFO_STRING, NULL);
+   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+   {
+       PGAPI_FreeStmt(hstmt, SQL_DROP);
+       return;
+   }
 
-   mylog("    done sending args\n");
+   /*
+    * Extract the Major and Minor numbers from the string. This assumes
+    * the string starts 'Postgresql X.X'
+    */
+   strcpy(szVersion, "0.0");
+   if (sscanf(self->pg_version, "%*s %d.%d", &major, &minor) >= 2)
+   {
+       snprintf(szVersion, sizeof(szVersion), "%d.%d", major, minor);
+       self->pg_version_major = major;
+       self->pg_version_minor = minor;
+   }
+   self->pg_version_number = (float) atof(szVersion);
+   if (PG_VERSION_GE(self, 7.3))
+       self->schema_support = 1;
 
-   mylog("  after flush output\n");
+   mylog("Got the PostgreSQL version string: '%s'\n", self->pg_version);
+   mylog("Extracted PostgreSQL version number: '%1.1f'\n", self->pg_version_number);
+   qlog("    [ PostgreSQL version string = '%s' ]\n", self->pg_version);
+   qlog("    [ PostgreSQL version number = '%1.1f' ]\n", self->pg_version_number);
 
-   done = FALSE;
-   return TRUE;
+   result = PGAPI_FreeStmt(hstmt, SQL_DROP);
 }
 
 
@@ -1574,439 +2882,327 @@ CC_log_error(const char *func, const char *desc, const ConnectionClass *self)
 
    if (self)
    {
-       qlog("CONN ERROR: func=%s, desc='%s', errnum=%d, sqlstate=%s, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__sqlstate), nullcheck(self->__error_message));
-       mylog("CONN ERROR: func=%s, desc='%s', errnum=%d, sqlstate=%s, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__sqlstate), nullcheck(self->__error_message));
+       qlog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__error_message));
+       mylog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__error_message));
        qlog("            ------------------------------------------------------------\n");
-       qlog("            henv=%u, conn=%u, status=%u, num_stmts=%d\n", self->henv, self, self->status, self->num_stmts);
+       qlog("            henv=%x, conn=%x, status=%u, num_stmts=%d\n", self->henv, self, self->status, self->num_stmts);
+       qlog("            sock=%x, stmts=%x, lobj_type=%d\n", self->sock, self->stmts, self->lobj_type);
+
+       qlog("            ---------------- Socket Info -------------------------------\n");
+       if (self->sock)
+       {
+           SocketClass *sock = self->sock;
+
+           qlog("            socket=%d, reverse=%d, errornumber=%d, errormsg='%s'\n", sock->socket, sock->reverse, sock->errornumber, nullcheck(sock->errormsg));
+           qlog("            buffer_in=%u, buffer_out=%u\n", sock->buffer_in, sock->buffer_out);
+           qlog("            buffer_filled_in=%d, buffer_filled_out=%d, buffer_read_in=%d\n", sock->buffer_filled_in, sock->buffer_filled_out, sock->buffer_read_in);
+       }
    }
    else
-   {
+{
        qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
        mylog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
-   }
+}
 #undef PRN_NULLCHECK
 }
 
-
 int
-CC_send_cancel_request(const ConnectionClass *conn)
+CC_get_max_query_len(const ConnectionClass *conn)
 {
-   int         ret = 0,errbufsize=256;
-   char        errbuf[256];
-   PGcancel    *cancel;
-
+   int         value;
 
-   cancel = PQgetCancel(conn->pgconn);
-   if(!cancel)
-   {
-       PQfreeCancel(cancel);
-       return FALSE;
-   }
-   ret=PQcancel(cancel, errbuf,errbufsize);
-   if(1 == ret)
-       return TRUE;
+   /* Long Queries in 7.0+ */
+   if (PG_VERSION_GE(conn, 7.0))
+       value = 0 /* MAX_STATEMENT_LEN */ ;
+   /* Prior to 7.0 we used 2*BLCKSZ */
+   else if (PG_VERSION_GE(conn, 6.5))
+       value = (2 * BLCKSZ);
    else
-   {
-       PQfreeCancel(cancel);
-       return FALSE;
-   }
-   return ret;
-}
-
-
-void
-LIBPQ_Destructor(PGconn *pgconn)
-{
-   mylog("entering PGCONN_Destructor \n");
-   PQfinish(pgconn);
-   mylog("exiting PGCONN_Destructor \n");
+       /* Prior to 6.5 we used BLCKSZ */
+       value = BLCKSZ;
+   return value;
 }
 
-
-int
-LIBPQ_connect(ConnectionClass *self)
+/*
+ * This doesn't really return the CURRENT SCHEMA
+ * but there's no alternative.
+ */
+const char *
+CC_get_current_schema(ConnectionClass *conn)
 {
-   char *conninfo;
-   mylog("connecting to the database  using %s as the server\n",self->connInfo.server);
-   if(self->connInfo.server != '\0')
+   if (!conn->current_schema && conn->schema_support)
    {
-       conninfo = (char *)malloc((sizeof(char) * strlen(" host=") + strlen(self->connInfo.server) + 1));
-       if(!conninfo)
-       {
-           CC_set_error(self, CONN_MEMORY_ALLOCATION_FAILED,"Could not allocate memory for connection string(server)");
-            CC_set_sqlstate(self, "08000");
-           mylog("could not allocate memory for server \n");
-            return 0;
-       }
-       conninfo = strcpy(conninfo," host=");
-       conninfo = strcat(conninfo,self->connInfo.server);
+       QResultClass    *res;
 
-   }
-   mylog("the size is %d \n",strlen(conninfo));
-   if(self->connInfo.port[0] != '\0')
-   {
-       size_t size=(sizeof(char) * (strlen(" port=") + strlen(self->connInfo.port) + 1));
-       conninfo = (char *)realloc(conninfo,size+strlen(conninfo));
-       if(!conninfo)
+       if (res = CC_send_query(conn, "select current_schema()", NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL), QR_command_maybe_successful(res))
        {
-           CC_set_error(self, CONN_MEMORY_ALLOCATION_FAILED,"Could not allocate memory for connection string(port)");
-            CC_set_sqlstate(self, "08000");
-           mylog("could not allocate memory for port \n");
-            return 0;
+           if (QR_get_num_total_tuples(res) == 1)
+               conn->current_schema = strdup(QR_get_value_backend_row(res, 0, 0));
        }
-       conninfo = strcat(conninfo," port=");
-       conninfo = strcat(conninfo,self->connInfo.port);
+       QR_Destructor(res);
    }
+   return (const char *) conn->current_schema;
+}
 
-
-   if(self->connInfo.database[0] != '\0')
+static int LIBPQ_send_cancel_request(const ConnectionClass *conn);
+int
+CC_send_cancel_request(const ConnectionClass *conn)
+{
+   int         save_errno = SOCK_ERRNO;
+   SOCKETFD        tmpsock = -1;
+   struct
    {
-       size_t size= (sizeof(char) * (strlen(" dbname=") + strlen(self->connInfo.database) + 1));
-       conninfo = (char *)realloc(conninfo,size+strlen(conninfo));
-       if(!conninfo)
-       {
-           CC_set_error(self, CONN_MEMORY_ALLOCATION_FAILED,"Could not allocate memory for connection string(database)");
-            CC_set_sqlstate(self, "08000");
-           mylog("i could not allocate memory for dbname \n");
-            return 0;
-       }
-       conninfo = strcat(conninfo," dbname=");
-       conninfo = strcat(conninfo,self->connInfo.database);
-   }
+       uint32      packetlen;
+       CancelRequestPacket cp;
+   }           crp;
+   BOOL    ret = TRUE;
+   SocketClass *sock;
 
+   /* Check we have an open connection */
+   if (!conn)
+       return FALSE;
+   sock = CC_get_socket(conn);
+   if (!sock)
+       return FALSE;
 
-   if(self->connInfo.username[0] != '\0')
+   if (sock->via_libpq)
+       return LIBPQ_send_cancel_request(conn);
+   /*
+    * We need to open a temporary connection to the postmaster. Use the
+    * information saved by connectDB to do this with only kernel calls.
+   */
+   if ((tmpsock = socket(conn->sock->sadr->sa_family, SOCK_STREAM, 0)) < 0)
    {
-       size_t size = (sizeof(char) * (strlen(" user=") + strlen(self->connInfo.username) + 1));
-       conninfo = (char *)realloc(conninfo,size+strlen(conninfo));
-       if(!conninfo)
-       {
-           CC_set_error(self, CONN_MEMORY_ALLOCATION_FAILED,"Could not allocate memory for connection string(username)");
-            CC_set_sqlstate(self, "08000");
-           mylog("i could not allocate memory for username \n");
-            return 0;
-       }
-       conninfo = strcat(conninfo," user=");
-       conninfo = strcat(conninfo,self->connInfo.username);
+       return FALSE;
+   }
+   if (connect(tmpsock, conn->sock->sadr, conn->sock->sadr_len) < 0)
+   {
+       closesocket(tmpsock);
+       return FALSE;
    }
 
+   /*
+    * We needn't set nonblocking I/O or NODELAY options here.
+    */
+   crp.packetlen = htonl((uint32) sizeof(crp));
+   crp.cp.cancelRequestCode = (MsgType) htonl(CANCEL_REQUEST_CODE);
+   crp.cp.backendPID = htonl(conn->be_pid);
+   crp.cp.cancelAuthCode = htonl(conn->be_key);
 
-   if(self->connInfo.sslmode[0] != '\0')
+   while (send(tmpsock, (char *) &crp, sizeof(crp), 0) != (int) sizeof(crp))
    {
-       size_t size = (sizeof(char) * (strlen(" sslmode=") + strlen(self->connInfo.sslmode) + 1));
-       conninfo = (char *)realloc(conninfo,size+strlen(conninfo));
-       if(!conninfo)
+       if (SOCK_ERRNO != EINTR)
        {
-           CC_set_error(self, CONN_MEMORY_ALLOCATION_FAILED,"Could not allocate memory for connection string(sslmode)");
-            CC_set_sqlstate(self, "08000");
-           mylog("i could not allocate memory for sslmode \n");
-            return 0;
+           save_errno = SOCK_ERRNO;
+           ret = FALSE;
+           break;
        }
-       conninfo = strcat(conninfo," sslmode=");
-       conninfo = strcat(conninfo,self->connInfo.sslmode);
    }
-    
-   if(self->connInfo.password[0] != '\0')
+   if (ret)
    {
-       size_t size = (sizeof(char) * (strlen(" password=") + strlen(self->connInfo.password) + 1));
-       conninfo = (char *)realloc(conninfo,size+strlen(conninfo));
-       if(!conninfo)
+       while (recv(tmpsock, (char *) &crp, 1, 0) < 0)
        {
-           CC_set_error(self, CONN_MEMORY_ALLOCATION_FAILED,"Could not allocate memory for connection string(password)");
-            CC_set_sqlstate(self, "08000");
-           mylog("i could not allocate memory for password \n");
-            return 0;
+           if (EINTR != SOCK_ERRNO)
+               break;
        }
-       conninfo = strcat(conninfo," password=");
-       conninfo = strcat(conninfo,self->connInfo.password);
    }
 
-   self->pgconn = PQconnectdb(conninfo);
-   if (PQstatus(self->pgconn) != CONNECTION_OK)
-   {
-       CC_set_error(self,CONNECTION_COULD_NOT_ESTABLISH, PQerrorMessage(self->pgconn));
-        CC_set_sqlstate(self, "08001");
-       mylog("Could not establish connection to the database; LIBPQ returned -> %s \n",PQerrorMessage(self->pgconn));
-       PQfinish(self->pgconn);
-        self->pgconn = NULL;
-       free(conninfo);
-       return 0;
-   }
-   /* free the conninfo structure */
-   free(conninfo);
-    /* setup the notice handler */
-    PQsetNoticeProcessor(self->pgconn, CC_handle_notice, NULL);
+   /* Sent it, done */
+   closesocket(tmpsock);
+   SOCK_ERRNO_SET(save_errno);
 
-    mylog("connection to the database succeeded.\n");
-   return 1;
+   return ret;
 }
 
+int    CC_mark_a_object_to_discard(ConnectionClass *conn, int type, const char *plan)
+{
+   int cnt = conn->num_discardp + 1;
+   char    *pname;
+   
+   CC_REALLOC_return_with_error(conn->discardp, char *,
+       (cnt * sizeof(char *)), conn, "Couldn't alloc discardp.", -1);
+   CC_MALLOC_return_with_error(pname, char, (strlen(plan) + 2),
+       conn, "Couldn't alloc discardp mem.", -1);
+   pname[0] = (char) type; /* 's':prepared statement 'p':cursor */
+   strcpy(pname + 1, plan);
+   conn->discardp[conn->num_discardp++] = pname;
 
-QResultClass *
-LIBPQ_execute_query(ConnectionClass *self,char *query)
+   return 1;
+}
+int    CC_discard_marked_objects(ConnectionClass *conn)
 {
-   QResultClass    *qres;
-   PGresult    *pgres = NULL, *pgresnew = NULL;
-   char        errbuffer[ERROR_MSG_LENGTH + 1];
-   int     pos=0;
+   int i, cnt;
+   QResultClass *res;
+   char    *pname, cmd[64];
 
-   mylog("LIBPQ_execute_query: entering ...\n");
-   qres=QR_Constructor();
-   if(!qres)
+   if ((cnt = conn->num_discardp) <= 0)
+       return 0;
+   for (i = cnt - 1; i >= 0; i--)
    {
-       CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not allocate memory for result set");
-       CC_on_abort(self, CONN_DEAD);
-       QR_Destructor(qres);
-       return NULL;
+       pname = conn->discardp[i];
+       if ('s' == pname[0])
+               snprintf(cmd, sizeof(cmd), "DEALLOCATE \"%s\"", pname + 1);
+       else
+               snprintf(cmd, sizeof(cmd), "CLOSE \"%s\"", pname + 1);
+       res = CC_send_query(conn, cmd, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+       QR_Destructor(res);
+       free(conn->discardp[i]);
+       conn->num_discardp--;
    }
 
-   PQsetNoticeProcessor(self->pgconn, CC_handle_notice, qres);
-   if (!PQsendQuery(self->pgconn,query))
-   {
-       CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not send query to backend");
-       CC_on_abort(self, CONN_DEAD);
-       QR_Destructor(qres);
-       return NULL;
-   }
-   while (pgresnew = PQgetResult(self->pgconn))
-   {
-       mylog("LIBPQ_execute_query: get next result with status = %i\n",PQresultStatus(pgresnew));
-       if (pgres)
-           PQclear(pgres);
-       pgres = pgresnew;
-   }
-   PQsetNoticeProcessor(self->pgconn, CC_handle_notice, NULL);
+   return 1;
+}
 
-   mylog("LIBPQ_execute_query: query = %s\n",query);
+static int
+LIBPQ_connect(ConnectionClass *self)
+{
+   CSTR    func = "LIBPQ_connect";
+   char    ret = 0;
+   char *conninfo = NULL;
+   void        *pqconn = NULL;
+   SocketClass *sock;
+   int socket = -1, pqret;
+   BOOL    libpqLoaded;
 
-   qres->status = PQresultStatus(pgres);
-   
-   /* Check the connection status */
-   if(PQstatus(self->pgconn) == CONNECTION_BAD)
-   {
-       snprintf(errbuffer, ERROR_MSG_LENGTH, "%s", PQerrorMessage(self->pgconn));
-       /* Remove the training CR that libpq adds to the message */
-       pos = strlen(errbuffer);
-       if (pos)
-           errbuffer[pos - 1] = '\0';
-       
-       mylog("The server could be dead: %s\n", errbuffer);
-       CC_set_error(self, CONNECTION_COULD_NOT_SEND, errbuffer);
-       CC_on_abort(self,CONN_DEAD);
-       PQclear(pgres);
-       return qres;
-   }
-    
-   if( (PQresultStatus(pgres) == PGRES_COMMAND_OK) )
-   {
-       if ((strnicmp(query, "BEGIN", 5) == 0) ||
-           (strnicmp(query, "START TRANSACTION", 17) == 0))
-           CC_set_in_trans(self);
-       else if ((strnicmp(query, "COMMIT", 6) == 0) ||
-                (strnicmp(query, "END", 3) == 0))
-           CC_on_commit(self);
-       else if (strnicmp(query, "ROLLBACK", 8) == 0)
-       {
-           /* 
-              The method of ROLLBACK an original form ....
-              ROLLBACK [ WORK | TRANSACTION ] TO [ SAVEPOINT ] savepoint_name
-            */
-           if (PG_VERSION_LT(self, 8.0) || !(contains_token(query, " TO ")))
-               CC_on_abort(self, NO_TRANS);
-       }
-       else if (strnicmp(query, "ABORT", 5) == 0)
-           CC_on_abort(self, NO_TRANS);
-       else
+   mylog("connecting to the database  using %s as the server\n",self->connInfo.server);
+   sock = self->sock;
+inolog("sock=%x\n", sock);
+   if (!sock)
+   {
+       sock = SOCK_Constructor(self);
+       if (!sock)
        {
-           if (PQcmdTuples(pgres)[0])
-               qres->recent_processed_row_count = atoi(PQcmdTuples(pgres));
-           else
-               qres->recent_processed_row_count = -1;
-           mylog("LIBPQ_execute_query: recent_processed_row_count = %i\n",qres->recent_processed_row_count);
+           CC_set_error(self, CONN_OPENDB_ERROR, "Could not construct a socket to the server", func);
+           goto cleanup1;
        }
-       mylog("The query was executed successfully and the query did not return any result \n");
-       PQclear(pgres);
-       return qres;
    }
 
-   if ( (PQresultStatus(pgres) != PGRES_EMPTY_QUERY) && (PQresultStatus(pgres) != PGRES_TUPLES_OK) )
+   if (!(conninfo = protocol3_opts_build(self)))
    {
-       snprintf(errbuffer, ERROR_MSG_LENGTH, "%s", PQerrorMessage(self->pgconn));
-       
-       /* Remove the training CR that libpq adds to the message */
-       pos = strlen(errbuffer);
-       if (pos)
-           errbuffer[pos - 1] = '\0';
-
-       mylog("the server returned the error: %s\n", errbuffer);
-       CC_set_error(self, CONNECTION_SERVER_REPORTED_ERROR, errbuffer);
-       CC_set_sqlstate(self, PQresultErrorField(pgres, PG_DIAG_SQLSTATE));
-
-       PQclear(pgres);
-       return qres;
+       CC_set_error(self, CONN_OPENDB_ERROR, "Couldn't allcate conninfo", func);
+       goto cleanup1;
    }
-
-   mylog("LIBPQ_execute_query: rest types ...\n");
-
-   if (PQcmdTuples(pgres)[0])
-       qres->recent_processed_row_count = atoi(PQcmdTuples(pgres));
-   else if (self->connInfo.drivers.use_declarefetch)
-       qres->recent_processed_row_count = -1;
-   else
-       qres->recent_processed_row_count = PQntuples(pgres);
-   mylog("LIBPQ_execute_query: recent_processed_row_count = %i\n",qres->recent_processed_row_count);
-
-   qres=CC_mapping(self,pgres,qres);
-   QR_set_command(qres, query);
-   PQclear(pgres);
-   return qres;
-}
-
-/*
- * This function populates the manual_tuples of QResultClass using PGresult class.
- */
-
-QResultClass *
-CC_mapping(ConnectionClass *self, PGresult *pgres,QResultClass *qres)
-{
-   CSTR func = "CC_mapping";
-   int i=0,j=0;
-   TupleNode *node, *temp;
-   Oid typid;
-   int atttypmod,typlen;
-   int num_attributes = PQnfields(pgres);
-   int num_tuples = PQntuples(pgres);
-   ConnInfo   *ci = &(self->connInfo);
-
-   mylog("%s: entering ...\n",func);
-   CI_set_num_fields(qres->fields, num_attributes);
-   mylog("%s: rows = %i, columns = %i\n",func,num_tuples,num_attributes);
-   for(i = 0 ; i < num_attributes ; i++)
-   {
-       mylog("%s: column = %i\n",func,i);
-       typid = PQftype(pgres,i);
-       atttypmod = PQfmod(pgres,i);
-        
-       /* Setup the typmod */
-       switch (typid)
+   pqconn = CALL_PQconnectdb(conninfo, &libpqLoaded);
+   free(conninfo);
+   if (!libpqLoaded)
+   {
+       CC_set_error(self, CONN_OPENDB_ERROR, "Couldn't load libpq library", func);
+       goto cleanup1;
+   }
+   sock->via_libpq = TRUE;
+   if (!pqconn)
+   {
+       CC_set_error(self, CONN_OPENDB_ERROR, "PQconnectdb error", func);
+       goto cleanup1;
+   }
+   sock->pqconn = pqconn;
+   pqret = PQstatus(pqconn);
+   if (CONNECTION_OK != pqret)
+   {
+       const char  *errmsg;
+inolog("status=%d\n", pqret);
+       errmsg = PQerrorMessage(pqconn);
+       if (CONNECTION_BAD == pqret && strstr(errmsg, "no password"))
        {
-           case PG_TYPE_DATETIME:
-           case PG_TYPE_TIMESTAMP_NO_TMZONE:
-           case PG_TYPE_TIME:
-           case PG_TYPE_TIME_WITH_TMZONE:
-               break;
-           default:
-               atttypmod -= 4;
+           mylog("password retry\n");
+           PQfinish(pqconn);
+           self->sock = sock;
+           return -1;
        }
-       if (atttypmod < 0)
-           atttypmod = -1;
-        
-       /* Setup the typlen */
-       switch (typid)
+       CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, errmsg, func);
+       mylog("Could not establish connection to the database; LIBPQ returned -> %s\n", errmsg);
+       goto cleanup1;
+   }
+   ret = 1;
+cleanup1:
+   if (!ret)
+   {
+       if (sock)
+           SOCK_Destructor(sock);
+       self->sock = NULL;
+       return ret;
+   }
+   mylog("libpq connection to the database succeeded.\n");
+   ret = 0;
+   socket = PQsocket(pqconn);
+inolog("socket=%d\n", socket);
+   sock->socket = socket;
+   sock->ssl = PQgetssl(pqconn);
+   {
+       int pversion;
+       ConnInfo    *ci = &self->connInfo;
+
+       sock->pversion = PG_PROTOCOL_74;
+       strcpy(ci->protocol, PG74);
+       pversion = PQprotocolVersion(pqconn);
+       switch (pversion)
        {
-           case PG_TYPE_NUMERIC:
-               typlen = (atttypmod >> 16) & 0xffff;
-               break;
-            
-           case PG_TYPE_BPCHAR:
-           case PG_TYPE_VARCHAR:
-               typlen = atttypmod;
+           case 2:
+               sock->pversion = PG_PROTOCOL_64;
+               strcpy(ci->protocol, PG64);
                break;
-        
-           default:
-                       typlen = PQfsize(pgres,i);
-           }
-        
-           /* 
-            * FIXME - The following is somewhat borked with regard to driver.unknownsizes
-            *         It works, but basically is not aware of different variable length types
-            *         (UNKNOWNS_AS_MAX), and UNKNOWNS_AS_LONGEST won't work because we don't
-            *         have data at this point 
-            */
-       if(typlen < 0)
-       {
-           switch (ci->drivers.unknown_sizes)
-           {
-               case UNKNOWNS_AS_DONTKNOW:
-                   typlen = SQL_NO_TOTAL;
-                   break;
-                
-               default:
-                   typlen = ( ci->drivers.text_as_longvarchar ? ci->drivers.max_longvarchar_size : ci->drivers.max_varchar_size );
-           }
-       }   
-        
-       mylog("%s: set field info: name = %s, typ = %i, typlen = %i, attypmod = %i\n", func, PQfname(pgres,i), typid, (Int2)typlen, atttypmod);
-       CI_set_field_info(qres->fields, i, PQfname(pgres,i),
-             typid, (Int2)typlen, atttypmod);
+       }
    }
-   if (qres->manual_tuples)
+   mylog("procotol=%s\n", self->connInfo.protocol);
    {
-       TL_Destructor(qres->manual_tuples);
+       int pversion, on;
+
+       pversion = PQserverVersion(pqconn);
+       self->pg_version_major = pversion / 10000;
+       self->pg_version_minor = (pversion % 10000) / 100;
+       sprintf(self->pg_version, "%d.%d.%d",  self->pg_version_major, self->pg_version_minor, pversion % 100);
+       self->pg_version_number = (float) atof(self->pg_version);
+       if (PG_VERSION_GE(self, 7.3))
+           self->schema_support = 1;
+       /* blocking mode */
+       /* ioctlsocket(sock, FIONBIO , 0);
+       setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)); */
    }
-   qres->manual_tuples = TL_Constructor(num_attributes);
-   qres->manual_tuples->num_tuples = (Int4)num_tuples;
-   for(i=0;i < num_tuples;i++)
+   if (sock->ssl)
    {
-           node = (TupleNode *)malloc(sizeof(TupleNode) + (num_attributes ) * sizeof(TupleField));
-           if(!node)
-           {
-               QR_set_status(qres, PGRES_FATAL_ERROR);
-               QR_set_message(qres, "Error could not allocate memory for row.");
-           }
-           if (i==0)
-           {
-               qres->manual_tuples->list_start = qres->manual_tuples->list_end = node;
-               qres->manual_tuples->lastref = node;
-               qres->manual_tuples->last_indexed = 0;
-               qres->manual_tuples->list_end->next = NULL;
-           }
-           else
-           {
-               temp = qres->manual_tuples->list_end;
-               qres->manual_tuples->list_end->next = node;
-               qres->manual_tuples->list_end = node;
-               qres->manual_tuples->list_end->prev = temp;
-               qres->manual_tuples->list_end->next = NULL;
-           }
-           for(j=0;j < num_attributes ;j++)
-           {
-               /* PQgetvalue returns an empty string even the data value is null. 
-                 * An additional checking is provided to set the null value */
-               if (PQgetisnull(pgres,i,j)) 
-               {
-                   mylog("%s: fetch column = %s, value = NULL\n",func,PQfname(pgres,j));
-                   set_tuplefield_null(&qres->manual_tuples->list_end->tuple[j]);
-               }
-               else
-               {
-                   mylog("%s: fetch column = %s, value = %s\n",func,PQfname(pgres,j),PQgetvalue(pgres,i,j));
-                   set_tuplefield_string(&qres->manual_tuples->list_end->tuple[j], PQgetvalue(pgres,i,j));
-               }
-           }
-
+       /* flags = fcntl(sock, F_GETFL);
+       fcntl(sock, F_SETFL, flags & (~O_NONBLOCKING));*/
    }
-       return qres;
-}
-
-void
-CC_is_server_alive(ConnectionClass *conn)
-{
-   PGresult *res;
-   if((PQstatus(conn->pgconn)) != CONNECTION_OK)
-       conn->status = CONN_NOT_CONNECTED;
-   res = PQexec(conn->pgconn,"SELECT 1");
-   if(PQresultStatus(res) != PGRES_TUPLES_OK)
+   mylog("Server version=%s\n", self->pg_version);
+   ret = 1;
+   if (ret)
    {
-       PQclear(res);
-       conn->status = CONN_DOWN;
+       self->sock = sock;
+       if (!CC_get_username(self)[0])
+       {
+           mylog("PQuser=%s\n", PQuser(pqconn));
+           strcpy(self->connInfo.username, PQuser(pqconn));
+       }
    }
    else
    {
-       PQclear(res);
-       conn->status = CONN_CONNECTED;
+       SOCK_Destructor(sock);
+       self->sock = NULL;
    }
-
+   
+   mylog("%s: retuning %d\n", func, ret);
+   return ret;
 }
 
+static int
+LIBPQ_send_cancel_request(const ConnectionClass *conn)
+{
+   int ret = 0;
+   char    errbuf[256];
+   void    *cancel;
+   SocketClass *sock = CC_get_socket(conn);
+
+   if (!sock)
+       return FALSE;
+       
+   cancel = PQgetCancel(sock->pqconn);
+   if(!cancel)
+       return FALSE;
+   ret = PQcancel(cancel, errbuf, sizeof(errbuf));
+   PQfreeCancel(cancel);
+   if(1 == ret)
+       return TRUE;
+   else
+       return FALSE;
+}
index b39b4cc1be11055d57a0e82086e32470ec419f48..be102ae337066303c85d79c00b213f324f381932 100644 (file)
@@ -1,6 +1,6 @@
 /* File:           connection.h
  *
- * Description:        See "CONNECTION.c"
+ * Description:        See "connection.c"
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
@@ -10,7 +10,7 @@
 #define __CONNECTION_H__
 
 #include "psqlodbc.h"
-#include <libpq-fe.h>
+
 #include <stdlib.h>
 #include <string.h>
 #include "descriptor.h"
 #include <pthread.h>
 #endif
 
-#if !defined WIN32 && defined HAVE_SYS_UN_H && !defined HAVE_UNIX_SOCKETS
-#define HAVE_UNIX_SOCKETS
+#ifdef __cplusplus
+extern "C" {
 #endif
+typedef enum
+{
+   CONN_NOT_CONNECTED, /* Connection has not been established */
+   CONN_CONNECTED,     /* Connection is up and has been established */
+   CONN_DOWN,      /* Connection is broken */
+   CONN_EXECUTING      /* the connection is currently executing a
+                * statement */
+} CONN_Status;
+
+enum
+{
+   DISALLOW_UPDATABLE_CURSORS = 0, /* No cursors are updatable */
+   ALLOW_STATIC_CURSORS = 1L, /* Static cursors are updatable */
+   ALLOW_KEYSET_DRIVEN_CURSORS = (1L << 1), /* Keyset-driven cursors are updatable */
+   ALLOW_DYNAMIC_CURSORS = (1L << 2), /* Dynamic cursors are updatable */
+   ALLOW_BULK_OPERATIONS = (1L << 3), /* Bulk operations available */
+   SENSE_SELF_OPERATIONS = (1L << 4), /* Sense self update/delete/add */
+};
 
 /* These errors have general sql error state */
-#define CONNECTION_SERVER_NOT_REACHED          101
+#define CONNECTION_SERVER_NOT_REACHED              101
 #define CONNECTION_MSG_TOO_LONG                    103
 #define CONNECTION_COULD_NOT_SEND              104
 #define CONNECTION_NO_SUCH_DATABASE                105
 #define CONNECTION_BACKEND_CRAZY               106
 #define CONNECTION_NO_RESPONSE                 107
-#define CONNECTION_SERVER_REPORTED_ERROR       108
-#define CONNECTION_COULD_NOT_RECEIVE           109
-#define CONNECTION_SERVER_REPORTED_WARNING     110
+#define CONNECTION_SERVER_REPORTED_ERROR           108
+#define CONNECTION_COULD_NOT_RECEIVE               109
+#define CONNECTION_SERVER_REPORTED_WARNING         110
 #define CONNECTION_NEED_PASSWORD               112
-#define CONNECTION_COULD_NOT_ESTABLISH         113
 
 /* These errors correspond to specific SQL states */
-#define CONN_INIREAD_ERROR                     201
-#define CONN_OPENDB_ERROR                      202
-#define CONN_STMT_ALLOC_ERROR                  203
-#define CONN_IN_USE                                204
-#define CONN_UNSUPPORTED_OPTION                    205
+#define CONN_INIREAD_ERROR                         201
+#define CONN_OPENDB_ERROR                          202
+#define CONN_STMT_ALLOC_ERROR                      203
+#define CONN_IN_USE                            204 
+#define CONN_UNSUPPORTED_OPTION                        205
 /* Used by SetConnectoption to indicate unsupported options */
-#define CONN_INVALID_ARGUMENT_NO               206
+#define CONN_INVALID_ARGUMENT_NO                   206
 /* SetConnectOption: corresponds to ODBC--"S1009" */
-#define CONN_TRANSACT_IN_PROGRES               207
-#define CONN_NO_MEMORY_ERROR                   208
-#define CONN_NOT_IMPLEMENTED_ERROR             209
-#define CONN_INVALID_AUTHENTICATION                210
-#define CONN_AUTH_TYPE_UNSUPPORTED             211
-#define CONN_UNABLE_TO_LOAD_DLL                    212
+#define CONN_TRANSACT_IN_PROGRES                   207
+#define CONN_NO_MEMORY_ERROR                       208
+#define CONN_NOT_IMPLEMENTED_ERROR                 209
+#define CONN_INVALID_AUTHENTICATION                    210
+#define CONN_AUTH_TYPE_UNSUPPORTED                 211
+#define CONN_UNABLE_TO_LOAD_DLL                        212
 
-#define CONN_OPTION_VALUE_CHANGED              213
-#define CONN_VALUE_OUT_OF_RANGE                    214
+#define CONN_OPTION_VALUE_CHANGED                  213
+#define CONN_VALUE_OUT_OF_RANGE                        214
 
 #define CONN_TRUNCATED                         215
-
-
-#define CONN_MEMORY_ALLOCATION_FAILED          301
-#define COULD_NOT_GET_RESULT_BACK              302
+#define CONN_OPTION_NOT_FOR_THE_DRIVER                 216
+#define CONN_EXEC_ERROR                            217
 
 /* Conn_status defines */
-#define CONN_IN_AUTOCOMMIT     1L
+#define CONN_IN_AUTOCOMMIT     1L 
 #define CONN_IN_TRANSACTION        (1L<<1)
 #define CONN_IN_MANUAL_TRANSACTION (1L<<2)
 #define CONN_IN_ERROR_BEFORE_IDLE  (1L<<3)
 /* Transaction in/not functions */
 #define CC_set_in_trans(x) (x->transact_status |= CONN_IN_TRANSACTION)
 #define CC_set_no_trans(x) (x->transact_status &= ~(CONN_IN_TRANSACTION | CONN_IN_ERROR_BEFORE_IDLE))
-#define CC_is_in_trans(x)  (x->transact_status & CONN_IN_TRANSACTION)
+#define CC_is_in_trans(x)  (0 != (x->transact_status & CONN_IN_TRANSACTION))
 
 /* Manual transaction in/not functions */
 #define CC_set_in_manual_trans(x) (x->transact_status |= CONN_IN_MANUAL_TRANSACTION)
 #define CC_set_no_manual_trans(x) (x->transact_status &= ~CONN_IN_MANUAL_TRANSACTION)
-#define CC_is_in_manual_trans(x) (x->transact_status & CONN_IN_MANUAL_TRANSACTION)
+#define CC_is_in_manual_trans(x) (0 != (x->transact_status & CONN_IN_MANUAL_TRANSACTION))
 
 /* Error waiting for ROLLBACK */
 #define CC_set_in_error_trans(x) (x->transact_status |= CONN_IN_ERROR_BEFORE_IDLE)
 #define CC_get_errormsg(x) (x->__error_message)
 #define CC_set_errornumber(x, n)   (x->__error_number = n)
 
+/* Unicode handling */
+#define    CONN_UNICODE_DRIVER (1L)
+#define    CONN_ANSI_APP       (1L << 1)
+#define    CC_set_in_unicode_driver(x) (x->unicode |= CONN_UNICODE_DRIVER)
+#define    CC_set_in_ansi_app(x)   (x->unicode |= CONN_ANSI_APP)
+#define    CC_is_in_unicode_driver(x)  (0 != (x->unicode & CONN_UNICODE_DRIVER))
+#define    CC_is_in_ansi_app(x)    (0 != (x->unicode & CONN_ANSI_APP))
+
 #define CC_MALLOC_return_with_error(t, tp, s, x, m, ret) \
+do { \
+   if (t = malloc(s), NULL == t) \
    { \
-       if (t = malloc(s), NULL == t) \
-       { \
-           CC_set_error(x, CONN_NO_MEMORY_ERROR, m); \
-           return ret; \
-       } \
-   }
+       CC_set_error(x, CONN_NO_MEMORY_ERROR, m, ""); \
+       return ret; \
+   } \
+} while (0)
 #define CC_REALLOC_return_with_error(t, tp, s, x, m, ret) \
+do { \
+   if (t = (tp *) realloc(t, s), NULL == t) \
    { \
-       if (t = (tp *) realloc(t, s), NULL == t) \
-       { \
-           CC_set_error(x, CONN_NO_MEMORY_ERROR, m); \
-           return ret; \
-       } \
-   }
+       CC_set_error(x, CONN_NO_MEMORY_ERROR, m, ""); \
+       return ret; \
+   } \
+} while (0)
 
 /* For Multi-thread */
 #if defined(WIN_MULTITHREAD_SUPPORT)
 #define INIT_CONN_CS(x)        pthread_mutex_init(&((x)->cs), getMutexAttr())
 #define ENTER_CONN_CS(x)   pthread_mutex_lock(&((x)->cs))
 #define ENTER_INNER_CONN_CS(x, entered) \
+do { \
+   if (getMutexAttr()) \
    { \
-       if (getMutexAttr()) \
-       { \
-           if (pthread_mutex_lock(&((x)->cs)) == 0) \
-               entered++; \
-           else \
-               -1; \
-       } \
+       if (pthread_mutex_lock(&((x)->cs)) == 0) \
+           entered++; \
        else \
-           0; \
-   }
+           -1; \
+   } \
+   else \
+       0; \
+} while (0)
 #define LEAVE_CONN_CS(x)   pthread_mutex_unlock(&((x)->cs))
 #define DELETE_CONN_CS(x)  pthread_mutex_destroy(&((x)->cs))
 #else
-#define INIT_CONN_CS(x)
+#define INIT_CONN_CS(x)    
 #define ENTER_CONN_CS(x)
-#define ENTER_INNER_CONN_CS(x, entered) ((void)(0))
+#define ENTER_INNER_CONN_CS(x, entered) (0)
 #define LEAVE_CONN_CS(x)
 #define DELETE_CONN_CS(x)
 #endif /* WIN_MULTITHREAD_SUPPORT */
 
 #define    LEAVE_INNER_CONN_CS(entered, conn) \
+do { \
+   if (entered > 0) \
    { \
-       if (entered > 0) \
-       { \
-           LEAVE_CONN_CS(conn); \
-           entered--; \
-       } \
-   }
-#define    CLEANUP_FUNC_CONN_CS(entered, conn) \
+       LEAVE_CONN_CS(conn); \
+       entered--; \
+   } \
+} while (0)
+#define CLEANUP_FUNC_CONN_CS(entered, conn) \
+do { \
    while (entered > 0) \
    { \
        LEAVE_CONN_CS(conn); \
        entered--; \
-   }
+   } \
+} while (0)
+
+/* Authentication types */
+#define AUTH_REQ_OK        0
+#define AUTH_REQ_KRB4      1
+#define AUTH_REQ_KRB5      2
+#define AUTH_REQ_PASSWORD  3
+#define AUTH_REQ_CRYPT     4
+#define AUTH_REQ_MD5       5
+#define AUTH_REQ_SCM_CREDS 6
+
+/* Startup Packet sizes */
+#define SM_DATABASE        64
+#define SM_USER            32
+#define SM_OPTIONS     64
+#define SM_UNUSED      64
+#define SM_TTY         64
 
+/* Old 6.2 protocol defines */
+#define NO_AUTHENTICATION  7
+#define PATH_SIZE      64
+#define ARGV_SIZE      64
+#define USRNAMEDATALEN     16
+
+typedef unsigned int ProtocolVersion;
+
+#define PG_PROTOCOL(major, minor)  (((major) << 16) | (minor))
+#define PG_PROTOCOL_LATEST PG_PROTOCOL(3, 0) 
+#define PG_PROTOCOL_74 PG_PROTOCOL(3, 0) 
+#define PG_PROTOCOL_64 PG_PROTOCOL(2, 0) 
+#define PG_PROTOCOL_63 PG_PROTOCOL(1, 0)
+#define PG_PROTOCOL_62 PG_PROTOCOL(0, 0)
+
+/* This startup packet is to support latest Postgres protocol (6.4, 6.3) */
+typedef struct _StartupPacket
+{
+   ProtocolVersion protoVersion;
+   char        database[SM_DATABASE];
+   char        user[SM_USER];
+   char        options[SM_OPTIONS];
+   char        unused[SM_UNUSED];
+   char        tty[SM_TTY];
+} StartupPacket;
 
-#define AUTH_REQ_OK                                0
-#define AUTH_REQ_KRB4                          1
-#define AUTH_REQ_KRB5                          2
-#define AUTH_REQ_PASSWORD                      3
-#define AUTH_REQ_CRYPT                         4
-#define AUTH_REQ_MD5                           5
-#define AUTH_REQ_SCM_CREDS                     6
 
-/* Old 6.2 protocol defines */
-#define NO_AUTHENTICATION                      7
-#define PATH_SIZE                              64
-#define ARGV_SIZE                              64
-#define USRNAMEDATALEN                         16
+/* This startup packet is to support pre-Postgres 6.3 protocol */
+typedef struct _StartupPacket6_2
+{
+   unsigned int authtype;
+   char        database[PATH_SIZE];
+   char        user[USRNAMEDATALEN];
+   char        options[ARGV_SIZE];
+   char        execfile[ARGV_SIZE];
+   char        tty[PATH_SIZE];
+} StartupPacket6_2;
 
+/* Transferred from pqcomm.h:  */
 
-typedef enum
+
+typedef ProtocolVersion MsgType;
+
+#define CANCEL_REQUEST_CODE PG_PROTOCOL(1234,5678)
+
+typedef struct CancelRequestPacket
 {
-   CONN_NOT_CONNECTED,         /* Connection has not been established */
-   CONN_CONNECTED,             /* Connection is up and has been
-                                * established */
-   CONN_DOWN,                  /* Connection is broken */
-   CONN_EXECUTING              /* the connection is currently executing a
-                                * statement */
-} CONN_Status;
+   /* Note that each field is stored in network byte order! */
+   MsgType     cancelRequestCode;  /* code to identify a cancel request */
+   unsigned int    backendPID; /* PID of client's backend */
+   unsigned int    cancelAuthCode; /* secret key to authorize cancel */
+} CancelRequestPacket;
 
 /* Structure to hold all the connection attributes for a specific
-   connection (used for both registry and file, DSN and DRIVER) */
-
+   connection (used for both registry and file, DSN and DRIVER)
+*/
 typedef struct
 {
    char        dsn[MEDIUM_REGISTRY_LEN];
@@ -195,8 +263,9 @@ typedef struct
    char        username[MEDIUM_REGISTRY_LEN];
    char        password[MEDIUM_REGISTRY_LEN];
    char        conn_settings[LARGE_REGISTRY_LEN];
+   char        protocol[SMALL_REGISTRY_LEN];
    char        port[SMALL_REGISTRY_LEN];
-   char        sslmode[MEDIUM_REGISTRY_LEN];
+   char        sslmode[SMALL_REGISTRY_LEN];
    char        onlyread[SMALL_REGISTRY_LEN];
    char        fake_oid_index[SMALL_REGISTRY_LEN];
    char        show_oid_column[SMALL_REGISTRY_LEN];
@@ -214,9 +283,26 @@ typedef struct
    signed char bytea_as_longvarbinary;
    signed char use_server_side_prepare;
    signed char lower_case_identifier;
+   signed char rollback_on_error;
+   signed char force_abbrev_connstr;
+#ifdef _HANDLE_ENLIST_IN_DTC_
+   signed char xa_opt;
+   signed char autocommit_normal;
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
    GLOBAL_VALUES drivers;      /* moved from driver's option */
 } ConnInfo;
 
+/* Macro to determine is the connection using 6.2 protocol? */
+#define PROTOCOL_62(conninfo_)     (strncmp((conninfo_)->protocol, PG62, strlen(PG62)) == 0)
+
+/* Macro to determine is the connection using 6.3 protocol? */
+#define PROTOCOL_63(conninfo_)     (strncmp((conninfo_)->protocol, PG63, strlen(PG63)) == 0)
+
+/* Macro to determine is the connection using 6.4 protocol? */
+#define PROTOCOL_74(conninfo_)     (strncmp((conninfo_)->protocol, PG74, strlen(PG74)) == 0)
+
+/* Macro to determine is the connection using 6.4 protocol? */
+#define PROTOCOL_64(conninfo_)     (strncmp((conninfo_)->protocol, PG64, strlen(PG64)) == 0)
 
 /*
  * Macros to compare the server's version with a specified version
@@ -257,10 +343,13 @@ typedef struct
 /* This is used to store cached table information in the connection */
 struct col_info
 {
-   QResultClass *result;
-   char        *schema;
-   char        name[TABLE_NAME_STORAGE_LEN + 1];
+   Int2        num_reserved_cols;
+   QResultClass    *result;
+   pgNAME      schema_name;
+   /**char     table_name[TABLE_NAME_STORAGE_LEN + 1];**/
+   pgNAME      table_name;
 };
+#define col_info_initialize(coli) (memset(coli, 0, sizeof(COL_INFO)))
 
  /* Translation DLL entry points */
 #ifdef WIN32
@@ -271,43 +360,45 @@ struct col_info
 #define HINSTANCE void *
 #endif
 
-typedef BOOL (FAR WINAPI * DataSourceToDriverProc) 
-   (UDWORD,SWORD,PTR,SDWORD,PTR,SDWORD,SDWORD FAR *,UCHAR FAR *,SWORD,SWORD FAR *);
+typedef BOOL (FAR WINAPI * DataSourceToDriverProc) (UDWORD, SWORD, PTR,
+       SDWORD, PTR, SDWORD, SDWORD FAR *, UCHAR FAR *, SWORD,
+       SWORD FAR *); 
+typedef BOOL (FAR WINAPI * DriverToDataSourceProc) (UDWORD, SWORD, PTR,
+       SDWORD, PTR, SDWORD, SDWORD FAR *, UCHAR FAR *, SWORD,
+       SWORD FAR *);
 
-typedef BOOL (FAR WINAPI * DriverToDataSourceProc) 
-   (UDWORD,SWORD,PTR,SDWORD,PTR,SDWORD,SDWORD FAR *,UCHAR FAR *,SWORD,SWORD FAR *);
-
- /*******  The Connection handle   ************/
+/*******   The Connection handle   ************/
 struct ConnectionClass_
 {
-   HENV        henv;           /* environment this connection was created
-                                * on */
+   HENV        henv;       /* environment this connection was
+                    * created on */
    StatementOptions stmtOptions;
    ARDFields   ardOptions;
    APDFields   apdOptions;
-   char       *__error_message;
-   int         __error_number;
-   char        __sqlstate[SQLSTATE_LENGTH + 1];  /* Set only by LIBPQ_execute_query() */
-   CONN_Status status;
+   char        *__error_message;
+   int     __error_number;
+   char        sqlstate[8];
+   CONN_Status status;
    ConnInfo    connInfo;
-   StatementClass **stmts;
-   int         num_stmts;
-   PGconn *pgconn;
-   int         lobj_type;
-   int         ntables;
-   COL_INFO  **col_info;
-   UDWORD      translation_option;
+   StatementClass  **stmts;
+   int     num_stmts;
+   SocketClass *sock;
+   Int4        lobj_type;
+   Int2        ntables;
+   Int2        ncursors;
+   COL_INFO    **col_info;
+   long        translation_option;
    HINSTANCE   translation_handle;
    DataSourceToDriverProc DataSourceToDriver;
    DriverToDataSourceProc DriverToDataSource;
-   Int2        driver_version; /* prepared for ODBC3.0 */
-   char        transact_status;/* Is a transaction is currently in
-                                * progress */
-   char        errormsg_created;       /* has an informative error msg
-                                        * been created?  */
+   Int2        driver_version;     /* prepared for ODBC3.0 */
+   char        transact_status;    /* Is a transaction is currently
+                        * in progress */
+   char        errormsg_created;   /* has an informative error msg
+                        * been created ? */
    char        pg_version[MAX_INFO_STRING];    /* Version of PostgreSQL
-                                                * we're connected to -
-                                                * DJP 25-1-2001 */
+                            * we're connected to -
+                            * DJP 25-1-2001 */
    float       pg_version_number;
    Int2        pg_version_major;
    Int2        pg_version_minor;
@@ -315,32 +406,42 @@ struct ConnectionClass_
    char        unicode;
    char        result_uncommitted;
    char        schema_support;
-   char        *client_encoding;
+   char        lo_is_domain;
+   char        *original_client_encoding;
+   char        *current_client_encoding;
    char        *server_encoding;
-   int     ccsc;
+   Int2        ccsc;
+   Int2        mb_maxbyte_per_char;
    int     be_pid; /* pid returned by backend */
    int     be_key; /* auth code needed to send cancel */
    UInt4       isolation;
    char        *current_schema;
-   int     num_discardp;
+   Int2        max_identifier_length;
+   Int2        num_discardp;
    char        **discardp;
+#if (ODBCVER >= 0x0300)
    int     num_descs;
    DescriptorClass **descs;
+#endif /* ODBCVER */
 #if defined(WIN_MULTITHREAD_SUPPORT)
    CRITICAL_SECTION    cs;
 #elif defined(POSIX_THREADMUTEX_SUPPORT)
    pthread_mutex_t     cs;
 #endif /* WIN_MULTITHREAD_SUPPORT */
+#ifdef _HANDLE_ENLIST_IN_DTC_
+   void        *asdum;
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
 };
 
 
 /* Accessor functions */
-#define CC_get_database(x)                 (x->connInfo.database)
-#define CC_get_server(x)                   (x->connInfo.server)
-#define CC_get_DSN(x)                      (x->connInfo.dsn)
-#define CC_get_username(x)                 (x->connInfo.username)
-#define CC_is_onlyread(x)                  (x->connInfo.onlyread[0] == '1')
-
+#define CC_get_socket(x)           (x->sock)
+#define CC_get_database(x)         (x->connInfo.database)
+#define CC_get_server(x)           (x->connInfo.server)
+#define CC_get_DSN(x)              (x->connInfo.dsn)
+#define CC_get_username(x)         (x->connInfo.username)
+#define CC_is_onlyread(x)          (x->connInfo.onlyread[0] == '1')
 /* for CC_DSN_info */
 #define CONN_DONT_OVERWRITE        0
 #define CONN_OVERWRITE         1
@@ -350,52 +451,65 @@ struct ConnectionClass_
 ConnectionClass *CC_Constructor(void);
 void       CC_conninfo_init(ConnInfo *conninfo);
 char       CC_Destructor(ConnectionClass *self);
-int            CC_cursor_count(ConnectionClass *self);
+int        CC_cursor_count(ConnectionClass *self);
 char       CC_cleanup(ConnectionClass *self);
 char       CC_begin(ConnectionClass *self);
 char       CC_commit(ConnectionClass *self);
 char       CC_abort(ConnectionClass *self);
-int            CC_set_translation(ConnectionClass *self);
+int        CC_set_translation(ConnectionClass *self);
 char       CC_connect(ConnectionClass *self, char password_req, char *salt);
 char       CC_add_statement(ConnectionClass *self, StatementClass *stmt);
-char       CC_remove_statement(ConnectionClass *self, StatementClass *stmt);
+char       CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
+;
+#if (ODBCVER >= 0x0300)
 char       CC_add_descriptor(ConnectionClass *self, DescriptorClass *desc);
 char       CC_remove_descriptor(ConnectionClass *self, DescriptorClass *desc);
-void       CC_set_error(ConnectionClass *self, int number, const char *message);
+#endif /* ODBCVER */
+void       CC_set_error(ConnectionClass *self, int number, const char *message, const char *func);
 void       CC_set_errormsg(ConnectionClass *self, const char *message);
 char       CC_get_error(ConnectionClass *self, int *number, char **message);
-QResultClass   *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag);
+QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag, StatementClass *stmt);
 void       CC_clear_error(ConnectionClass *self);
-char      *CC_create_errormsg(ConnectionClass *self);
+char       *CC_create_errormsg(ConnectionClass *self);
 int        CC_send_function(ConnectionClass *conn, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *argv, int nargs);
 char       CC_send_settings(ConnectionClass *self);
 void       CC_lookup_lo(ConnectionClass *conn);
 void       CC_lookup_pg_version(ConnectionClass *conn);
+void       CC_initialize_pg_version(ConnectionClass *conn);
 void       CC_log_error(const char *func, const char *desc, const ConnectionClass *self);
 int        CC_get_max_query_len(const ConnectionClass *self);
 int        CC_send_cancel_request(const ConnectionClass *conn);
 void       CC_on_commit(ConnectionClass *conn);
 void       CC_on_abort(ConnectionClass *conn, UDWORD opt);
-void       ProcessRollback(ConnectionClass *conn, BOOL undo);
+void       CC_on_abort_partial(ConnectionClass *conn);
+void       ProcessRollback(ConnectionClass *conn, BOOL undo, BOOL partial);
 const char *CC_get_current_schema(ConnectionClass *conn);
-int        CC_mark_a_plan_to_discard(ConnectionClass *conn, const char *plannm);
-int        CC_discard_marked_plans(ConnectionClass *conn);
-void       CC_set_sqlstate(ConnectionClass *self, const char *sqlstate);
-char       *CC_get_sqlstate(ConnectionClass *self);
-
-/* Accessor functions*/
-PGconn         *LIBPQ_Constructor();
-void           LIBPQ_Destructor(PGconn *pgconn);
-int            LIBPQ_connect(ConnectionClass *self);
-QResultClass       *LIBPQ_execute_query(ConnectionClass *self,char *query);
-QResultClass       *CC_mapping(ConnectionClass *self,PGresult *pgres,QResultClass *qres);
-void       CC_is_server_alive(ConnectionClass *conn);
+int             CC_mark_a_object_to_discard(ConnectionClass *conn, int type, const char *plan);
+int             CC_discard_marked_objects(ConnectionClass *conn);
+
+int    handle_error_message(ConnectionClass *self, char *msgbuf, int buflen,
+        char *sqlstate, const char *comment, QResultClass *res);
+int    handle_notice_message(ConnectionClass *self, char *msgbuf, int buflen,
+        char *sqlstate, const char *comment, QResultClass *res);
+int        EatReadyForQuery(ConnectionClass *self);
+void       getParameterValues(ConnectionClass *self);
+int        CC_get_max_idlen(ConnectionClass *self);
+
+BOOL       SendSyncRequest(ConnectionClass *self);
+
 /* CC_send_query options */
-#define    CLEAR_RESULT_ON_ABORT   1L
-#define    CREATE_KEYSET       (1L << 1) /* create keyset for updatable curosrs */
-#define    GO_INTO_TRANSACTION (1L << 2) /* issue begin in advance */
+enum {
+   IGNORE_ABORT_ON_CONN    = 1L /* not set the error result even when  */
+   ,CREATE_KEYSET      = (1L << 1) /* create keyset for updatable curosrs */
+   ,GO_INTO_TRANSACTION    = (1L << 2) /* issue begin in advance */
+   , ROLLBACK_ON_ERROR = (1L << 3) /* rollback the query when an error occurs */
+};
 /* CC_on_abort options */
 #define    NO_TRANS        1L
 #define    CONN_DEAD       (1L << 1) /* connection is no longer valid */
 
+#ifdef __cplusplus
+}
+#endif
 #endif /* __CONNECTION_H__ */
+
index 205b1a03f11a8bad0e71425a27a7a10eea95568e..8cc01db1439c36162b1d4160545da3ae068b1d43 100644 (file)
--- a/convert.c
+++ b/convert.c
 #endif
 #include <math.h>
 #include <stdlib.h>
-#include <libpq/libpq-fs.h>
 #include "statement.h"
 #include "qresult.h"
 #include "bind.h"
 #include "pgtypes.h"
+#include "lobj.h"
 #include "connection.h"
 #include "pgapifunc.h"
 
 #endif
 
 #ifdef __CYGWIN__
-#  define TIMEZONE_GLOBAL _timezone
+#define TIMEZONE_GLOBAL _timezone
 #elif  defined(WIN32) || defined(HAVE_INT_TIMEZONE)
-#  ifdef __BORLANDC__
-#    define timezone _timzone
-#    define daylight _daylight
-#    define TIMEZONE_GLOBAL _timezone
-#  else
-#    define TIMEZONE_GLOBAL timezone
-#  endif
+#define TIMEZONE_GLOBAL timezone
 #endif
 
 /*
- * How to map ODBC scalar functions {fn func(args)} to PostgreSQL.
+ * How to map ODBC scalar functions {fn func(args)} to Postgres.
  * This is just a simple substitution.  List augmented from:
  * http://www.merant.com/datadirect/download/docs/odbc16/Odbcref/rappc.htm
  * - thomas 2000-04-03
@@ -68,15 +62,15 @@ char       *mapFuncs[][2] = {
 /* { "DIFFERENCE", "difference" }, how to ? */
    {"INSERT", "substring($1 from 1 for $2 - 1) || $4 || substring($1 from $2 + $3)" },
    {"LCASE", "lower($*)" },
-   {"LEFT", "substring($1 for $2)" },
+   {"LEFT", "ltrunc($*)" },
    {"%2LOCATE", "strpos($2,  $1)" },   /* 2 parameters */
    {"%3LOCATE", "strpos(substring($2 from $3), $1) + $3 - 1" },    /* 3 parameters */
-/* { "LENGTH",      "length"     }, built_in */
+   {"LENGTH", "char_length($*)"},
 /* { "LTRIM",       "ltrim"      }, built_in */
-   {"RIGHT", "substring($1 from char_length($1) - $2 + 1)" },
-   {"SPACE", "repeat(' ', $1)" },
+   {"RIGHT", "rtrunc($*)" },
+   {"SPACE", "repeat('' '', $1)" },
 /* { "REPEAT",      "repeat"     }, built_in */
-/* { "REPLACE",         "replace"    }, built_in */
+/* { "REPLACE", "replace" }, ??? */
 /* { "RTRIM",       "rtrim"      }, built_in */
 /* { "SOUNDEX", "soundex" }, how to ? */
    {"SUBSTRING", "substr($*)" },
@@ -86,7 +80,7 @@ char     *mapFuncs[][2] = {
 /* { "ACOS",        "acos"       }, built_in */
 /* { "ASIN",        "asin"       }, built_in */
 /* { "ATAN",        "atan"       }, built_in */
-/* { "ATAN2",       "atan2"      }, built_in */
+/* { "ATAN2",       "atan2"      }, bui;t_in */
    {"CEILING", "ceil($*)" },
 /* { "COS",         "cos"        }, built_in */
 /* { "COT",         "cot"        }, built_in */
@@ -109,14 +103,12 @@ char     *mapFuncs[][2] = {
    {"TRUNCATE", "trunc($*)" },
 
    {"CURRENT_DATE", "current_date" },
-   {"%0CURRENT_TIME", "current_time" },
-   {"%1CURRENT_TIME", "current_time($1)" },
-   {"%0CURRENT_TIMESTAMP", "current_timestamp" },
-   {"%1CURRENT_TIMESTAMP", "current_timestamp($1)" },
-   {"%0LOCALTIME", "localtime" },
-   {"%1LOCALTIME", "localtime($1)" },
-   {"%0LOCALTIMESTAMP", "localtimestamp" },
-   {"%1LOCALTIMESTAMP", "localtimestamp($1)" },
+   {"CURRENT_TIME", "current_time" },
+   {"CURRENT_TIMESTAMP", "current_timestamp" },
+   {"LOCALTIME", "localtime" },
+   {"LOCALTIMESTAMP", "localtimestamp" },
+   {"CURRENT_USER", "cast(current_user as text)" },
+   {"SESSION_USER", "cast(session_user as text)" },
    {"CURDATE",  "current_date" },
    {"CURTIME",  "current_time" },
    {"DAYNAME",  "to_char($1, 'Day')" },
@@ -133,17 +125,14 @@ char     *mapFuncs[][2] = {
    {"WEEK",    "cast(extract(week from $1) as integer)" },
    {"YEAR",    "cast(extract(year from $1) as integer)" },
 
-   {"DATABASE", "current_database()" },
+/* { "DATABASE",    "database"   }, */
    {"IFNULL", "coalesce($*)" },
    {"USER", "cast(current_user as text)" },
-   {"CURRENT_USER", "cast(current_user as text)" },
-   {"SESSION_USER", "cast(session_user as text)" },
    {0, 0}
 };
 
 static const char *mapFunction(const char *func, int param_count);
 static unsigned int conv_from_octal(const UCHAR *s);
-static unsigned int conv_from_hex(const UCHAR *s);
 static char *conv_to_octal(UCHAR val, char *octal);
 static int pg_bin2hex(UCHAR *src, UCHAR *dst, int length);
 
@@ -186,12 +175,18 @@ static int pg_bin2hex(UCHAR *src, UCHAR *dst, int length);
 #define    ATOI64U _atoi64
 #define    FORMATI64   "%I64d"
 #define    FORMATI64U  "%I64u"
+#elif  (SIZEOF_LONG == 8)
+#define    ATOI64(val) strtol(val, NULL, 10)
+#define    ATOI64U(val)    strtoul(val, NULL, 10)
+#define    FORMATI64   "%ld"
+#define    FORMATI64U  "%lu"
 #elif  defined(HAVE_STRTOLL)
 #define    ATOI64(val) strtoll(val, NULL, 10)
 #define    ATOI64U(val)    strtoull(val, NULL, 10)
 #define    FORMATI64   "%lld"
 #define    FORMATI64U  "%llu"
 #else /* HAVE_STRTOLL */
+#error cant handle ODBCINT64
 #endif /* WIN32 */
 #endif /* ODBCINT64 */
 
@@ -391,8 +386,8 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
    CSTR func = "copy_and_convert_field";
    ARDFields   *opts = SC_get_ARDF(stmt);
    GetDataInfo *gdata = SC_get_GDTI(stmt);
-   Int4        len = 0,
-               copy_len = 0;
+   SQLLEN      len = 0,
+               copy_len = 0, needbuflen = 0;
    SIMPLE_TIME std_time;
    time_t      stmt_t = SC_get_time(stmt);
    struct tm  *tim;
@@ -408,17 +403,21 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
    int         result = COPY_OK;
    ConnectionClass     *conn = SC_get_conn(stmt);
    BOOL        changed, true_is_minus1 = FALSE;
+   BOOL    text_handling, localize_needed;
    const char *neut_str = value;
    char        midtemp[2][32];
    int         mtemp_cnt = 0;
    GetDataClass *pgdc;
 #ifdef UNICODE_SUPPORT
-   BOOL    wchanged =   FALSE;
+   BOOL    wconverted =   FALSE;
 #endif /* UNICODE_SUPPORT */
 #ifdef WIN_UNICODE_SUPPORT
    SQLWCHAR    *allocbuf = NULL;
    Int4        wstrlen;    
 #endif /* WIN_UNICODE_SUPPORT */
+#ifdef HAVE_LOCALE_H
+   char *saved_locale;
+#endif /* HAVE_LOCALE_H */
 
    if (stmt->current_col >= 0)
    {
@@ -478,6 +477,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
    std_time.y = tim->tm_year + 1900;
 
    mylog("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n", field_type, fCType, (value == NULL) ? "<NULL>" : value, cbValueMax);
+
    if (!value)
    {
        /*
@@ -491,15 +491,14 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
        }
        else
        {
-           SC_set_error(stmt, STMT_RETURN_NULL_WITHOUT_INDICATOR, "StrLen_or_IndPtr was a null pointer and NULL data was retrieved");  
-           SC_log_error(func, "", stmt);
+           SC_set_error(stmt, STMT_RETURN_NULL_WITHOUT_INDICATOR, "StrLen_or_IndPtr was a null pointer and NULL data was retrieved", func);    
            return  SQL_ERROR;
        }
    }
 
    if (stmt->hdbc->DataSourceToDriver != NULL)
    {
-       int         length = strlen(value);
+       size_t          length = strlen(value);
 
        stmt->hdbc->DataSourceToDriver(stmt->hdbc->translation_option,
                                       SQL_CHAR,
@@ -679,8 +678,9 @@ inolog("2stime fr=%d\n", std_time.fr);
 
        default:
 
-           if (field_type == stmt->hdbc->lobj_type)    /* hack until permanent
-                                                        * type available */
+           if (field_type == stmt->hdbc->lobj_type /* hack until permanent type available */
+              || (PG_TYPE_OID == field_type && SQL_C_BINARY == fCType && conn->lo_is_domain)
+              )
                return convert_lo(stmt, value, fCType, rgbValueBindRow, cbValueMax, (SDWORD *) pcbValueBindRow);
    }
 
@@ -688,16 +688,42 @@ inolog("2stime fr=%d\n", std_time.fr);
    if (fCType == SQL_C_DEFAULT)
    {
        fCType = pgtype_to_ctype(stmt, field_type);
+       if (fCType == SQL_C_WCHAR
+           && (CC_is_in_ansi_app(conn) 
+           || conn->ms_jet /* not only but for any other ? */
+          ))
+           fCType = SQL_C_CHAR;
 
        mylog("copy_and_convert, SQL_C_DEFAULT: fCType = %d\n", fCType);
    }
 
+   text_handling = localize_needed = FALSE;
+   if (fCType == INTERNAL_ASIS_TYPE
 #ifdef UNICODE_SUPPORT
-   if (fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR
-#else
-   if (fCType == SQL_C_CHAR
+       || fCType == SQL_C_WCHAR
 #endif /* UNICODE_SUPPORT */
-       || fCType == INTERNAL_ASIS_TYPE)
+       || fCType == SQL_C_CHAR)
+       text_handling = TRUE;
+   else if (fCType == SQL_C_BINARY &&
+        (field_type == PG_TYPE_UNKNOWN
+         || field_type == PG_TYPE_BPCHAR
+         || field_type == PG_TYPE_VARCHAR
+         || field_type == PG_TYPE_TEXT
+         || field_type == PG_TYPE_BPCHARARRAY
+         || field_type == PG_TYPE_VARCHARARRAY
+         || field_type == PG_TYPE_TEXTARRAY
+        ))
+       text_handling = TRUE;
+   if (text_handling)
+   {
+#ifdef WIN_UNICODE_SUPPORT
+       if (SQL_C_CHAR == fCType
+           || SQL_C_BINARY == fCType)
+           localize_needed = TRUE;
+#endif /* WIN_UNICODE_SUPPORT */
+   }
+
+   if (text_handling)
    {
        /* Special character formatting as required */
 
@@ -762,6 +788,10 @@ inolog("2stime fr=%d\n", std_time.fr);
                }
                else
                    pgdc = &gdata->gdata[stmt->current_col];
+#ifdef UNICODE_SUPPORT
+               if (fCType == SQL_C_WCHAR)
+                   wconverted = TRUE;
+#endif /* UNICODE_SUPPORT */
                if (pgdc->data_left < 0)
                {
                    BOOL lf_conv = conn->connInfo.lf_conversion;
@@ -770,7 +800,7 @@ inolog("2stime fr=%d\n", std_time.fr);
                    {
                        len = utf8_to_ucs2_lf(neut_str, -1, lf_conv, NULL, 0);
                        len *= WCLEN;
-                       wchanged = changed = TRUE;
+                       changed = TRUE;
                    }
                    else
 #endif /* UNICODE_SUPPORT */
@@ -782,7 +812,7 @@ inolog("2stime fr=%d\n", std_time.fr);
                    }
                    else
 #ifdef WIN_UNICODE_SUPPORT
-                   if (fCType == SQL_C_CHAR)
+                   if (localize_needed)
                    {
                        wstrlen = utf8_to_ucs2_lf(neut_str, -1, lf_conv, NULL, 0);
                        allocbuf = (SQLWCHAR *) malloc(WCLEN * (wstrlen + 1));
@@ -806,12 +836,25 @@ inolog("2stime fr=%d\n", std_time.fr);
                    }
                    if (!pgdc->ttlbuf)
                        pgdc->ttlbuflen = 0;
-                   if (changed || len >= cbValueMax)
+                   needbuflen = len;
+                   switch (fCType)
+                   {
+#ifdef UNICODE_SUPPORT
+                       case SQL_C_WCHAR:
+                           needbuflen += WCLEN;
+                           break;
+#endif /* UNICODE_SUPPORT */
+                       case SQL_C_BINARY:
+                           break;
+                       default:
+                           needbuflen++;
+                   }
+                   if (changed || needbuflen > cbValueMax)
                    {
-                       if (len >= (int) pgdc->ttlbuflen)
+                       if (needbuflen > (SQLLEN) pgdc->ttlbuflen)
                        {
-                           pgdc->ttlbuf = realloc(pgdc->ttlbuf, len + 1);
-                           pgdc->ttlbuflen = len + 1;
+                           pgdc->ttlbuf = realloc(pgdc->ttlbuf, needbuflen);
+                           pgdc->ttlbuflen = needbuflen;
                        }
 #ifdef UNICODE_SUPPORT
                        if (fCType == SQL_C_WCHAR)
@@ -828,7 +871,7 @@ inolog("2stime fr=%d\n", std_time.fr);
                        }
                        else
 #ifdef WIN_UNICODE_SUPPORT
-                       if (fCType == SQL_C_CHAR)
+                       if (localize_needed)
                        {
                            len = WideCharToMultiByte(CP_ACP, 0, allocbuf, wstrlen, pgdc->ttlbuf, pgdc->ttlbuflen, NULL, NULL);
                            free(allocbuf);
@@ -856,7 +899,7 @@ inolog("2stime fr=%d\n", std_time.fr);
                    len = pgdc->ttlbufused;
                }
 
-               mylog("DEFAULT: len = %d, ptr = '%s'\n", len, ptr);
+               mylog("DEFAULT: len = %d, ptr = '%.*s'\n", len, len, ptr);
 
                if (stmt->current_col >= 0)
                {
@@ -864,6 +907,7 @@ inolog("2stime fr=%d\n", std_time.fr);
                    {
                        ptr += len - pgdc->data_left;
                        len = pgdc->data_left;
+                       needbuflen = len + (pgdc->ttlbuflen - pgdc->ttlbufused);
                    }
                    else
                        pgdc->data_left = len;
@@ -873,7 +917,10 @@ inolog("2stime fr=%d\n", std_time.fr);
                {
                    BOOL    already_copied = FALSE;
 
-                   copy_len = (len >= cbValueMax) ? cbValueMax - 1 : len;
+                   if (fCType == SQL_C_BINARY)
+                       copy_len = (len > cbValueMax) ? cbValueMax : len;
+                   else
+                       copy_len = (len >= cbValueMax) ? (cbValueMax - 1) : len;
 #ifdef UNICODE_SUPPORT
                    if (fCType == SQL_C_WCHAR)
                    {
@@ -918,12 +965,13 @@ inolog("2stime fr=%d\n", std_time.fr);
 #ifdef UNICODE_SUPPORT
                        if (fCType == SQL_C_WCHAR)
                        {
-                           memset(rgbValueBindRow + copy_len, 0, WCLEN);
-                           wchanged = TRUE;
+                           if (copy_len + WCLEN <= cbValueMax)
+                               memset(rgbValueBindRow + copy_len, 0, WCLEN);
                        }
                        else
 #endif /* UNICODE_SUPPORT */
-                       rgbValueBindRow[copy_len] = '\0';
+                       if (copy_len < cbValueMax)
+                           rgbValueBindRow[copy_len] = '\0';
                    }
                    /* Adjust data_left for next time */
                    if (stmt->current_col >= 0)
@@ -934,7 +982,7 @@ inolog("2stime fr=%d\n", std_time.fr);
                 * Finally, check for truncation so that proper status can
                 * be returned
                 */
-               if (cbValueMax > 0 && len >= cbValueMax)
+               if (cbValueMax > 0 && needbuflen > cbValueMax)
                    result = COPY_RESULT_TRUNCATED;
                else
                {
@@ -946,29 +994,23 @@ inolog("2stime fr=%d\n", std_time.fr);
                }
 
 
-               mylog("    SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
+               if (SQL_C_WCHAR == fCType)
+                   mylog("    SQL_C_WCHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%S'\n", len, cbValueMax, rgbValueBindRow);
+               else if (SQL_C_BINARY == fCType)
+                   mylog("    SQL_C_BINARY, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%.*s'\n", len, cbValueMax, copy_len, rgbValueBindRow);
+               else
+                   mylog("    SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
                break;
        }
 #ifdef UNICODE_SUPPORT
-       if (SQL_C_WCHAR == fCType && ! wchanged)
+       if (SQL_C_WCHAR == fCType && ! wconverted)
        {
-           if (cbValueMax > (SDWORD) (WCLEN * (len + 1)))
-           {
-               char *str = strdup(rgbValueBindRow);
-               UInt4   ucount = utf8_to_ucs2(str, len, (SQLWCHAR *) rgbValueBindRow, cbValueMax / WCLEN);
-               if (cbValueMax < (SDWORD) (WCLEN * ucount))
-                   result = COPY_RESULT_TRUNCATED;
-               free(str); 
-           }
-           else
-           {
-                if ((SDWORD) (len + WCLEN) <= cbValueMax)
-                {
-                    result = COPY_OK;
-                }
-                else
-                    result = COPY_RESULT_TRUNCATED; 
-           }
+           char *str = strdup(rgbValueBindRow);
+           UInt4   ucount = utf8_to_ucs2(str, len, (SQLWCHAR *) rgbValueBindRow, cbValueMax / WCLEN);
+           if (cbValueMax < (SDWORD) (WCLEN * ucount))
+               result = COPY_RESULT_TRUNCATED;
+           len = ucount * WCLEN;
+           free(str); 
        }
 #endif /* UNICODE_SUPPORT */
 
@@ -997,8 +1039,9 @@ inolog("2stime fr=%d\n", std_time.fr);
        switch (fCType)
        {
            case SQL_C_DATE:
+#if (ODBCVER >= 0x0300)
            case SQL_C_TYPE_DATE:       /* 91 */
-
+#endif
                len = 6;
                {
                    DATE_STRUCT *ds;
@@ -1014,8 +1057,9 @@ inolog("2stime fr=%d\n", std_time.fr);
                break;
 
            case SQL_C_TIME:
+#if (ODBCVER >= 0x0300)
            case SQL_C_TYPE_TIME:       /* 92 */
-
+#endif
                len = 6;
                {
                    TIME_STRUCT *ts;
@@ -1031,8 +1075,9 @@ inolog("2stime fr=%d\n", std_time.fr);
                break;
 
            case SQL_C_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
            case SQL_C_TYPE_TIMESTAMP:  /* 93 */
-
+#endif
                len = 16;
                {
                    TIMESTAMP_STRUCT *ts;
@@ -1083,10 +1128,7 @@ inolog("2stime fr=%d\n", std_time.fr);
                break;
 
            case SQL_C_FLOAT:
-           {
 #ifdef HAVE_LOCALE_H
-               char *saved_locale;
-
                saved_locale = strdup(setlocale(LC_ALL, NULL));
                setlocale(LC_ALL, "C");
 #endif /* HAVE_LOCALE_H */
@@ -1100,13 +1142,9 @@ inolog("2stime fr=%d\n", std_time.fr);
                free(saved_locale);
 #endif /* HAVE_LOCALE_H */
                break;
-           }
 
            case SQL_C_DOUBLE:
-           {
 #ifdef HAVE_LOCALE_H
-               char *saved_locale;
-
                saved_locale = strdup(setlocale(LC_ALL, NULL));
                setlocale(LC_ALL, "C");
 #endif /* HAVE_LOCALE_H */
@@ -1120,109 +1158,116 @@ inolog("2stime fr=%d\n", std_time.fr);
                free(saved_locale);
 #endif /* HAVE_LOCALE_H */
                break;
-           }
 
-           case SQL_C_NUMERIC:
+#if (ODBCVER >= 0x0300)
+                        case SQL_C_NUMERIC:
+#ifdef HAVE_LOCALE_H
+           /* strcpy(saved_locale, setlocale(LC_ALL, NULL));
+           setlocale(LC_ALL, "C"); not needed currently */ 
+#endif /* HAVE_LOCALE_H */
            {
-               SQL_NUMERIC_STRUCT      *ns;
-               int i, nlen, bit, hval, tv, dig, sta, olen;
-               char    calv[SQL_MAX_NUMERIC_LEN * 3];
-               const char *wv;
-               BOOL    dot_exist;
+           SQL_NUMERIC_STRUCT      *ns;
+           int i, nlen, bit, hval, tv, dig, sta, olen;
+           char    calv[SQL_MAX_NUMERIC_LEN * 3];
+           const char *wv;
+           BOOL    dot_exist;
 
-               len = sizeof(SQL_NUMERIC_STRUCT);
-               if (bind_size > 0)
-                   ns = (SQL_NUMERIC_STRUCT *) rgbValueBindRow;
-               else
-                   ns = (SQL_NUMERIC_STRUCT *) rgbValue + bind_row;
-               for (wv = neut_str; *wv && isspace(*wv); wv++)
-                   ;
-               ns->sign = 1;
-               if (*wv == '-')
+           len = sizeof(SQL_NUMERIC_STRUCT);
+           if (bind_size > 0)
+               ns = (SQL_NUMERIC_STRUCT *) rgbValueBindRow;
+           else
+               ns = (SQL_NUMERIC_STRUCT *) rgbValue + bind_row;
+           for (wv = neut_str; *wv && isspace(*wv); wv++)
+               ;
+           ns->sign = 1;
+           if (*wv == '-')
+           {
+               ns->sign = 0;
+               wv++;
+           }
+           else if (*wv == '+')
+               wv++;
+           while (*wv == '0') wv++;
+           ns->precision = 0;
+           ns->scale = 0;
+           for (nlen = 0, dot_exist = FALSE;; wv++) 
+           {
+               if (*wv == '.')
                {
-                   ns->sign = 0;
-                   wv++;
+                   if (dot_exist)
+                       break;
+                   dot_exist = TRUE;
                }
-               else if (*wv == '+')
-                   wv++;
-               while (*wv == '0') wv++;
-               ns->precision = 0;
-               ns->scale = 0;
-               for (nlen = 0, dot_exist = FALSE;; wv++) 
-               {
-                   if (*wv == '.')
-                   {
-                       if (dot_exist)
-                           break;
-                       dot_exist = TRUE;
-                   }
-                   else if (!isdigit(*wv))
+               else if (!isdigit(*wv))
                        break;
+               else
+               {
+                   if (dot_exist)
+                       ns->scale++;
                    else
-                   {
-                       if (dot_exist)
-                           ns->scale++;
-
                        ns->precision++;
-                       calv[nlen++] = *wv;
-                   }
+                   calv[nlen++] = *wv;
                }
-               memset(ns->val, 0, sizeof(ns->val));
-               for (hval = 0, bit = 1L, sta = 0, olen = 0; sta < nlen;)
+           }
+           memset(ns->val, 0, sizeof(ns->val));
+           for (hval = 0, bit = 1L, sta = 0, olen = 0; sta < nlen;)
+           {
+               for (dig = 0, i = sta; i < nlen; i++)
                {
-                   for (dig = 0, i = sta; i < nlen; i++)
-                   {
-                       tv = dig * 10 + calv[i] - '0';
-                       dig = tv % 2;
-                       calv[i] = tv / 2 + '0';
-                       if (i == sta && tv < 2)
-                           sta++;
-                   }
-                   if (dig > 0)
-                       hval |= bit;
-                   bit <<= 1;
-                   if (bit >= (1L << 8))
-                   {
-                       ns->val[olen++] = hval;
-                       hval = 0;
-                       bit = 1L;
-                       if (olen >= SQL_MAX_NUMERIC_LEN - 1)
-                       {
-                           ns->scale = sta - ns->precision;
-                           break;
-                       }
-                   } 
+                   tv = dig * 10 + calv[i] - '0';
+                   dig = tv % 2;
+                   calv[i] = tv / 2 + '0';
+                   if (i == sta && tv < 2)
+                       sta++;
                }
-               if (hval && olen < SQL_MAX_NUMERIC_LEN - 1)
+               if (dig > 0)
+                   hval |= bit;
+               bit <<= 1;
+               if (bit >= (1L << 8))
+               {
                    ns->val[olen++] = hval;
-
-               break;
+                   hval = 0;
+                   bit = 1L;
+                   if (olen >= SQL_MAX_NUMERIC_LEN - 1)
+                   {
+                       ns->scale = sta - ns->precision;
+                       break;
+                   }
+               } 
            }
+           if (hval && olen < SQL_MAX_NUMERIC_LEN - 1)
+               ns->val[olen++] = hval;
+           }
+#ifdef HAVE_LOCALE_H
+           /* setlocale(LC_ALL, saved_locale); */
+#endif /* HAVE_LOCALE_H */
+           break;
+#endif /* ODBCVER */
 
            case SQL_C_SSHORT:
            case SQL_C_SHORT:
                len = 2;
                if (bind_size > 0)
-                   *((SWORD *) rgbValueBindRow) = atoi(neut_str);
+                   *((SQLSMALLINT *) rgbValueBindRow) = atoi(neut_str);
                else
-                   *((SWORD *) rgbValue + bind_row) = atoi(neut_str);
+                   *((SQLSMALLINT *) rgbValue + bind_row) = atoi(neut_str);
                break;
 
            case SQL_C_USHORT:
                len = 2;
                if (bind_size > 0)
-                   *((UWORD *) rgbValueBindRow) = atoi(neut_str);
+                   *((SQLUSMALLINT *) rgbValueBindRow) = atoi(neut_str);
                else
-                   *((UWORD *) rgbValue + bind_row) = atoi(neut_str);
+                   *((SQLUSMALLINT *) rgbValue + bind_row) = atoi(neut_str);
                break;
 
            case SQL_C_SLONG:
            case SQL_C_LONG:
                len = 4;
                if (bind_size > 0)
-                   *((SDWORD *) rgbValueBindRow) = atol(neut_str);
+                   *((SQLINTEGER *) rgbValueBindRow) = atol(neut_str);
                else
-                   *((SDWORD *) rgbValue + bind_row) = atol(neut_str);
+                   *((SQLINTEGER *) rgbValue + bind_row) = atol(neut_str);
                break;
 
            case SQL_C_ULONG:
@@ -1233,9 +1278,8 @@ inolog("2stime fr=%d\n", std_time.fr);
                    *((UDWORD *) rgbValue + bind_row) = ATOI32U(neut_str);
                break;
 
-#ifdef ODBCINT64
+#if (ODBCVER >= 0x0300) && defined(ODBCINT64)
            case SQL_C_SBIGINT:
-           case SQL_BIGINT: /* Is this needed ? */
                len = 8;
                if (bind_size > 0)
                    *((SQLBIGINT *) rgbValueBindRow) = ATOI64(neut_str);
@@ -1256,7 +1300,10 @@ inolog("2stime fr=%d\n", std_time.fr);
                if (PG_TYPE_UNKNOWN == field_type ||
                    PG_TYPE_TEXT == field_type ||
                    PG_TYPE_VARCHAR == field_type ||
-                   PG_TYPE_BPCHAR == field_type)
+                   PG_TYPE_BPCHAR == field_type ||
+                   PG_TYPE_TEXTARRAY == field_type ||
+                   PG_TYPE_VARCHARARRAY == field_type ||
+                   PG_TYPE_BPCHARARRAY == field_type)
                {
                    int len = SQL_NULL_DATA;
 
@@ -1404,6 +1451,7 @@ inolog("SQL_C_VARBOOKMARK value=%d\n", ival);
 #define    FLGP_SELECT_INTO        (1L << 2)
 #define    FLGP_SELECT_FOR_UPDATE  (1L << 3)
 #define    FLGP_BUILDING_PREPARE_STATEMENT (1L << 4)
+#define    FLGP_MULTIPLE_STATEMENT (1L << 5)
 typedef struct _QueryParse {
    const char  *statement;
    int     statement_type;
@@ -1411,7 +1459,9 @@ typedef struct _QueryParse {
    int     from_pos;
    int     where_pos;
    UInt4       stmt_len;
-   BOOL        in_quote, in_dquote, in_escape;
+   char        in_literal, in_identifier, in_escape, in_dollar_quote;
+   const   char *dollar_tag;
+   int     taglen;
    char        token_save[64];
    int     token_len;
    BOOL        prev_token_end;
@@ -1430,7 +1480,9 @@ QP_initialize(QueryParse *q, const StatementClass *stmt)
    q->from_pos = -1;
    q->where_pos = -1;
    q->stmt_len = (q->statement) ? strlen(q->statement) : -1;
-   q->in_quote = q->in_dquote = q->in_escape = FALSE;
+   q->in_literal = q->in_identifier = q->in_escape = q->in_dollar_quote = FALSE;
+   q->dollar_tag = NULL;
+   q->taglen = -1;
    q->token_save[0] = '\0';
    q->token_len = 0;
    q->prev_token_end = TRUE;
@@ -1443,23 +1495,33 @@ QP_initialize(QueryParse *q, const StatementClass *stmt)
 }
 
 #define    FLGB_PRE_EXECUTING  1L
-#define    FLGB_INACCURATE_RESULT  (1L << 1)
-#define    FLGB_CREATE_KEYSET  (1L << 2)
-#define    FLGB_KEYSET_DRIVEN  (1L << 3)
-#define    FLGB_BUILDING_PREPARE_STATEMENT (1L << 4)
+#define    FLGB_BUILDING_PREPARE_STATEMENT (1L << 1)
+#define    FLGB_BUILDING_BIND_REQUEST  (1L << 2)
+#define    FLGB_EXECUTE_PREPARED       (1L << 3)
+
+#define    FLGB_INACCURATE_RESULT  (1L << 4)
+#define    FLGB_CREATE_KEYSET  (1L << 5)
+#define    FLGB_KEYSET_DRIVEN  (1L << 6)
+#define    FLGB_CONVERT_LF     (1L << 7)
+#define    FLGB_DISCARD_OUTPUT (1L << 8)
+#define    FLGB_BINARY_AS_POSSIBLE (1L << 9)
 typedef struct _QueryBuild {
    char    *query_statement;
    UInt4   str_size_limit;
    UInt4   str_alsize;
    UInt4   npos;
-   int current_row;
-   int param_number;
+   Int4    current_row;
+   Int2    param_number;
+   Int2    dollar_number;
+   Int2    num_io_params;
+   Int2    num_output_params;
+   Int2    num_discard_params;
+   Int2    proc_return;
    APDFields *apdopts;
    IPDFields *ipdopts;
    PutDataInfo *pdata;
    UInt4   load_stmt_len;
    UInt4   flags;
-   BOOL    lf_conv;
    int ccsc;
    int errornumber;
    const char *errormsg;
@@ -1480,23 +1542,38 @@ QB_initialize(QueryBuild *qb, UInt4 size, StatementClass *stmt, ConnectionClass
    qb->apdopts = NULL;
    qb->ipdopts = NULL;
    qb->pdata = NULL;
+   qb->proc_return = 0;
+   qb->num_io_params = 0;
+   qb->num_output_params = 0;
+   qb->num_discard_params = 0;
    if (conn)
        qb->conn = conn;
    else if (stmt)
    {
+       Int2    dummy;
+
        qb->apdopts = SC_get_APDF(stmt);
        qb->ipdopts = SC_get_IPDF(stmt);
        qb->pdata = SC_get_PDTI(stmt);
        qb->conn = SC_get_conn(stmt);
        if (stmt->pre_executing)
            qb->flags |= FLGB_PRE_EXECUTING;
+       if (stmt->discard_output_params)
+           qb->flags |= FLGB_DISCARD_OUTPUT;
+       qb->num_io_params = CountParameters(stmt, NULL, &dummy, &qb->num_output_params);
+       qb->proc_return = stmt->proc_return;
+       if (0 != (qb->flags & FLGB_DISCARD_OUTPUT))
+           qb->num_discard_params = qb->num_output_params;
+       if (qb->num_discard_params < qb->proc_return)
+           qb->num_discard_params = qb->proc_return;
    }
    else
    {
        qb->conn = NULL;
        return -1;
    }
-   qb->lf_conv = qb->conn->connInfo.lf_conversion;
+   if (qb->conn->connInfo.lf_conversion)
+       qb->flags |= FLGB_CONVERT_LF;
    qb->ccsc = qb->conn->ccsc;
        
    if (stmt)
@@ -1525,6 +1602,7 @@ QB_initialize(QueryBuild *qb, UInt4 size, StatementClass *stmt, ConnectionClass
    qb->npos = 0;
    qb->current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
    qb->param_number = -1;
+   qb->dollar_number = 0;
    qb->errornumber = 0;
    qb->errormsg = NULL;
 
@@ -1553,6 +1631,17 @@ QB_initialize_copy(QueryBuild *qb_to, const QueryBuild *qb_from, UInt4 size)
    return size;
 }
 
+static void
+QB_replace_SC_error(StatementClass *stmt, const QueryBuild *qb, const char *func)
+{
+   int number;
+
+   if (0 == qb->errornumber)   return;
+   if ((number = SC_get_errornumber(stmt)) > 0) return;
+   if (number < 0 && qb->errornumber < 0)  return;
+   SC_set_error(stmt, qb->errornumber, qb->errormsg, func);
+}
+
 static void
 QB_Destructor(QueryBuild *qb)
 {
@@ -1589,9 +1678,9 @@ do { \
    unsigned int    c = 0; \
    while (qp->statement[qp->opos] != '\0' && qp->statement[qp->opos] != ch) \
    { \
-       buf[c++] = qp->statement[qp->opos++]; \
-       if (c >= maxsize - 1) \
+       if (c >= maxsize) \
            break; \
+       buf[c++] = qp->statement[qp->opos++]; \
    } \
    if (qp->statement[qp->opos] == '\0') \
        return SQL_ERROR; \
@@ -1635,8 +1724,7 @@ enlarge_query_statement(QueryBuild *qb, unsigned int newsize)
        if (qb->stmt)
        {
            
-           SC_set_error(qb->stmt, STMT_EXEC_ERROR, "Query buffer overflow in copy_statement_with_parameters");
-           SC_log_error(func, "", qb->stmt);
+           SC_set_error(qb->stmt, STMT_EXEC_ERROR, "Query buffer overflow in copy_statement_with_parameters", func);
        }
        else
        {
@@ -1652,7 +1740,7 @@ enlarge_query_statement(QueryBuild *qb, unsigned int newsize)
        qb->str_alsize = 0;
        if (qb->stmt)
        {
-           SC_set_error(qb->stmt, STMT_EXEC_ERROR, "Query buffer allocate error in copy_statement_with_parameters");
+           SC_set_error(qb->stmt, STMT_EXEC_ERROR, "Query buffer allocate error in copy_statement_with_parameters", func);
        }
        else
        {
@@ -1727,7 +1815,7 @@ do { \
 do { \
    unsigned int    newlimit = qb->npos + 5 * used; \
    ENLARGE_NEWSTATEMENT(qb, newlimit); \
-   qb->npos += convert_to_pgbinary(buf, &qb->query_statement[qb->npos], used); \
+   qb->npos += convert_to_pgbinary(buf, &qb->query_statement[qb->npos], used, qb->flags); \
 } while (0)
 
 /*----------
@@ -1736,11 +1824,11 @@ do { \
  */
 #define CVT_SPECIAL_CHARS(qb, buf, used) \
 do { \
-   int cnvlen = convert_special_chars(buf, NULL, used, qb->lf_conv, qb->ccsc); \
+   int cnvlen = convert_special_chars(buf, NULL, used, qb->flags, qb->ccsc); \
    unsigned int    newlimit = qb->npos + cnvlen; \
 \
    ENLARGE_NEWSTATEMENT(qb, newlimit); \
-   convert_special_chars(buf, &qb->query_statement[qb->npos], used, qb->lf_conv, qb->ccsc); \
+   convert_special_chars(buf, &qb->query_statement[qb->npos], used, qb->flags, qb->ccsc); \
    qb->npos += cnvlen; \
 } while (0)
 
@@ -1763,18 +1851,18 @@ into_table_from(const char *stmt)
    {
        case '\0':
        case ',':
-       case '\'':
+       case LITERAL_QUOTE:
            return FALSE;
-       case '\"':              /* double quoted table name ? */
+       case IDENTIFIER_QUOTE:  /* double quoted table name ? */
            do
            {
                do
-                   while (*(++stmt) != '\"' && *stmt);
-               while (*stmt && *(++stmt) == '\"');
-               while (*stmt && !isspace((UCHAR) *stmt) && *stmt != '\"')
+                   while (*(++stmt) != IDENTIFIER_QUOTE && *stmt);
+               while (*stmt && *(++stmt) == IDENTIFIER_QUOTE);
+               while (*stmt && !isspace((UCHAR) *stmt) && *stmt != IDENTIFIER_QUOTE)
                    stmt++;
            }
-           while (*stmt == '\"');
+           while (*stmt == IDENTIFIER_QUOTE);
            break;
        default:
            while (!isspace((UCHAR) *(++stmt)));
@@ -1837,50 +1925,66 @@ insert_without_target(const char *stmt, int *endpos)
        || ';' == wstmt[0];
 }
 
+static
+RETCODE    prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb);
 static int
 Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
 {
    CSTR func = "Prepare_and_convert";
    char    *new_statement, *exe_statement = NULL;
    int retval;
+   ConnectionClass *conn = SC_get_conn(stmt);
+   ConnInfo    *ci = &(conn->connInfo);
+   BOOL    discardOutput, outpara;
 
+   if (PROTOCOL_74(ci) && NOT_YET_PREPARED != stmt->prepared)
+       return SQL_SUCCESS;
    if (QB_initialize(qb, qp->stmt_len, stmt, NULL) < 0)
        return SQL_ERROR;
-   if (!stmt->prepared) /*  not yet prepared */
+   if (PROTOCOL_74(ci))
+       return prep_params(stmt, qp, qb);
+   discardOutput = (0 != (qb->flags & FLGB_DISCARD_OUTPUT));
+   if (NOT_YET_PREPARED == stmt->prepared) /*  not yet prepared */
    {
-       int i, elen;
-       SWORD   marker_count;
+       int i, oc, elen;
+       SQLSMALLINT marker_count;
        const IPDFields *ipdopts = qb->ipdopts;
+       char    plan_name[32];
 
        new_statement = qb->query_statement;
-       qb->flags = FLGB_BUILDING_PREPARE_STATEMENT;
-       sprintf(new_statement, "PREPARE \"_PLAN%p\"", stmt);
+       qb->flags |= FLGB_BUILDING_PREPARE_STATEMENT;
+       sprintf(plan_name, "_PLAN%0x", stmt);
+       sprintf(new_statement, "PREPARE \"%s\"", plan_name);
        qb->npos = strlen(new_statement);
-       if (SQL_SUCCESS != PGAPI_NumParams(stmt, &marker_count))
+       marker_count = stmt->num_params - qb->num_discard_params;
+       if (!ipdopts || ipdopts->allocated < marker_count)
        {
-           QB_Destructor(qb);
+           SC_set_error(stmt, STMT_COUNT_FIELD_INCORRECT,
+               "The # of binded parameters < the # of parameter markers", func);
            return SQL_ERROR;
        }
        if (marker_count > 0)
        {
-           if (ipdopts->allocated >= marker_count)
+           CVT_APPEND_CHAR(qb, '(');
+           for (i = qb->proc_return, oc = 0; i < stmt->num_params; i++)
            {
-               CVT_APPEND_CHAR(qb, '(');
-               for (i = 0; i < marker_count; i++)
+               outpara = FALSE;
+               if (i < ipdopts->allocated &&
+                   SQL_PARAM_OUTPUT == ipdopts->parameters[i].paramType)
                {
-                   if (i > 0)
-                       CVT_APPEND_STR(qb, ", ");
-                   CVT_APPEND_STR(qb, pgtype_to_name(stmt, ipdopts->parameters[i].PGType));
+                   outpara = TRUE;
+                   if (discardOutput)
+                       continue;
                }
-               CVT_APPEND_CHAR(qb, ')');
-           }
-           else
-           {
-               SC_set_error(stmt, STMT_COUNT_FIELD_INCORRECT, "The # of binded parameters < the # of parameter markers");
-               SC_set_sqlstate(stmt, "07002");
-               QB_Destructor(qb);
-               return SQL_ERROR;
+               if (oc > 0)
+                   CVT_APPEND_STR(qb, ", ");
+               if (outpara)
+                   CVT_APPEND_STR(qb, "void");
+               else
+                   CVT_APPEND_STR(qb, pgtype_to_name(stmt, ipdopts->parameters[i].PGType));
+               oc++;
            }
+           CVT_APPEND_CHAR(qb, ')');
        }
        CVT_APPEND_STR(qb, " as ");
        for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++)
@@ -1888,11 +1992,7 @@ Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
            retval = inner_process_tokens(qp, qb);
            if (SQL_ERROR == retval)
            {
-               if (0 == SC_get_errornumber(stmt))
-               {
-                   SC_set_error(stmt, qb->errornumber, qb->errormsg);
-               }
-               SC_log_error(func, "", stmt);
+               QB_replace_SC_error(stmt, qb, func);
                QB_Destructor(qb);
                return retval;
            }
@@ -1900,7 +2000,7 @@ Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
        CVT_APPEND_CHAR(qb, ';');
        /* build the execute statement */
        exe_statement = malloc(30 + 2 * marker_count);
-       sprintf(exe_statement, "EXECUTE \"_PLAN%p\"", stmt);
+       sprintf(exe_statement, "EXECUTE \"%s\"", plan_name);
        if (marker_count > 0)
        {
            elen = strlen(exe_statement);
@@ -1914,21 +2014,20 @@ Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
            exe_statement[elen++] = ')';
            exe_statement[elen] = '\0';
        }
+inolog("exe_statement=%s\n", exe_statement);
        stmt->execute_statement = exe_statement;
        QP_initialize(qp, stmt);
+       SC_set_planname(stmt, plan_name);
    }
-   qb->flags = 0;
+   qb->flags &= FLGB_DISCARD_OUTPUT;
+   qb->flags |= FLGB_EXECUTE_PREPARED;
    qb->param_number = -1;
    for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++)
    {
        retval = inner_process_tokens(qp, qb);
        if (SQL_ERROR == retval)
        {
-           if (0 == SC_get_errornumber(stmt))
-           {
-               SC_set_error(stmt, qb->errornumber, qb->errormsg);
-           }
-           SC_log_error(func, "", stmt);
+           QB_replace_SC_error(stmt, qb, func);
            if (exe_statement)
            {
                free(exe_statement);
@@ -1942,13 +2041,89 @@ Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
    CVT_TERMINATE(qb);
 
    if (exe_statement)
-       SC_set_prepare_before_exec(stmt);
+       SC_set_concat_prepare_exec(stmt);
    stmt->stmt_with_params = qb->query_statement;
+   qb->query_statement = NULL;
    return SQL_SUCCESS;
 }
 
 #define        my_strchr(conn, s1,c1) pg_mbschr(conn->ccsc, s1,c1)
 
+static
+RETCODE    prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
+{
+   CSTR        func = "prep_params";
+   RETCODE     retval;
+   BOOL        ret;
+   ConnectionClass *conn = SC_get_conn(stmt);
+   QResultClass    *res;
+   char        plan_name[32];
+   int     func_cs_count = 0;
+
+inolog("prep_params\n");
+   qb->flags |= FLGB_BUILDING_PREPARE_STATEMENT;
+   for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++)
+   {
+       retval = inner_process_tokens(qp, qb);
+       if (SQL_ERROR == retval)
+       {
+           QB_replace_SC_error(stmt, qb, func);
+           QB_Destructor(qb);
+           return retval;
+       }
+   }
+   CVT_TERMINATE(qb);
+
+   retval = SQL_ERROR;
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   ENTER_INNER_CONN_CS(conn, func_cs_count);
+   if (USING_PARSE_REQUEST == SC_get_prepare_method(stmt))
+       sprintf(plan_name, "_PLAN%0x", stmt);
+   else
+       strcpy(plan_name, "");
+
+   ret = SendParseRequest(stmt, plan_name, qb->query_statement);
+   QB_Destructor(qb);
+   if (!ret)
+       goto cleanup;
+   if (!SendDescribeRequest(stmt, plan_name))
+       goto cleanup;
+   SC_set_planname(stmt, plan_name);
+   if (!(res = SendSyncAndReceive(stmt, NULL, "prepare_and_describe")))
+   {
+       SC_set_error(stmt, STMT_EXEC_ERROR, "commnication error while preapreand_describe", func);
+       CC_on_abort(conn, CONN_DEAD);
+       goto cleanup;
+   }
+   SC_set_Result(stmt, res);
+   if (QR_command_maybe_successful(res))
+       retval = SQL_SUCCESS;
+   else
+       SC_set_error(stmt, STMT_EXEC_ERROR, "Error while preparing parameters", func); 
+cleanup:
+#undef return
+   CLEANUP_FUNC_CONN_CS(func_cs_count, conn);
+   return retval;
+}
+
+RETCODE    prepareParameters(StatementClass *stmt)
+{
+   if (NOT_YET_PREPARED == stmt->prepared)
+   {
+       QueryParse  query_org, *qp;
+       QueryBuild  query_crt, *qb;
+
+inolog("prepareParameters\n");
+       qp = &query_org;
+       QP_initialize(qp, stmt);
+       qb = &query_crt;
+       if (QB_initialize(qb, qp->stmt_len, stmt, NULL) < 0)
+           return SQL_ERROR;
+       return prep_params(stmt, qp, qb);
+   }
+   return SQL_SUCCESS;
+}
+
 /*
  * This function inserts parameters into an SQL statements.
  * It will also modify a SELECT statement for use with declare/fetch cursors.
@@ -1971,7 +2146,7 @@ copy_statement_with_parameters(StatementClass *stmt, BOOL buildPrepareStatement)
 
    if (!stmt->statement)
    {
-       SC_log_error(func, "No statement string", stmt);
+       SC_set_error(stmt, STMT_INTERNAL_ERROR, "No statement string", func);
        return SQL_ERROR;
    }
 
@@ -1979,7 +2154,6 @@ copy_statement_with_parameters(StatementClass *stmt, BOOL buildPrepareStatement)
    qp = &query_org;
    QP_initialize(qp, stmt);
 
-#ifdef DRIVER_CURSOR_IMPLEMENT
    if (stmt->statement_type != STMT_TYPE_SELECT)
    {
        stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY;
@@ -1989,9 +2163,15 @@ copy_statement_with_parameters(StatementClass *stmt, BOOL buildPrepareStatement)
        stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
    else if (stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
    {
-       if (stmt->parse_status == STMT_PARSE_NONE)
-           parse_statement(stmt);
-       if (stmt->parse_status == STMT_PARSE_FATAL)
+       if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
+            0 == (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
+           stmt->options.cursor_type = SQL_CURSOR_STATIC;
+       if (SQL_CURSOR_STATIC == stmt->options.cursor_type &&
+            0 == (ci->updatable_cursors & ALLOW_STATIC_CURSORS))
+           stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
+       else if (SC_update_not_ready(stmt))
+           parse_statement(stmt, TRUE);
+       if (SC_parsed_status(stmt) == STMT_PARSE_FATAL)
        {
            stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
            if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
@@ -2007,17 +2187,20 @@ copy_statement_with_parameters(StatementClass *stmt, BOOL buildPrepareStatement)
            qp->from_pos = stmt->from_pos;
            qp->where_pos = stmt->where_pos;
        }
+inolog("type=%d concur=%d\n", 
+           stmt->options.cursor_type,
+           stmt->options.scroll_concurrency);
    }
-#else
-   stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-   if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
-       stmt->options.cursor_type = SQL_CURSOR_STATIC;
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
 
-   stmt->miscinfo = 0;
+   SC_miscinfo_clear(stmt);
    /* If the application hasn't set a cursor name, then generate one */
-   if (stmt->cursor_name[0] == '\0')
-       sprintf(stmt->cursor_name, "SQL_CUR%p", stmt);
+   if (!SC_cursor_is_valid(stmt))
+   {
+       char    curname[32];
+
+       sprintf(curname, "SQL_CUR%p", stmt);
+       STR_TO_NAME(stmt->cursor_name, curname);
+   }
    if (stmt->stmt_with_params)
    {
        free(stmt->stmt_with_params);
@@ -2029,9 +2212,11 @@ copy_statement_with_parameters(StatementClass *stmt, BOOL buildPrepareStatement)
    if (stmt->statement_type == STMT_TYPE_SELECT)
        SC_set_pre_executable(stmt);
    qb = &query_crt;
-   if (stmt->prepared || (buildPrepareStatement && stmt->options.scroll_concurrency == SQL_CONCUR_READ_ONLY))
+   qb->query_statement = NULL;
+   if (PREPARED_PERMANENTLY == stmt->prepared || (buildPrepareStatement && stmt->options.scroll_concurrency == SQL_CONCUR_READ_ONLY))
    {
-       return Prepare_and_convert(stmt, qp, qb);
+       retval = Prepare_and_convert(stmt, qp, qb);
+       return retval;
    }
 
    if (ci->disallow_premature)
@@ -2043,22 +2228,36 @@ copy_statement_with_parameters(StatementClass *stmt, BOOL buildPrepareStatement)
    new_statement = qb->query_statement;
 
    /* For selects, prepend a declare cursor to the statement */
-   if (stmt->statement_type == STMT_TYPE_SELECT)
+   if (stmt->statement_type == STMT_TYPE_SELECT && !stmt->internal)
    {
-       if (prepare_dummy_cursor || ci->drivers.use_declarefetch)
+       char    *opt_scroll = "", *opt_hold = "";
+
+       if (prepare_dummy_cursor)
        {
-           if (prepare_dummy_cursor)
+           SC_set_fetchcursor(stmt);
+           if (!CC_is_in_trans(conn) && PG_VERSION_GE(conn, 7.1))
            {
-               if (!CC_is_in_trans(conn) && PG_VERSION_GE(conn, 7.1))
-               {
-                   strcpy(new_statement, "BEGIN;");
-                   begin_first = TRUE;
-               }
+               strcpy(new_statement, "BEGIN;");
+               begin_first = TRUE;
+           }
+       }
+       else if (ci->drivers.use_declarefetch
+            /** && SQL_CONCUR_READ_ONLY == stmt->options.scroll_concurrency **/
+           )
+       {
+           SC_set_fetchcursor(stmt);
+           if (SC_is_with_hold(stmt))
+               opt_hold = " with hold";
+           if (PG_VERSION_GE(conn, 7.4))
+           {
+               if (SQL_CURSOR_FORWARD_ONLY != stmt->options.cursor_type)
+                   opt_scroll = " scroll";
            }
-           else if (ci->drivers.use_declarefetch)
-               SC_set_fetchcursor(stmt);
-           sprintf(new_statement, "%sdeclare %s cursor for ",
-                   new_statement, stmt->cursor_name);
+       }
+       if (SC_is_fetchcursor(stmt))
+       {
+           sprintf(new_statement, "%sdeclare \"%s\"%s cursor%s for ",
+               new_statement, SC_cursor_name(stmt), opt_scroll, opt_hold);
            qb->npos = strlen(new_statement);
            qp->flags |= FLGP_CURSOR_CHECK_OK;
            qp->declare_pos = qb->npos;
@@ -2076,11 +2275,7 @@ copy_statement_with_parameters(StatementClass *stmt, BOOL buildPrepareStatement)
        retval = inner_process_tokens(qp, qb);
        if (SQL_ERROR == retval)
        {
-           if (0 == SC_get_errornumber(stmt))
-           {
-               SC_set_error(stmt, qb->errornumber, qb->errormsg);
-           }
-           SC_log_error(func, "", stmt);
+           QB_replace_SC_error(stmt, qb, func);
            QB_Destructor(qb);
            return retval;
        }
@@ -2091,7 +2286,8 @@ copy_statement_with_parameters(StatementClass *stmt, BOOL buildPrepareStatement)
    new_statement = qb->query_statement;
    stmt->statement_type = qp->statement_type;
    stmt->inaccurate_result = (0 != (qb->flags & FLGB_INACCURATE_RESULT));
-   if (0 != (qp->flags & FLGP_SELECT_INTO))
+   if (0 != (qp->flags & FLGP_SELECT_INTO) ||
+       0 != (qp->flags & FLGP_MULTIPLE_STATEMENT))
    {
        SC_no_pre_executable(stmt);
        SC_no_fetchcursor(stmt);
@@ -2114,7 +2310,6 @@ copy_statement_with_parameters(StatementClass *stmt, BOOL buildPrepareStatement)
                                 NULL, 0, NULL);
    }
 
-#ifdef DRIVER_CURSOR_IMPLEMENT
    if (!stmt->load_statement && qp->from_pos >= 0)
    {
        UInt4   npos = qb->load_stmt_len;
@@ -2136,21 +2331,20 @@ copy_statement_with_parameters(StatementClass *stmt, BOOL buildPrepareStatement)
                 * 1st query is for field information
                 * 2nd query is keyset gathering
                 */
-               CVT_APPEND_STR(qb, " where ctid = '(0,0)';select ctid, oid from ");
+               CVT_APPEND_STR(qb, " where ctid = '(,)';select ctid, oid from ");
                CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, npos - qp->from_pos - 5);
            }
        }
        stmt->load_statement = malloc(npos + 1);
-       memcpy(stmt->load_statement, qb->query_statement, npos);
+       memcpy(stmt->load_statement, qb->query_statement + qp->declare_pos, npos);
        stmt->load_statement[npos] = '\0';
    }
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
    if (prepare_dummy_cursor && SC_is_pre_executable(stmt))
    {
        char        fetchstr[128];
 
-       sprintf(fetchstr, ";fetch backward in %s;close %s;",
-               stmt->cursor_name, stmt->cursor_name);
+       sprintf(fetchstr, ";fetch backward in \"%s\";close %s;",
+               SC_cursor_name(stmt), SC_cursor_name(stmt));
        if (begin_first && CC_is_in_autocommit(conn))
            strcat(fetchstr, "COMMIT;");
        CVT_APPEND_STR(qb, fetchstr);
@@ -2161,25 +2355,50 @@ copy_statement_with_parameters(StatementClass *stmt, BOOL buildPrepareStatement)
    return SQL_SUCCESS;
 }
 
+static void
+remove_declare_cursor(QueryBuild *qb, QueryParse *qp)
+{
+   memmove(qb->query_statement, qb->query_statement + qp->declare_pos, qb->npos - qp->declare_pos);
+   qb->npos -= qp->declare_pos;
+   qp->declare_pos = 0;
+}
+
 static int
 inner_process_tokens(QueryParse *qp, QueryBuild *qb)
 {
    CSTR func = "inner_process_tokens";
-   BOOL    lf_conv = qb->lf_conv;
+   BOOL    lf_conv = ((qb->flags & FLGB_CONVERT_LF) != 0);
+   const char *bestitem = NULL;
 
    RETCODE retval;
    char       oldchar;
+   StatementClass  *stmt = qb->stmt;
+   char    literal_quote = LITERAL_QUOTE, escape_in_literal = ESCAPE_IN_LITERAL, dollar_quote = '$';
 
+   if (stmt && stmt->ntab > 0)
+       bestitem = GET_NAME(stmt->ti[0]->bestitem);
    if (qp->from_pos == (Int4) qp->opos)
    {
-       CVT_APPEND_STR(qb, ", CTID, OID ");
+       CVT_APPEND_STR(qb, ", \"ctid");
+       if (bestitem)
+       {
+           CVT_APPEND_STR(qb, "\", \"");
+           CVT_APPEND_STR(qb, bestitem);
+       }
+       CVT_APPEND_STR(qb, "\" ");
    }
    else if (qp->where_pos == (Int4) qp->opos)
    {
        qb->load_stmt_len = qb->npos;
        if (0 != (qb->flags & FLGB_KEYSET_DRIVEN))
        {
-           CVT_APPEND_STR(qb, "where ctid = '(0,0)';select CTID, OID from ");
+           CVT_APPEND_STR(qb, "where ctid = '(,)';select \"ctid");
+           if (bestitem)
+           {
+               CVT_APPEND_STR(qb, "\", \"");
+               CVT_APPEND_STR(qb, bestitem);
+           }
+           CVT_APPEND_STR(qb, "\" from ");
            CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, qp->where_pos - qp->from_pos - 5);
        }
    }
@@ -2200,21 +2419,44 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
        CVT_APPEND_CHAR(qb, oldchar);
        return SQL_SUCCESS;
    }
-   else if (qp->in_quote || qp->in_dquote) /* quote/double quote check */
+   else if (qp->in_dollar_quote) /* dollar quote check */
    {
-       if (oldchar == '\\')
+       if (oldchar == dollar_quote)
+       {
+           if (strncmp(F_OldPtr(qp), qp->dollar_tag, qp->taglen) == 0)
+           {
+               CVT_APPEND_DATA(qb, F_OldPtr(qp), qp->taglen);
+               qp->opos += (qp->taglen - 1);
+               qp->in_dollar_quote = FALSE;
+               qp->in_literal = FALSE;
+               qp->dollar_tag = NULL;
+               qp->taglen = -1;
+               return SQL_SUCCESS;
+           }
+       }
+       CVT_APPEND_CHAR(qb, oldchar);
+       return SQL_SUCCESS;
+   }
+   else if (qp->in_literal) /* quote check */
+   {
+       if (oldchar == escape_in_literal)
            qp->in_escape = TRUE;
-       else if (oldchar == '\'' && qp->in_quote)
-           qp->in_quote = FALSE;
-       else if (oldchar == '\"' && qp->in_dquote)
-           qp->in_dquote = FALSE;
+       else if (oldchar == literal_quote)
+           qp->in_literal = FALSE;
+       CVT_APPEND_CHAR(qb, oldchar);
+       return SQL_SUCCESS;
+   }
+   else if (qp->in_identifier) /* double quote check */
+   {
+       if (oldchar == IDENTIFIER_QUOTE)
+           qp->in_identifier = FALSE;
        CVT_APPEND_CHAR(qb, oldchar);
        return SQL_SUCCESS;
    }
 
    /*
-    * From here we are guranteed to be in neither an escape, a quote
-    * nor a double quote.
+    * From here we are guranteed to be in neither a literal_escape,
+    * a literal_quote nor an idetifier_quote.
     */
    /* Squeeze carriage-return/linefeed pairs to linefeed only */
    else if (lf_conv && oldchar == '\r' && qp->opos + 1 < qp->stmt_len &&
@@ -2261,12 +2503,49 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
     */
    else if (oldchar != '?')
    {
-       if (oldchar == '\'')
-           qp->in_quote = TRUE;
-       else if (oldchar == '\\')
-           qp->in_escape = TRUE;
-       else if (oldchar == '\"')
-           qp->in_dquote = TRUE;
+       if (oldchar == dollar_quote)
+       {
+           char    *next_dollar;
+
+           qp->in_literal = TRUE;
+           qp->in_dollar_quote = TRUE;
+           qp->dollar_tag = F_OldPtr(qp);
+           qp->taglen = 1;
+           if (next_dollar = (strchr(F_OldPtr(qp) + 1, dollar_quote)))
+           {
+               qp->taglen = next_dollar - F_OldPtr(qp) + 1;
+               CVT_APPEND_DATA(qb, F_OldPtr(qp), qp->taglen);
+               qp->opos += (qp->taglen - 1);
+               return SQL_SUCCESS;
+           }
+       }
+       else if (oldchar == literal_quote)
+       {
+           if (!qp->in_identifier)
+               qp->in_literal = TRUE;
+       }
+       else if (oldchar == IDENTIFIER_QUOTE)
+       {
+           if (!qp->in_literal)
+               qp->in_identifier = TRUE;
+       }
+       else if (oldchar == ';')
+       {
+           if (0 != (qp->flags & FLGP_CURSOR_CHECK_OK))
+           {
+               const char *vp = &(qp->statement[qp->opos + 1]);
+
+               while (*vp && isspace(*vp))
+                   vp++;
+               if (*vp)    /* multiple statement */
+               {
+                   qp->flags |= FLGP_MULTIPLE_STATEMENT;
+                   qp->flags &= ~FLGP_CURSOR_CHECK_OK;
+                   qb->flags &= ~FLGB_KEYSET_DRIVEN;
+                   remove_declare_cursor(qb, qp);
+               }
+           }
+       }
        else
        {
            if (isspace((UCHAR) oldchar))
@@ -2284,8 +2563,7 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
                            qp->flags &= ~FLGP_CURSOR_CHECK_OK;
                            qb->flags &= ~FLGB_KEYSET_DRIVEN;
                            qp->statement_type = STMT_TYPE_CREATE;
-                           memmove(qb->query_statement, qb->query_statement + qp->declare_pos, qb->npos - qp->declare_pos);
-                           qb->npos -= qp->declare_pos;
+                           remove_declare_cursor(qb, qp);
                        }
                    }
                    else if (qp->token_len == 3)
@@ -2294,7 +2572,7 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
 
                        if (0 != (qp->flags & FLGP_CURSOR_CHECK_OK) &&
                            strnicmp(qp->token_save, "for", 3) == 0 &&
-                           table_for_update(&qp->statement[qp->opos], &endpos))
+                           table_for_update(F_OldPtr(qp), &endpos))
                        {
                            qp->flags |= FLGP_SELECT_FOR_UPDATE;
                            qp->flags &= ~FLGP_CURSOR_CHECK_OK;
@@ -2305,8 +2583,7 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
                            }
                            else
                            {
-                               memmove(qb->query_statement, qb->query_statement + qp->declare_pos, qb->npos - qp->declare_pos);
-                               qb->npos -= qp->declare_pos;
+                               remove_declare_cursor(qb, qp);
                            }
                        }
                    }
@@ -2316,7 +2593,7 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
 
                        if (STMT_TYPE_INSERT == qp->statement_type &&
                            strnicmp(qp->token_save, "()", 2) == 0 &&
-                           insert_without_target(&qp->statement[qp->opos], &endpos))
+                           insert_without_target(F_OldPtr(qp), &endpos))
                        {
                            qb->npos -= 2;
                            CVT_APPEND_STR(qb, "DEFAULT VALUES");
@@ -2345,9 +2622,145 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
    if (retval = ResolveOneParam(qb), retval < 0)
        return retval;
 
+   if (SQL_SUCCESS_WITH_INFO == retval) /* means discarding output parameter */
+   {
+   }
    return SQL_SUCCESS;
 }
 
+#define    MIN_ALC_SIZE    128
+BOOL   BuildBindRequest(StatementClass *stmt, const char *plan_name)
+{
+   CSTR func = "BuildBindRequest";
+   QueryBuild  qb;
+   UDWORD      leng, plen, netleng;
+   SQLSMALLINT     num_p, netnum_p;
+   int     i, num_params;
+   char        *bindreq;
+   ConnectionClass *conn = SC_get_conn(stmt);
+   BOOL        ret = TRUE, sockerr = FALSE, discard_output;
+   RETCODE     retval;
+   const       IPDFields *ipdopts = SC_get_IPDF(stmt);
+
+   num_params = stmt->num_params;
+   if (num_params < 0)
+   {
+       PGAPI_NumParams(stmt, &num_p);
+       num_params = num_p;
+   }
+   if (0 == num_params)  /* BindRequest Unnecessary */
+       return TRUE; 
+   if (ipdopts->allocated < num_params)
+   {
+       SC_set_error(stmt, STMT_COUNT_FIELD_INCORRECT, "The # of binded parameters < the # of parameter markers", func);
+       return FALSE;
+   }
+        plen = strlen(plan_name);
+   netleng = sizeof(netleng)   /* length fields */
+         + 2 * (plen + 1)  /* portal name/plan name */
+         + sizeof(SWORD) * (num_params + 1) /* parameter types (max) */
+         + sizeof(SWORD)   /* result format */
+         + 1;
+        if (QB_initialize(&qb, netleng > MIN_ALC_SIZE ? netleng : MIN_ALC_SIZE, stmt, NULL) < 0)
+   {
+                return FALSE;
+   }
+        qb.flags |= FLGB_BUILDING_BIND_REQUEST;
+        qb.flags |= FLGB_BINARY_AS_POSSIBLE;
+        bindreq = qb.query_statement;
+        leng = sizeof(netleng);
+        memcpy(bindreq + leng, plan_name, plen + 1); /* portal name */
+        leng += (plen + 1);
+        memcpy(bindreq + leng, plan_name, plen + 1); /* prepared plan name */
+        leng += (plen + 1);
+inolog("num_params=%d proc_return=%d\n", num_params, stmt->proc_return);
+        num_p = num_params - qb.num_discard_params;
+inolog("num_p=%d\n", num_p);
+   discard_output = (0 != (qb.flags & FLGB_DISCARD_OUTPUT));
+        netnum_p = htons(num_p);   /* Network byte order */
+   if (0 != (qb.flags & FLGB_BINARY_AS_POSSIBLE))
+   {
+       int j;
+       ParameterImplClass  *parameters = ipdopts->parameters;
+       SWORD   net_one = 1;
+       net_one = htons(net_one);
+           memcpy(bindreq + leng, &netnum_p, sizeof(netnum_p)); /* number of parameter format */
+           leng += sizeof(SWORD);
+           memset(bindreq + leng, 0, sizeof(SWORD) * num_p);  /* initialize by text format */
+       for (i = stmt->proc_return, j = 0; i < num_params; i++)
+       {
+inolog("%dth paramater type oid is %u\n", i, parameters[i].PGType);
+           if (discard_output &&
+               SQL_PARAM_OUTPUT == parameters[i].paramType)
+               continue;
+           if (PG_TYPE_BYTEA == parameters[i].PGType)
+           {
+               mylog("%dth parameter is of binary format\n", j);
+               memcpy(bindreq + leng + sizeof(SWORD) * j,
+                   &net_one, sizeof(net_one));  /* binary */
+           }
+           j++; 
+       }
+       leng += sizeof(SWORD) * num_p;
+   }
+   else
+   {
+           memset(bindreq + leng, 0, sizeof(SWORD));  /* text format */
+           leng += sizeof(SWORD);
+   }
+        memcpy(bindreq + leng, &netnum_p, sizeof(netnum_p)); /* number of params */
+        leng += sizeof(SWORD); /* must be 2 */
+        qb.npos = leng;
+        for (i = 0; i < stmt->num_params; i++)
+   {
+                retval = ResolveOneParam(&qb);
+       if (SQL_ERROR == retval)
+       {
+           QB_replace_SC_error(stmt, &qb, func);
+           ret = FALSE;
+           goto cleanup;
+       }
+   }
+
+        leng = qb.npos;
+        memset(qb.query_statement + leng, 0, sizeof(SWORD)); /* result format is text */
+        leng += sizeof(SWORD);
+inolog("bind leng=%d\n", leng);
+        netleng = htonl(leng); /* Network byte order */
+        memcpy(qb.query_statement, &netleng, sizeof(netleng));
+   if (CC_is_in_trans(conn) && !SC_accessed_db(stmt))
+   {
+       if (SQL_ERROR == SetStatementSvp(stmt))
+       {
+           SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal savepoint error in SendBindRequest", func);
+           ret = FALSE;
+           goto cleanup;
+       }
+   }
+
+        SOCK_put_char(conn->sock, 'B'); /* Bind Message */
+   if (SOCK_get_errcode(conn->sock) != 0)
+   {
+       sockerr = TRUE;
+       goto cleanup;
+   }
+        SOCK_put_n_char(conn->sock, qb.query_statement, leng);
+   if (SOCK_get_errcode(conn->sock) != 0)
+       sockerr = TRUE;
+cleanup:
+   QB_Destructor(&qb);
+
+   if (sockerr)
+   {
+       CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send D Request to backend", func);
+       CC_on_abort(conn, CONN_DEAD);
+       ret = FALSE;
+   }
+   return ret;
+}
+
+#if (ODBCVER >= 0x0300)
 static BOOL
 ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
 {
@@ -2357,6 +2770,7 @@ ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
    const UCHAR *val = (const UCHAR *) ns->val;
    BOOL    next_figure;
 
+inolog("C_NUMERIC [prec=%d scale=%d]", ns->precision, ns->scale);
    if (0 == ns->precision)
    {
        strcpy(chrform, "0");
@@ -2366,8 +2780,10 @@ ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
    {
        for (i = 0, ival = 0; i < sizeof(Int4) && prec[i] <= ns->precision; i++)
        {
+inolog("(%d)", val[i]);
            ival += (val[i] << (8 * i)); /* ns->val is little endian */
        }
+inolog(" ival=%d,%d", ival, (val[3] << 24) | (val[2] << 16) | (val[1] << 8) | val[0]);
        if (0 == ns->scale)
        {
            if (0 == ns->sign)
@@ -2384,8 +2800,9 @@ ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
            o2val = ival % div;
            if (0 == ns->sign)
                o1val *= -1;
-           sprintf(chrform, "%d.%.*d", o1val, ns->scale, o2val);
+           sprintf(chrform, "%d.%0.*d", o1val, ns->scale, o2val);
        }
+inolog(" convval=%s\n", chrform);
        return TRUE;
    }
 
@@ -2394,6 +2811,7 @@ ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
    vlen = i;
    len = 0;
    memset(calv, 0, sizeof(calv));
+inolog(" len1=%d", vlen);
    for (i = vlen - 1; i >= 0; i--)
    {
        for (j = len - 1; j >= 0; j--)
@@ -2452,6 +2870,7 @@ ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
                break;
        }
    }
+inolog(" len2=%d", len);
    newlen = 0;
    if (0 == ns->sign)
        chrform[newlen++] = '-';
@@ -2468,8 +2887,10 @@ ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
    if (0 == len)
        chrform[newlen++] = '0';
    chrform[newlen] = '\0';
+inolog(" convval(2) len=%d %s\n", newlen, chrform);
    return TRUE;
 }
+#endif /* ODBCVER */
 
 /*
  *
@@ -2497,52 +2918,120 @@ ResolveOneParam(QueryBuild *qb)
    struct tm   tm;
 #endif /* HAVE_LOCALTIME_R */
    SDWORD      used;
-   char        *buffer, *buf, *allocbuf;
+   char        *buffer, *buf, *allocbuf, *lastadd = NULL;
    Oid     lobj_oid;
    int     lobj_fd, retval;
    UInt4   offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0;
-   UInt4   current_row = qb->current_row;
-   BOOL    handling_large_object = FALSE;
+   UInt4   current_row = qb->current_row, npos;
+   BOOL    handling_large_object = FALSE, req_bind, add_quote = FALSE;
+   ParameterInfoClass  *apara;
+   ParameterImplClass  *ipara;
+   BOOL outputDiscard, valueOutput;
+
+   outputDiscard = (0 != (qb->flags & FLGB_DISCARD_OUTPUT));
+   valueOutput = (0 == (qb->flags & (FLGB_PRE_EXECUTING | FLGB_BUILDING_PREPARE_STATEMENT)));
 
+   if (qb->proc_return < 0 && qb->stmt)
+       qb->proc_return = qb->stmt->proc_return;
    /*
     * Its a '?' parameter alright
     */
    param_number = ++qb->param_number;
 
-   if (param_number >= apdopts->allocated)
+inolog("resolveOnParam %d(%d,%d)\n", param_number, ipdopts->allocated, apdopts->allocated);
+   apara = NULL;
+   ipara = NULL;
+   if (param_number < apdopts->allocated)
+       apara = apdopts->parameters + param_number;
+   if (param_number < ipdopts->allocated)
+       ipara = ipdopts->parameters + param_number;
+   if ((!apara || !ipara) && valueOutput)
    {
-       if (0 != (qb->flags & FLGB_PRE_EXECUTING))
+       qb->errormsg = "The # of binded parameters < the # of parameter markers";
+       qb->errornumber = STMT_COUNT_FIELD_INCORRECT;
+       CVT_TERMINATE(qb);  /* just in case */
+       return SQL_ERROR;
+   }
+   if (0 != (qb->flags & FLGB_EXECUTE_PREPARED)
+       && (outputDiscard || param_number < qb->proc_return)
+           )
+   {
+       while (ipara && SQL_PARAM_OUTPUT == ipara->paramType)
        {
-           CVT_APPEND_STR(qb, "NULL");
-           qb->flags |= FLGB_INACCURATE_RESULT;
-           return SQL_SUCCESS;
+           apara = NULL;
+           ipara = NULL;
+           param_number = ++qb->param_number;
+           if (param_number < apdopts->allocated)
+               apara = apdopts->parameters + param_number;
+           if (param_number < ipdopts->allocated)
+               ipara = ipdopts->parameters + param_number;
        }
-       else
+   }
+inolog("ipara=%x paramType=%d %d proc_return=%d\n", ipara, ipara ? ipara->paramType : -1, PG_VERSION_LT(conn, 8.1), qb->proc_return);
+   if (param_number < qb->proc_return)
+   {
+       if (ipara && SQL_PARAM_OUTPUT != ipara->paramType)
        {
-           qb->errormsg = "The # of binded parameters < the # of parameter markers";
-           qb->errornumber = STMT_COUNT_FIELD_INCORRECT;
+           qb->errormsg = "The function return value isn't marked as output parameter";
+           qb->errornumber = STMT_EXEC_ERROR;
            CVT_TERMINATE(qb);  /* just in case */
            return SQL_ERROR;
        }
+       return SQL_SUCCESS;
    }
-   if (SQL_PARAM_OUTPUT == ipdopts->parameters[param_number].paramType)
+   if (ipara &&
+       SQL_PARAM_OUTPUT == ipara->paramType)
    {
-       qb->errormsg = "Output parameter isn't available";
-       qb->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
-       CVT_TERMINATE(qb);  /* just in case */
-       return SQL_ERROR;
+       if (PG_VERSION_LT(conn, 8.1))
+       {
+           qb->errormsg = "Output parameter isn't available before 8.1 version";
+           qb->errornumber = STMT_INTERNAL_ERROR;
+           CVT_TERMINATE(qb);  /* just in case */
+           return SQL_ERROR;
+       }
+       if (outputDiscard)
+       {
+           for (npos = qb->npos - 1; npos >= 0 && isspace(qb->query_statement[npos]) ; npos--) ;
+           if (npos >= 0 && qb->query_statement[npos] == ',')
+           {
+               qb->npos = npos;
+               qb->query_statement[npos] = '\0';
+           }
+           return SQL_SUCCESS_WITH_INFO;
+       }
    }
 
+   if (!apara || !ipara)
+   {
+       if (0 != (qb->flags & FLGB_PRE_EXECUTING))
+       {
+           CVT_APPEND_STR(qb, "NULL");
+           qb->flags |= FLGB_INACCURATE_RESULT;
+           return SQL_SUCCESS;
+       }
+   }
    if (0 != (qb->flags & FLGB_BUILDING_PREPARE_STATEMENT))
    {
        char    pnum[16];
 
-       sprintf(pnum, "$%d", param_number + 1);
+#ifdef NOT_USED /* !! named parameter is unavailable !! */
+       if (ipara && SAFE_NAME(ipara->paramName)[0])
+       {
+           CVT_APPEND_CHAR(qb, '"'); 
+           CVT_APPEND_STR(qb, SAFE_NAME(ipara->paramName)); 
+           CVT_APPEND_CHAR(qb, '"'); 
+           CVT_APPEND_STR(qb, " = "); 
+       }
+#endif /* NOT_USED */
+       qb->dollar_number++;
+       sprintf(pnum, "$%d", qb->dollar_number);
        CVT_APPEND_STR(qb, pnum); 
        return SQL_SUCCESS;
-   } 
+   }
    /* Assign correct buffers based on data at exec param or not */
-   if (apdopts->parameters[param_number].data_at_exec)
+   if (apara->data_at_exec)
    {
        if (pdata->allocated != apdopts->allocated)
            extend_putdata_info(pdata, apdopts->allocated, TRUE);
@@ -2556,38 +3045,51 @@ ResolveOneParam(QueryBuild *qb)
        UInt4   bind_size = apdopts->param_bind_type;
        UInt4   ctypelen;
 
-       buffer = apdopts->parameters[param_number].buffer + offset;
+       buffer = apara->buffer + offset;
        if (current_row > 0)
        {
            if (bind_size > 0)
                buffer += (bind_size * current_row);
-           else if (ctypelen = ctype_length(apdopts->parameters[param_number].CType), ctypelen > 0)
+           else if (ctypelen = ctype_length(apara->CType), ctypelen > 0)
                buffer += current_row * ctypelen;
            else 
-               buffer += current_row * apdopts->parameters[param_number].buflen;
+               buffer += current_row * apara->buflen;
        }
-       if (apdopts->parameters[param_number].used)
+       if (apara->used)
        {
            UInt4   p_offset = offset;
            if (bind_size > 0)
                p_offset = offset + bind_size * current_row;
            else
                p_offset = offset + sizeof(SDWORD) * current_row;
-           used = *(SDWORD *)((char *)apdopts->parameters[param_number].used + p_offset);
+           used = *(SDWORD *)((char *)apara->used + p_offset);
        }
        else
            used = SQL_NTS;
    }   
 
-   /* Handle NULL parameter data */
-   if (used == SQL_NULL_DATA)
+   req_bind = (0 != (FLGB_BUILDING_BIND_REQUEST & qb->flags));
+   /* Handle DEFAULT_PARAM parameter data */
+   if (used == SQL_DEFAULT_PARAM)
    {
-       CVT_APPEND_STR(qb, "NULL");
        return SQL_SUCCESS;
    }
-   /* Handle DEFAULT_PARAM parameter data */
-   if (used == SQL_DEFAULT_PARAM)
+   if (req_bind)
+   {
+       npos = qb->npos;
+       qb->npos += 4;
+   }
+   /* Handle NULL parameter data */
+   if ((ipara && SQL_PARAM_OUTPUT == ipara->paramType) ||
+       used == SQL_NULL_DATA)
    {
+       if (req_bind)
+       {
+           DWORD   len = htonl(-1);
+           memcpy(qb->query_statement + npos, &len, sizeof(len));
+       }
+       else
+           CVT_APPEND_STR(qb, "NULL");
        return SQL_SUCCESS;
    }
 
@@ -2610,16 +3112,23 @@ ResolveOneParam(QueryBuild *qb)
        }
    }
 
-   param_ctype = apdopts->parameters[param_number].CType;
-   param_sqltype = ipdopts->parameters[param_number].SQLType;
-   param_pgtype = ipdopts->parameters[param_number].PGType;
+   param_ctype = apara->CType;
+   param_sqltype = ipara->SQLType;
+   param_pgtype = ipara->PGType;
 
    mylog("%s: from(fcType)=%d, to(fSqlType)=%d\n", func,
                param_ctype, param_sqltype);
 
    /* replace DEFAULT with something we can use */
    if (param_ctype == SQL_C_DEFAULT)
+   {
        param_ctype = sqltype_to_default_ctype(conn, param_sqltype);
+       if (param_ctype == SQL_C_WCHAR
+           && (CC_is_in_ansi_app(conn)
+           || conn->ms_jet /* not only but for any other ? */
+          ))
+           param_ctype =SQL_C_CHAR;
+   }
 
    allocbuf = buf = NULL;
    param_string[0] = '\0';
@@ -2643,23 +3152,14 @@ ResolveOneParam(QueryBuild *qb)
            break;
        case SQL_C_CHAR:
 #ifdef WIN_UNICODE_SUPPORT
-           switch (param_sqltype)
-           {
-               case SQL_WCHAR:
-               case SQL_WVARCHAR:
-               case SQL_WLONGVARCHAR:
-                   if (SQL_NTS == used)
-                       used = strlen(buffer);
-                   allocbuf = malloc(WCLEN * (used + 1));
-                   used = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buffer,
-                       used, (LPWSTR) allocbuf, used + 1);
-                   buf = ucs2_to_utf8((SQLWCHAR *) allocbuf, used, (UInt4 *) &used, FALSE);
-                   free(allocbuf);
-                   allocbuf = buf;
-                   break;
-               default:
-                   buf = buffer;
-           }
+           if (SQL_NTS == used)
+               used = strlen(buffer);
+           allocbuf = malloc(WCLEN * (used + 1));
+           used = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buffer,
+               used, (LPWSTR) allocbuf, used + 1);
+           buf = ucs2_to_utf8((SQLWCHAR *) allocbuf, used, &used, FALSE);
+           free(allocbuf);
+           allocbuf = buf;
 #else
            buf = buffer;
 #endif /* WIN_UNICODE_SUPPORT */
@@ -2667,9 +3167,8 @@ ResolveOneParam(QueryBuild *qb)
 
 #ifdef UNICODE_SUPPORT
        case SQL_C_WCHAR:
-            if (SQL_NTS == used)
-                used = WCLEN * wcslen((SQLWCHAR *) buffer);
-           buf = allocbuf = ucs2_to_utf8((SQLWCHAR *) buffer, used / WCLEN, (UInt4 *) &used, FALSE);
+mylog("C_WCHAR=%s(%d)\n", buffer, used);
+           buf = allocbuf = ucs2_to_utf8((SQLWCHAR *) buffer, used > 0 ? used / WCLEN : used, &used, FALSE);
            used *= WCLEN;
            break;
 #endif /* UNICODE_SUPPORT */
@@ -2687,11 +3186,12 @@ ResolveOneParam(QueryBuild *qb)
        case SQL_C_SLONG:
        case SQL_C_LONG:
            sprintf(param_string, "%d",
-                   (int) *((SDWORD *) buffer));
+                   *((SDWORD *) buffer));
            break;
 
-#ifdef ODBCINT64
+#if (ODBCVER >= 0x0300) && defined(ODBCINT64)
        case SQL_C_SBIGINT:
+       case SQL_BIGINT: /* Is this needed ? */
            sprintf(param_string, FORMATI64,
                    *((SQLBIGINT *) buffer));
            break;
@@ -2705,7 +3205,7 @@ ResolveOneParam(QueryBuild *qb)
        case SQL_C_SSHORT:
        case SQL_C_SHORT:
            sprintf(param_string, "%d",
-                   *((SWORD *) buffer));
+                   *((SQLSMALLINT *) buffer));
            break;
 
        case SQL_C_STINYINT:
@@ -2716,12 +3216,12 @@ ResolveOneParam(QueryBuild *qb)
 
        case SQL_C_ULONG:
            sprintf(param_string, "%u",
-                   (unsigned int) *((UDWORD *) buffer));
+                   *((UDWORD *) buffer));
            break;
 
        case SQL_C_USHORT:
            sprintf(param_string, "%u",
-                   *((UWORD *) buffer));
+                   *((SQLUSMALLINT *) buffer));
            break;
 
        case SQL_C_UTINYINT:
@@ -2738,7 +3238,9 @@ ResolveOneParam(QueryBuild *qb)
            }
 
        case SQL_C_DATE:
+#if (ODBCVER >= 0x0300)
        case SQL_C_TYPE_DATE:       /* 91 */
+#endif
            {
                DATE_STRUCT *ds = (DATE_STRUCT *) buffer;
 
@@ -2750,7 +3252,9 @@ ResolveOneParam(QueryBuild *qb)
            }
 
        case SQL_C_TIME:
+#if (ODBCVER >= 0x0300)
        case SQL_C_TYPE_TIME:       /* 92 */
+#endif
            {
                TIME_STRUCT *ts = (TIME_STRUCT *) buffer;
 
@@ -2762,7 +3266,9 @@ ResolveOneParam(QueryBuild *qb)
            }
 
        case SQL_C_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
        case SQL_C_TYPE_TIMESTAMP:  /* 93 */
+#endif
            {
                TIMESTAMP_STRUCT *tss = (TIMESTAMP_STRUCT *) buffer;
 
@@ -2779,9 +3285,11 @@ ResolveOneParam(QueryBuild *qb)
                break;
 
            }
+#if (ODBCVER >= 0x0300)
        case SQL_C_NUMERIC:
            if (ResolveNumericParam((SQL_NUMERIC_STRUCT *) buffer, param_string))
                break;
+#endif
        default:
            /* error */
            qb->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters";
@@ -2795,6 +3303,19 @@ ResolveOneParam(QueryBuild *qb)
     * the desired output format (sqltype)
     */
 
+   switch (param_sqltype)
+   {
+       case SQL_INTEGER:
+       case SQL_SMALLINT:
+           break;
+       default:
+           if (!req_bind)
+           {
+               CVT_APPEND_CHAR(qb, LITERAL_QUOTE);
+               add_quote = TRUE;
+           }
+           break;
+   }
    switch (param_sqltype)
    {
        case SQL_CHAR:
@@ -2806,8 +3327,6 @@ ResolveOneParam(QueryBuild *qb)
        case SQL_WLONGVARCHAR:
 #endif /* UNICODE_SUPPORT */
 
-           CVT_APPEND_CHAR(qb, '\'');  /* Open Quote */
-
            /* it was a SQL_C_CHAR */
            if (buf)
                CVT_SPECIAL_CHARS(qb, buf, used);
@@ -2824,39 +3343,42 @@ ResolveOneParam(QueryBuild *qb)
 
                CVT_APPEND_STR(qb, tmp);
            }
-
-           CVT_APPEND_CHAR(qb, '\'');  /* Close Quote */
-
            break;
 
        case SQL_DATE:
+#if (ODBCVER >= 0x0300)
        case SQL_TYPE_DATE: /* 91 */
+#endif
            if (buf)
            {               /* copy char data to time */
                my_strcpy(cbuf, sizeof(cbuf), buf, used);
                parse_datetime(cbuf, &st);
            }
 
-           sprintf(tmp, "'%.4d-%.2d-%.2d'::date", st.y, st.m, st.d);
-
+           sprintf(tmp, "%.4d-%.2d-%.2d", st.y, st.m, st.d);
+           lastadd = "::date";
            CVT_APPEND_STR(qb, tmp);
            break;
 
        case SQL_TIME:
+#if (ODBCVER >= 0x0300)
        case SQL_TYPE_TIME: /* 92 */
+#endif
            if (buf)
            {               /* copy char data to time */
                my_strcpy(cbuf, sizeof(cbuf), buf, used);
                parse_datetime(cbuf, &st);
            }
 
-           sprintf(tmp, "'%.2d:%.2d:%.2d'::time", st.hh, st.mm, st.ss);
-
+           sprintf(tmp, "%.2d:%.2d:%.2d", st.hh, st.mm, st.ss);
+           lastadd = "::time";
            CVT_APPEND_STR(qb, tmp);
            break;
 
        case SQL_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
        case SQL_TYPE_TIMESTAMP:    /* 93 */
+#endif
 
            if (buf)
            {
@@ -2865,14 +3387,12 @@ ResolveOneParam(QueryBuild *qb)
            }
 
            /*
-            * sprintf(tmp, "'%.4d-%.2d-%.2d %.2d:%.2d:%.2d'", st.y,
+            * sprintf(tmp, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", st.y,
             * st.m, st.d, st.hh, st.mm, st.ss);
             */
-           tmp[0] = '\'';
            /* Time zone stuff is unreliable */
-           stime2timestamp(&st, tmp + 1, USE_ZONE, PG_VERSION_GE(conn, 7.2));
-           strcat(tmp, "'::timestamp");
-
+           stime2timestamp(&st, tmp, USE_ZONE, PG_VERSION_GE(conn, 7.2));
+           lastadd = "::timestamp";
            CVT_APPEND_STR(qb, tmp);
 
            break;
@@ -2906,27 +3426,32 @@ ResolveOneParam(QueryBuild *qb)
            }
            if (param_pgtype == PG_TYPE_BYTEA)
            {
-               /* non-ascii characters should be
-                * converted to octal
-                */
-               CVT_APPEND_CHAR(qb, '\'');  /* Open Quote */
-
-               mylog("SQL_VARBINARY: about to call convert_to_pgbinary, used = %d\n", used);
-
-               CVT_APPEND_BINARY(qb, buf, used);
-
-               CVT_APPEND_CHAR(qb, '\'');  /* Close Quote */
+               if (0 != (qb->flags & FLGB_BINARY_AS_POSSIBLE))
+               {
+                   mylog("sending binary data leng=%d\n", used);
+                   CVT_APPEND_DATA(qb, buf, used);
+               }
+               else
+               {
+                   /* non-ascii characters should be
+                    * converted to octal
+                    */
+                   mylog("SQL_VARBINARY: about to call convert_to_pgbinary, used = %d\n", used);
 
+                   CVT_APPEND_BINARY(qb, buf, used);
+               }
                break;
            }
-           if (param_pgtype != conn->lobj_type)
+           if (PG_TYPE_OID == param_pgtype && conn->lo_is_domain)
+               ;
+           else if (param_pgtype != conn->lobj_type)
            {
                qb->errormsg = "Could not convert binary other than LO type";
                qb->errornumber = STMT_EXEC_ERROR;
                return SQL_ERROR;
            }
 
-           if (apdopts->parameters[param_number].data_at_exec)
+           if (apara->data_at_exec)
                lobj_oid = pdata->pdata[param_number].lobj_oid;
            else
            {
@@ -2942,7 +3467,7 @@ ResolveOneParam(QueryBuild *qb)
                }
 
                /* store the oid */
-               lobj_oid = lo_creat(conn->pgconn, INV_READ | INV_WRITE);
+               lobj_oid = odbc_lo_creat(conn, INV_READ | INV_WRITE);
                if (lobj_oid == 0)
                {
                    qb->errornumber = STMT_EXEC_ERROR;
@@ -2951,17 +3476,17 @@ ResolveOneParam(QueryBuild *qb)
                }
 
                /* store the fd */
-               lobj_fd = lo_open(conn->pgconn, lobj_oid, INV_WRITE);
-
+               lobj_fd = odbc_lo_open(conn, lobj_oid, INV_WRITE);
                if (lobj_fd < 0)
                {
                    qb->errornumber = STMT_EXEC_ERROR;
                    qb->errormsg = "Couldnt open (in-line) large object for writing.";
                    return SQL_ERROR;
                }
-       
-               retval = lo_write(conn->pgconn, lobj_fd, buffer, used);
-               lo_close(conn->pgconn, lobj_fd);
+
+               retval = odbc_lo_write(conn, lobj_fd, buffer, used);
+
+               odbc_lo_close(conn, lobj_fd);
 
                /* commit transaction if needed */
                if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
@@ -2980,7 +3505,8 @@ ResolveOneParam(QueryBuild *qb)
             * parameter marker -- the data has already been sent to
             * the large object
             */
-           sprintf(param_string, "'%d'::lo", lobj_oid);
+           sprintf(param_string, "%d", lobj_oid);
+           lastadd = "::lo";
            CVT_APPEND_STR(qb, param_string);
 
            break;
@@ -2994,38 +3520,26 @@ ResolveOneParam(QueryBuild *qb)
        case SQL_REAL:
            if (buf)
                my_strcpy(param_string, sizeof(param_string), buf, used);
-           sprintf(tmp, "'%s'::float4", param_string);
-           CVT_APPEND_STR(qb, tmp);
+           lastadd = "::float4";
+           CVT_APPEND_STR(qb, param_string);
            break;
        case SQL_FLOAT:
        case SQL_DOUBLE:
            if (buf)
                my_strcpy(param_string, sizeof(param_string), buf, used);
-           sprintf(tmp, "'%s'::float8", param_string);
-           CVT_APPEND_STR(qb, tmp);
+           lastadd = "::float8";
+           CVT_APPEND_STR(qb, param_string);
            break;
        case SQL_NUMERIC:
            if (buf)
            {
-               cbuf[0] = '\'';
-               my_strcpy(cbuf + 1, sizeof(cbuf) - 3, buf, used);   /* 3 = 1('\'') +
-                                                                   * strlen("'")
-                                                                   * + 1('\0') */
-               strcat(cbuf, "'");
+               my_strcpy(cbuf, sizeof(cbuf), buf, used);
            }
            else
-               sprintf(cbuf, "'%s'", param_string);
+               sprintf(cbuf, "%s", param_string);
            CVT_APPEND_STR(qb, cbuf);
            break;
-
        default:            /* a numeric type or SQL_BIT */
-           if (param_sqltype == SQL_BIT)
-               CVT_APPEND_CHAR(qb, '\'');      /* Open Quote */
-
-           if (param_sqltype == SQL_SMALLINT)
-           {
-               CVT_APPEND_STR(qb, "(");
-           }
 
            if (buf)
            {
@@ -3043,19 +3557,22 @@ ResolveOneParam(QueryBuild *qb)
            else
                CVT_APPEND_STR(qb, param_string);
 
-           if (param_sqltype == SQL_SMALLINT)
-           {
-               /* needs cast because there is no automatic downcast from int4 constants */
-               CVT_APPEND_STR(qb, ")::int2");
-           }
-
-           if (param_sqltype == SQL_BIT)
-               CVT_APPEND_CHAR(qb, '\'');      /* Close Quote */
-
            break;
    }
+   if (add_quote)
+   {
+       CVT_APPEND_CHAR(qb, LITERAL_QUOTE);
+       if (lastadd)
+           CVT_APPEND_STR(qb, lastadd);
+   }
    if (allocbuf)
        free(allocbuf);
+   if (req_bind)
+   {
+       SDWORD  slen = htonl(qb->npos - npos - 4);
+
+       memcpy(qb->query_statement + npos, &slen, sizeof(slen));
+   }
    return SQL_SUCCESS;
 }
 
@@ -3103,7 +3620,7 @@ processParameters(QueryParse *qp, QueryBuild *qb,
            return retval;
        if (ENCODE_STATUS(qp->encstr) != 0)
            continue;
-       if (qp->in_dquote || qp->in_quote || qp->in_escape)
+       if (qp->in_identifier || qp->in_literal || qp->in_escape)
            continue;
 
        switch (F_OldChar(qp))
@@ -3206,6 +3723,9 @@ convert_escape(QueryParse *qp, QueryBuild *qb)
        if (F_OldChar(qp) == '?')
        {
            qb->param_number++;
+           qb->proc_return = 1;
+           if (qb->stmt)
+               qb->stmt->proc_return = 1;
            while (isspace((UCHAR) qp->statement[++qp->opos]));
            if (F_OldChar(qp) != '=')
            {
@@ -3221,7 +3741,10 @@ convert_escape(QueryParse *qp, QueryBuild *qb)
            return SQL_SUCCESS;
        }
        qp->opos += lit_call_len;
-       CVT_APPEND_STR(qb, "SELECT ");
+       if (qb->num_io_params > 1)
+           CVT_APPEND_STR(qb, "SELECT * FROM");
+       else
+           CVT_APPEND_STR(qb, "SELECT");
        if (my_strchr(conn, F_OldPtr(qp), '('))
            qp->proc_no_param = FALSE;
        return SQL_SUCCESS;
@@ -3445,7 +3968,7 @@ parse_datetime(const char *buf, SIMPLE_TIME *st)
    /* escape sequence ? */
    if (buf[0] == '{')
    {
-       while (*(++buf) && *buf != '\'');
+       while (*(++buf) && *buf != LITERAL_QUOTE);
        if (!(*buf))
            return FALSE;
        buf++;
@@ -3547,13 +4070,15 @@ convert_linefeeds(const char *si, char *dst, size_t max, BOOL convlf, BOOL *chan
  * Plus, escape any special characters.
  */
 int
-convert_special_chars(const char *si, char *dst, int used, BOOL convlf, int ccsc)
+convert_special_chars(const char *si, char *dst, int used, UInt4 flags, int ccsc)
 {
    size_t      i = 0,
                out = 0,
                max;
-   char       *p = NULL;
+   char       *p = NULL, literal_quote = LITERAL_QUOTE;
    encoded_str encstr;
+   BOOL    convlf = (0 != (flags & FLGB_CONVERT_LF)),
+       escadd = (0 == (flags & FLGB_BUILDING_BIND_REQUEST));
 
    if (used == SQL_NTS)
        max = strlen(si);
@@ -3578,10 +4103,10 @@ convert_special_chars(const char *si, char *dst, int used, BOOL convlf, int ccsc
        }
        if (convlf && si[i] == '\r' && si[i + 1] == '\n')
            continue;
-       else if (si[i] == '\'' || si[i] == '\\')
+       else if (escadd && (si[i] == literal_quote || si[i] == ESCAPE_IN_LITERAL))
        {
            if (p)
-               p[out++] = '\\';
+               p[out++] = ESCAPE_IN_LITERAL;
            else
                out++;
        }
@@ -3621,29 +4146,6 @@ conv_from_octal(const UCHAR *s)
 }
 
 
-static unsigned int
-conv_from_hex(const UCHAR *s)
-{
-   int         i,
-               y = 0,
-               val;
-
-   for (i = 1; i <= 2; i++)
-   {
-       if (s[i] >= 'a' && s[i] <= 'f')
-           val = s[i] - 'a' + 10;
-       else if (s[i] >= 'A' && s[i] <= 'F')
-           val = s[i] - 'A' + 10;
-       else
-           val = s[i] - '0';
-
-       y += val << (4 * (2 - i));
-   }
-
-   return y;
-}
-
-
 /* convert octal escapes to bytes */
 int
 convert_from_pgbinary(const UCHAR *value, UCHAR *rgbValue, int cbValueMax)
@@ -3655,9 +4157,9 @@ convert_from_pgbinary(const UCHAR *value, UCHAR *rgbValue, int cbValueMax)
 
    for (i = 0; i < ilen;)
    {
-       if (value[i] == '\\')
+       if (value[i] == ESCAPE_IN_LITERAL)
        {
-           if (value[i + 1] == '\\')
+           if (value[i + 1] == BYTEA_ESCAPE_CHAR)
            {
                if (rgbValue)
                    rgbValue[o] = value[i];
@@ -3695,8 +4197,8 @@ conv_to_octal(UCHAR val, char *octal)
 {
    int         i;
 
-   octal[0] = '\\';
-   octal[1] = '\\';
+   octal[0] = ESCAPE_IN_LITERAL;
+   octal[1] = BYTEA_ESCAPE_CHAR;
    octal[5] = '\0';
 
    for (i = 4; i > 1; i--)
@@ -3709,12 +4211,31 @@ conv_to_octal(UCHAR val, char *octal)
 }
 
 
+static char *
+conv_to_octal2(UCHAR val, char *octal)
+{
+   int         i;
+
+   octal[0] = BYTEA_ESCAPE_CHAR;
+   octal[4] = '\0';
+
+   for (i = 3; i > 0; i--)
+   {
+       octal[i] = (val & 7) + '0';
+       val >>= 3;
+   }
+
+   return octal;
+}
+
+
 /* convert non-ascii bytes to octal escape sequences */
 int
-convert_to_pgbinary(const UCHAR *in, char *out, int len)
+convert_to_pgbinary(const UCHAR *in, char *out, int len, UInt4 flags)
 {
    int         i,
                o = 0;
+   BOOL    esc_double = (0 == (flags & FLGB_BUILDING_BIND_REQUEST));
 
    for (i = 0; i < len; i++)
    {
@@ -3723,8 +4244,16 @@ convert_to_pgbinary(const UCHAR *in, char *out, int len)
            out[o++] = in[i];
        else
        {
-           conv_to_octal(in[i], &out[o]);
-           o += 5;
+           if (esc_double)
+           {
+               conv_to_octal(in[i], &out[o]);
+               o += 5;
+           }
+           else
+           {
+               conv_to_octal2(in[i], &out[o]);
+               o += 4;
+           }
        }
    }
 
@@ -3734,56 +4263,6 @@ convert_to_pgbinary(const UCHAR *in, char *out, int len)
 }
 
 
-void
-encode(const char *in, char *out)
-{
-   unsigned int i,
-               ilen = strlen(in),
-               o = 0;
-
-   for (i = 0; i < ilen; i++)
-   {
-       if (in[i] == '+')
-       {
-           sprintf(&out[o], "%%2B");
-           o += 3;
-       }
-       else if (isspace((UCHAR) in[i]))
-           out[o++] = '+';
-       else if (!isalnum((UCHAR) in[i]))
-       {
-           sprintf(&out[o], "%%%02x", (UCHAR) in[i]);
-           o += 3;
-       }
-       else
-           out[o++] = in[i];
-   }
-   out[o++] = '\0';
-}
-
-
-void
-decode(const char *in, char *out)
-{
-   unsigned int i,
-               ilen = strlen(in),
-               o = 0;
-
-   for (i = 0; i < ilen; i++)
-   {
-       if (in[i] == '+')
-           out[o++] = ' ';
-       else if (in[i] == '%')
-       {
-           sprintf(&out[o++], "%c", conv_from_hex(&in[i]));
-           i += 2;
-       }
-       else
-           out[o++] = in[i];
-   }
-   out[o++] = '\0';
-}
-
 static const char *hextbl = "0123456789ABCDEF";
 static int
 pg_bin2hex(UCHAR *src, UCHAR *dst, int length)
@@ -3875,6 +4354,7 @@ int
 convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
           SDWORD cbValueMax, SDWORD *pcbValue)
 {
+   CSTR    func = "convert_lo";
    Oid         oid;
    int         retval,
                result,
@@ -3894,7 +4374,7 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
            factor = 1;
            break;
        default:
-           SC_set_error(stmt, STMT_EXEC_ERROR, "Could not convert lo to the c-type");
+           SC_set_error(stmt, STMT_EXEC_ERROR, "Could not convert lo to the c-type", func);
            return COPY_GENERAL_ERROR;
    }
    /* If using SQLGetData, then current_col will be set */
@@ -3916,32 +4396,29 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
        {
            if (!CC_begin(conn))
            {
-               SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction");
+               SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction", func);
                return COPY_GENERAL_ERROR;
            }
        }
 
        oid = ATOI32U(value);
-       stmt->lobj_fd = lo_open(conn->pgconn, oid, INV_READ);
-
+       stmt->lobj_fd = odbc_lo_open(conn, oid, INV_READ);
        if (stmt->lobj_fd < 0)
        {
-           SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open large object for reading.");
+           SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open large object for reading.", func);
            return COPY_GENERAL_ERROR;
        }
 
        /* Get the size */
-       retval = lo_lseek(conn->pgconn, stmt->lobj_fd, 0L, SEEK_END);
-
+       retval = odbc_lo_lseek(conn, stmt->lobj_fd, 0L, SEEK_END);
        if (retval >= 0)
        {
-           left = lo_tell(conn->pgconn, stmt->lobj_fd);
-
+           left = odbc_lo_tell(conn, stmt->lobj_fd);
            if (gdata)
                gdata->data_left = left;
 
            /* return to beginning */
-           lo_lseek(conn->pgconn, stmt->lobj_fd, 0L, SEEK_SET);
+           odbc_lo_lseek(conn, stmt->lobj_fd, 0L, SEEK_SET);
        }
    }
    mylog("lo data left = %d\n", left);
@@ -3951,29 +4428,28 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
 
    if (stmt->lobj_fd < 0)
    {
-       SC_set_error(stmt, STMT_EXEC_ERROR, "Large object FD undefined for multiple read.");
+       SC_set_error(stmt, STMT_EXEC_ERROR, "Large object FD undefined for multiple read.", func);
        return COPY_GENERAL_ERROR;
    }
 
-   retval = lo_read(conn->pgconn, stmt->lobj_fd, (char *) rgbValue, factor > 1 ? (cbValueMax - 1) / factor : cbValueMax);
-
+   retval = odbc_lo_read(conn, stmt->lobj_fd, (char *) rgbValue, factor > 1 ? (cbValueMax - 1) / factor : cbValueMax);
    if (retval < 0)
    {
-       lo_close(conn->pgconn, stmt->lobj_fd);
+       odbc_lo_close(conn, stmt->lobj_fd);
 
        /* commit transaction if needed */
        if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
        {
            if (!CC_commit(conn))
            {
-               SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction");
+               SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction", func);
                return COPY_GENERAL_ERROR;
            }
        }
 
        stmt->lobj_fd = -1;
 
-       SC_set_error(stmt, STMT_EXEC_ERROR, "Error reading from large object.");
+       SC_set_error(stmt, STMT_EXEC_ERROR, "Error reading from large object.", func);
        return COPY_GENERAL_ERROR;
    }
 
@@ -3992,14 +4468,14 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
 
    if (!gdata || gdata->data_left == 0)
    {
-       lo_close(conn->pgconn, stmt->lobj_fd);
+       odbc_lo_close(conn, stmt->lobj_fd);
 
        /* commit transaction if needed */
        if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
        {
            if (!CC_commit(conn))
            {
-               SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction");
+               SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction", func);
                return COPY_GENERAL_ERROR;
            }
        }
index 5788bbcfe7c9dd1dc07b516560d8ec8b75a87812..9c0c81d903dd424b4416770e6b84db6796fb5ecc 100644 (file)
--- a/convert.h
+++ b/convert.h
@@ -43,14 +43,12 @@ int     copy_statement_with_parameters(StatementClass *stmt, BOOL);
 BOOL       convert_money(const char *s, char *sout, size_t soutmax);
 char       parse_datetime(const char *buf, SIMPLE_TIME *st);
 int            convert_linefeeds(const char *s, char *dst, size_t max, BOOL convlf, BOOL *changed);
-int            convert_special_chars(const char *si, char *dst, int used, BOOL convlf,int ccsc);
+int        convert_special_chars(const char *si, char *dst, int used, UInt4 flags,int ccsc);
 
 int            convert_pgbinary_to_char(const char *value, char *rgbValue, int cbValueMax);
 int            convert_from_pgbinary(const UCHAR *value, UCHAR *rgbValue, int cbValueMax);
-int            convert_to_pgbinary(const UCHAR *in, char *out, int len);
+int        convert_to_pgbinary(const UCHAR *in, char *out, int len, UInt4 flags);
 int        pg_hex2bin(const UCHAR *in, UCHAR *out, int len);
-void       encode(const char *in, char *out);
-void       decode(const char *in, char *out);
 int convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
           SDWORD cbValueMax, SDWORD *pcbValue);
 
index 7124ecb5cc3325882c34a0024199dee73408295e..3ae28dc9c36d7d25a1a273ceab443bae5245bff0 100644 (file)
 #include "pgapifunc.h"
 
 
+void   TI_Constructor(TABLE_INFO *self, const ConnectionClass *conn)
+{
+   memset(self, 0, sizeof(TABLE_INFO));
+   TI_set_updatable(self);
+   if (PG_VERSION_LT(conn, 7.2))
+   {
+       char    qual[32];
+
+       STR_TO_NAME(self->bestitem, OID_NAME);
+       sprintf(qual, "\"oid\" = %%u");
+       STR_TO_NAME(self->bestqual, qual);
+       TI_set_hasoids(self);
+       TI_set_hasoids_checked(self);
+   }
+}
+void   TI_Destructor(TABLE_INFO **ti, int count)
+{
+   int i;
+
+inolog("TI_Destructor count=%d\n", count);
+   if (ti)
+   {
+       for (i = 0; i < count; i++)
+       {
+           if (ti[i])
+           {
+               NULL_THE_NAME(ti[i]->schema_name);
+               NULL_THE_NAME(ti[i]->table_name);
+               NULL_THE_NAME(ti[i]->table_alias);
+               NULL_THE_NAME(ti[i]->bestitem);
+               NULL_THE_NAME(ti[i]->bestqual);
+               free(ti[i]);
+               ti[i] = NULL;
+           }
+       }
+   }
+}
+void   FI_Constructor(FIELD_INFO *self, BOOL reuse)
+{
+inolog("FI_Constructor reuse=%d\n", reuse);
+   if (reuse)
+       FI_Destructor(&self, 1, FALSE);
+   memset(self, 0, sizeof(FIELD_INFO));
+}
+void   FI_Destructor(FIELD_INFO **fi, int count, BOOL freeFI)
+{
+   int i;
+
+inolog("FI_Destructor count=%d\n", count);
+   if (fi)
+   {
+       for (i = 0; i < count; i++)
+       {
+           if (fi[i])
+           {
+               NULL_THE_NAME(fi[i]->column_name);
+               NULL_THE_NAME(fi[i]->column_alias);
+               NULL_THE_NAME(fi[i]->schema_name);
+               NULL_THE_NAME(fi[i]->before_dot);
+               if (freeFI)
+               {
+                   free(fi[i]);
+                   fi[i] = NULL;
+               }
+           }
+       }
+       if (freeFI)
+           free(fi);
+   }
+}
+
 void   DC_Constructor(DescriptorClass *self, BOOL embedded, StatementClass *stmt)
 {
    memset(self, 0, sizeof(DescriptorClass));
@@ -37,6 +108,7 @@ inolog("ARDFields_free %x bookmark=%x", self, self->bookmark);
        free(self->bookmark);
        self->bookmark = NULL;
    }
+inolog(" hey");
    /*
     * the memory pointed to by the bindings is not deallocated by the
     * driver but by the application that uses that driver, so we don't
@@ -61,20 +133,10 @@ static void IRDFields_free(IRDFields * self)
    /* Free the parsed field information */
    if (self->fi)
    {
-       int         i;
-
-       for (i = 0; i < (int) self->nfields; i++)
-       {
-           if (self->fi[i])
-           {
-               if (self->fi[i]->schema)
-                   free(self->fi[i]->schema);
-               free(self->fi[i]);
-           }
-       }
-       free(self->fi);
+       FI_Destructor(self->fi, self->nfields, TRUE);
        self->fi = NULL;
    }
+   self->nfields = 0;
 }
 
 static void IPDFields_free(IPDFields * self)
@@ -151,7 +213,9 @@ void
 InitializeARDFields(ARDFields *opt)
 {
    memset(opt, 0, sizeof(ARDFields));
+#if (ODBCVER >= 0x0300)
    opt->size_of_rowset = 1;
+#endif /* ODBCVER */
    opt->bind_size = 0;     /* default is to bind by column */
    opt->size_of_rowset_odbc2 = 1;
 }
@@ -177,12 +241,14 @@ BindInfoClass *ARD_AllocBookmark(ARDFields *ardopts)
    return ardopts->bookmark;
 }
 
+#if (ODBCVER >= 0x0300)
+
 #define    DESC_INCREMENT  10
 char CC_add_descriptor(ConnectionClass *self, DescriptorClass *desc)
 {
    int i;
 
-   mylog("CC_add_descriptor: self=%u, desc=%u\n", self, desc);
+   mylog("CC_add_descriptor: self=%x, desc=%x\n", self, desc);
 
    for (i = 0; i < self->num_descs; i++)
    {
@@ -228,13 +294,13 @@ RETCODE SQL_API PGAPI_AllocDesc(HDBC ConnectionHandle,
        else
        {
            free(desc);
-           CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of descriptors exceeded");
+           CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of descriptors exceeded", func);
            ret = SQL_ERROR;
        } 
    }
    else
    {
-       CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "No more memory ti allocate a further descriptor");
+       CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "No more memory ti allocate a further descriptor",func);
        ret = SQL_ERROR;
    }
    return ret;
@@ -365,7 +431,7 @@ PGAPI_CopyDesc(SQLHDESC SourceDescHandle,
    }
    if (target->type_defined)
    {
-inolog("CopyDesc source type=%d -> target type=%d\n", src->desc_type, target->desc_type);
+inolog("source type=%d -> target type=%d\n", src->desc_type, target->desc_type);
        if (SQL_ATTR_IMP_ROW_DESC == target->desc_type)
        {
            mylog("can't modify IRD\n");
@@ -475,6 +541,8 @@ static struct
 }  Descriptor_sqlstate[] =
 
 {
+   { DESC_ERROR_IN_ROW, "01S01", "01S01" },
+   { DESC_OPTION_VALUE_CHANGED, "01S02", "01S02" },
    { DESC_OK,  "00000", "00000" }, /* OK */
    { DESC_EXEC_ERROR, "HY000", "S1000" }, /* also a general error */
    { DESC_STATUS_ERROR, "HY010", "S1010" },
@@ -492,7 +560,6 @@ static struct
    { DESC_INVALID_COLUMN_NUMBER_ERROR, "07009", "S1002" },
    { DESC_RESTRICTED_DATA_TYPE_ERROR, "07006", "07006" },
    { DESC_INVALID_CURSOR_STATE_ERROR, "07005", "24000" },
-   { DESC_OPTION_VALUE_CHANGED, "01S02", "01S02" },
    { DESC_CREATE_TABLE_ERROR, "42S01", "S0001" }, /* table already exists */
    { DESC_NO_CURSOR_NAME, "S1015", "S1015" },
    { DESC_INVALID_CURSOR_NAME, "34000", "34000" },
@@ -506,7 +573,6 @@ static struct
    { DESC_BAD_ERROR, "08S01", "08S01" }, /* communication link failure */
    { DESC_INVALID_OPTION_IDENTIFIER, "HY092", "HY092" },
    { DESC_RETURN_NULL_WITHOUT_INDICATOR, "22002", "22002" },
-   { DESC_ERROR_IN_ROW, "01S01", "01S01" },
    { DESC_INVALID_DESCRIPTOR_IDENTIFIER, "HY091", "HY091" },
    { DESC_OPTION_NOT_FOR_THE_DRIVER, "HYC00", "HYC00" },
    { DESC_FETCH_OUT_OF_RANGE, "HY106", "S1106" },
@@ -515,10 +581,12 @@ static struct
 
 static PG_ErrorInfo    *DC_create_errorinfo(const DescriptorClass *desc)
 {
+   CSTR func = "DC_create_erroinfo";
    PG_ErrorInfo    *error;
    ConnectionClass *conn;
    EnvironmentClass    *env;
    Int4    errornum;
+   BOOL        env_is_odbc3 = TRUE;
 
    if (desc->pgerror)
        return desc->pgerror;
@@ -527,11 +595,13 @@ static    PG_ErrorInfo    *DC_create_errorinfo(const DescriptorClass *desc)
    if (!error)
        return error;
    conn = DC_get_conn(desc);
-   env = (EnvironmentClass *) conn->henv;
+   if (conn && (env = (EnvironmentClass *) conn->henv))
+       env_is_odbc3 = EN_is_odbc3(env);
+   errornum -= LOWEST_DESC_ERROR;
    if (errornum < 0 ||
        errornum >= sizeof(Descriptor_sqlstate) / sizeof(Descriptor_sqlstate[0]))
-       errornum = 1;
-   strcpy(error->sqlstate, EN_is_odbc3(env) ? Descriptor_sqlstate[errornum].ver3str : Descriptor_sqlstate[errornum].ver2str); 
+       errornum = 1 - LOWEST_DESC_ERROR;
+   strcpy(error->sqlstate, env_is_odbc3 ? Descriptor_sqlstate[errornum].ver3str : Descriptor_sqlstate[errornum].ver2str); 
         return error;
 }
 void
@@ -547,21 +617,24 @@ DC_log_error(const char *func, const char *desc, const DescriptorClass *self)
 
 /*     Returns the next SQL error information. */
 RETCODE        SQL_API
-PGAPI_DescError(SQLHDESC hdesc, 
-       SWORD RecNumber,
-       SQLCHAR *szSqlState, 
-       SQLINTEGER *pfNativeError,
-       SQLCHAR *szErrorMsg, 
-       SQLSMALLINT cbErrorMsgMax,
-       SQLSMALLINT *pcbErrorMsg, 
-       UWORD flag)
+PGAPI_DescError(   SQLHDESC hdesc,
+           SQLSMALLINT RecNumber,
+           SQLCHAR FAR * szSqlState,
+           SQLINTEGER FAR * pfNativeError,
+           SQLCHAR FAR * szErrorMsg,
+           SQLSMALLINT cbErrorMsgMax,
+           SQLSMALLINT FAR * pcbErrorMsg,
+           UWORD flag)
 {
+   CSTR func = "PGAPI_DescError";
    /* CC: return an error of a hdesc  */
    DescriptorClass *desc = (DescriptorClass *) hdesc;
 
+   mylog("%s RecN=%d\n", func);
    desc->pgerror = DC_create_errorinfo(desc);
-   return ER_ReturnError(desc->pgerror, RecNumber, szSqlState,
+   return ER_ReturnError(&(desc->pgerror), RecNumber, szSqlState,
                pfNativeError, szErrorMsg, cbErrorMsgMax,
                pcbErrorMsg, flag);
 }
 
+#endif /* ODBCVER */
index ca72a6fed0bc4591cec30f805e2503e30e5d7661..614be0a02d16088c5d436ce7a99ca6edcc69822c 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * $Id: descriptor.h,v 1.13 2004/07/21 12:29:58 dpage Exp $
+ * $Id: descriptor.h,v 1.14 2006/04/08 16:30:01 dpage Exp $
  *
  */
 
 
 typedef struct
 {
+   char    *name;
+} pgNAME;
+#define    GET_NAME(the_name)  (the_name.name)
+#define    SAFE_NAME(the_name) (the_name.name ? the_name.name : NULL_STRING)
+#define    PRINT_NAME(the_name)    (the_name.name ? the_name.name : PRINT_NULL)
+#define    NAME_IS_NULL(the_name)  (NULL == the_name.name)
+#define    NAME_IS_VALID(the_name) (NULL != the_name.name)
+#define    INIT_NAME(the_name) (the_name.name = NULL)
+#define    NULL_THE_NAME(the_name) \
+do { \
+   if (the_name.name) free(the_name.name); \
+   the_name.name = NULL; \
+} while (0)
+#define    STR_TO_NAME(the_name, str) \
+do { \
+   if ((the_name).name) \
+       free((the_name).name); \
+   (the_name).name = strdup((str)); \
+} while (0)
+#define    NAME_TO_STR(str, the_name) \
+do {\
+   if (the_name.name) strcpy(str, the_name.name); \
+   else *str = '\0'; \
+} while (0)
+#define    NAME_TO_NAME(to, from) \
+do { \
+   if ((to).name) \
+       free((to).name); \
+   if ((from).name) \
+       (to).name = strdup(from.name); \
+   else \
+       (to).name = NULL; \
+} while (0)
+#define    MOVE_NAME(to, from) \
+do { \
+   if ((to).name) \
+       free((to).name); \
+   (to).name = (from).name; \
+   (from).name = NULL; \
+} while (0)
+#define    SET_NAME(the_name, str) ((the_name).name = (str))
+
+#define    NAMECMP(name1, name2) (strcmp(SAFE_NAME(name1), SAFE_NAME(name2)))
+#define    NAMEICMP(name1, name2) (stricmp(SAFE_NAME(name1), SAFE_NAME(name2)))
+
+enum {
+   TI_UPDATABLE    =   1L
+   ,TI_HASOIDS_CHECKED =   (1L << 1)
+   ,TI_HASOIDS =   (1L << 2)
+};
+typedef struct
+{
+   UInt4       table_oid;
    COL_INFO    *col_info; /* cached SQLColumns info for this table */
-   char        schema[SCHEMA_NAME_STORAGE_LEN + 1];
-   char        name[TABLE_NAME_STORAGE_LEN + 1];
-   char        alias[TABLE_NAME_STORAGE_LEN + 1];
-   char        updatable;
+   pgNAME      schema_name;
+   pgNAME      table_name;
+   pgNAME      table_alias;
+   pgNAME      bestitem;
+   pgNAME      bestqual;
+   UInt4       flags;
 } TABLE_INFO;
+#define    TI_set_updatable(ti)    (ti->flags |= TI_UPDATABLE)
+#define    TI_is_updatable(ti) (0 != (ti->flags &= TI_UPDATABLE))
+#define    TI_no_updatable(ti) (ti->flags &= (~TI_UPDATABLE))
+#define    TI_set_hasoids_checked(ti)  (ti->flags |= TI_HASOIDS_CHECKED)
+#define    TI_checked_hasoids(ti)      (0 != (ti->flags &= TI_HASOIDS))
+#define    TI_set_hasoids(ti)  (ti->flags |= TI_HASOIDS)
+#define    TI_has_oids(ti)     (0 != (ti->flags &= TI_HASOIDS))
+#define    TI_set_has_no_oids(ti)  (ti->flags &= (~TI_HASOIDS))
+void   TI_Constructor(TABLE_INFO *, const ConnectionClass *);
+void   TI_Destructor(TABLE_INFO **, int);
 
+enum {
+   FIELD_INITIALIZED   = 0
+   ,FIELD_PARSING      = 1L
+   ,FIELD_TEMP_SET     = (1L << 1)
+   ,FIELD_COL_ATTRIBUTE    = (1L << 2)
+   ,FIELD_PARSED_OK    = (1L << 3)
+};
 typedef struct
 {
-   TABLE_INFO *ti;     /* resolve to explicit table names */
-   int         column_size; /* precision in 2.x */
-   int         decimal_digits; /* scale in 2.x */
-   int         display_size;
-   int         length;
-   int         type;
+   char        flag;
+   char        updatable;
+   Int2        attnum;
+   pgNAME      schema_name;
+   TABLE_INFO *ti; /* to resolve explicit table names */
+   pgNAME      column_name;
+   pgNAME      column_alias;
    char        nullable;
+   char        auto_increment;
    char        func;
+   int     column_size; /* precision in 2.x */
+   int     decimal_digits; /* scale in 2.x */
+   int     display_size;
+   int     length;
+   int     type;
    char        expr;
    char        quote;
    char        dquote;
    char        numeric;
-   char        updatable;
-   char        dot[TABLE_NAME_STORAGE_LEN + 1];
-   char        name[COLUMN_NAME_STORAGE_LEN + 1];
-   char        alias[COLUMN_NAME_STORAGE_LEN + 1];
-   char        *schema;
+   pgNAME      before_dot;
 } FIELD_INFO;
 Int4 FI_precision(const FIELD_INFO *);
 Int4 FI_scale(const FIELD_INFO *);
+void   FI_Constructor(FIELD_INFO *, BOOL reuse);
+void   FI_Destructor(FIELD_INFO **, int, BOOL freeFI);
 
 typedef struct DescriptorHeader_
 {
@@ -64,7 +141,9 @@ typedef struct DescriptorHeader_
  */
 struct ARDFields_
 {
+#if (ODBCVER >= 0x0300)
    int     size_of_rowset; /* for ODBC3 fetch operation */
+#endif /* ODBCVER */
    int     bind_size;  /* size of each structure if using
                     * Row-wise Binding */
    UInt2       *row_operation_ptr;
@@ -80,7 +159,7 @@ struct ARDFields_
  */
 struct APDFields_
 {
-   int     paramset_size;
+   SQLLEN      paramset_size;
    int     param_bind_type; /* size of each structure if using
                      * Row-wsie Parameter Binding */
    UInt2       *param_operation_ptr;
@@ -152,6 +231,7 @@ BindInfoClass   *ARD_AllocBookmark(ARDFields *self);
 void   ARD_unbind_cols(ARDFields *self, BOOL freeall);
 void   APD_free_params(APDFields *self, char option);
 void   IPD_free_params(IPDFields *self, char option);
+#if (ODBCVER >= 0x0300)
 RETCODE    DC_set_stmt(DescriptorClass *desc, StatementClass *stmt);
 void   DC_clear_error(DescriptorClass *desc);
 void   DC_set_error(DescriptorClass *desc, int errornumber, const char * errormsg);
@@ -160,42 +240,46 @@ PG_ErrorInfo *DC_get_error(DescriptorClass *self);
 int    DC_get_errornumber(const DescriptorClass *self);
 const char *DC_get_errormsg(const DescriptorClass *self);
 void   DC_log_error(const char *func, const char *desc, const DescriptorClass *self);
+#endif /* ODBCVER */
 
 /* Error numbers about descriptor handle */
-#define DESC_OK                        0
-#define DESC_EXEC_ERROR                    1
-#define DESC_STATUS_ERROR              2
-#define DESC_SEQUENCE_ERROR                3
-#define DESC_NO_MEMORY_ERROR               4
-#define DESC_COLNUM_ERROR              5
-#define DESC_NO_STMTSTRING             6
-#define DESC_ERROR_TAKEN_FROM_BACKEND          7
-#define DESC_INTERNAL_ERROR                8
-#define DESC_STILL_EXECUTING               9
-#define DESC_NOT_IMPLEMENTED_ERROR         10
-#define DESC_BAD_PARAMETER_NUMBER_ERROR            11
-#define DESC_OPTION_OUT_OF_RANGE_ERROR         12
-#define DESC_INVALID_COLUMN_NUMBER_ERROR       13
-#define DESC_RESTRICTED_DATA_TYPE_ERROR            14
-#define DESC_INVALID_CURSOR_STATE_ERROR            15
-#define DESC_OPTION_VALUE_CHANGED          16
-#define DESC_CREATE_TABLE_ERROR                17
-#define DESC_NO_CURSOR_NAME                18
-#define DESC_INVALID_CURSOR_NAME           19
-#define DESC_INVALID_ARGUMENT_NO           20
-#define DESC_ROW_OUT_OF_RANGE              21
-#define DESC_OPERATION_CANCELLED           22
-#define DESC_INVALID_CURSOR_POSITION           23
-#define DESC_VALUE_OUT_OF_RANGE                24
-#define DESC_OPERATION_INVALID             25
-#define DESC_PROGRAM_TYPE_OUT_OF_RANGE         26
-#define DESC_BAD_ERROR                 27
-#define DESC_INVALID_OPTION_IDENTIFIER         28
-#define DESC_RETURN_NULL_WITHOUT_INDICATOR     29
-#define DESC_ERROR_IN_ROW              30
-#define DESC_INVALID_DESCRIPTOR_IDENTIFIER     31
-#define DESC_OPTION_NOT_FOR_THE_DRIVER         32
-#define DESC_FETCH_OUT_OF_RANGE                33
-#define DESC_COUNT_FIELD_INCORRECT         34
-
+enum {
+   LOWEST_DESC_ERROR       = -2
+   /* minus means warning/notice message */
+   ,DESC_ERROR_IN_ROW      = -2
+   ,DESC_OPTION_VALUE_CHANGED  = -1
+   ,DESC_OK            = 0
+   ,DESC_EXEC_ERROR
+   ,DESC_STATUS_ERROR
+   ,DESC_SEQUENCE_ERROR
+   ,DESC_NO_MEMORY_ERROR
+   ,DESC_COLNUM_ERROR
+   ,DESC_NO_STMTSTRING
+   ,DESC_ERROR_TAKEN_FROM_BACKEND
+   ,DESC_INTERNAL_ERROR
+   ,DESC_STILL_EXECUTING
+   ,DESC_NOT_IMPLEMENTED_ERROR
+   ,DESC_BAD_PARAMETER_NUMBER_ERROR
+   ,DESC_OPTION_OUT_OF_RANGE_ERROR
+   ,DESC_INVALID_COLUMN_NUMBER_ERROR
+   ,DESC_RESTRICTED_DATA_TYPE_ERROR
+   ,DESC_INVALID_CURSOR_STATE_ERROR
+   ,DESC_CREATE_TABLE_ERROR
+   ,DESC_NO_CURSOR_NAME
+   ,DESC_INVALID_CURSOR_NAME
+   ,DESC_INVALID_ARGUMENT_NO
+   ,DESC_ROW_OUT_OF_RANGE
+   ,DESC_OPERATION_CANCELLED
+   ,DESC_INVALID_CURSOR_POSITION
+   ,DESC_VALUE_OUT_OF_RANGE
+   ,DESC_OPERATION_INVALID 
+   ,DESC_PROGRAM_TYPE_OUT_OF_RANGE
+   ,DESC_BAD_ERROR
+   ,DESC_INVALID_OPTION_IDENTIFIER
+   ,DESC_RETURN_NULL_WITHOUT_INDICATOR
+   ,DESC_INVALID_DESCRIPTOR_IDENTIFIER
+   ,DESC_OPTION_NOT_FOR_THE_DRIVER
+   ,DESC_FETCH_OUT_OF_RANGE
+   ,DESC_COUNT_FIELD_INCORRECT
+};
 #endif /* __DESCRIPTOR_H__ */
index eeb91a484091fae24625323756d6f4e45cd5ff3b..0db4f0247a3d6c6aa5a5b33b6d0b1cacd2c1eee6 100644 (file)
  *
  * API functions:  none
  *
- * Removed params:  Don't reuse old parameter name if it's not for original
- *                  purpose. Here is list of deleted params:
- *                  Protocol              communication protocol (before libpq)
- *
  * Comments:       See "notice.txt" for copyright and license information.
  *-------
  */
 #include "multibyte.h"
 #include "pgapifunc.h"
 
-#ifndef BOOL
-#define BOOL   int
-#endif
-#ifndef FALSE
-#define FALSE  (BOOL)0
-#endif
-#ifndef TRUE
-#define TRUE   (BOOL)1
-#endif
-
 extern GLOBAL_VALUES globals;
 
+static void encode(const char *in, char *out);
+static void decode(const char *in, char *out);
+
 void
 makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
 {
    char        got_dsn = (ci->dsn[0] != '\0');
    char        encoded_conn_settings[LARGE_REGISTRY_LEN];
-   UWORD       hlen;
+   Int4        hlen, nlen, olen;
    /*BOOL      abbrev = (len <= 400);*/
-   BOOL        abbrev = (len < 1024);
+   BOOL        abbrev = (len < 1024) || ci->force_abbrev_connstr;
 
+inolog("force_abbrev=%d abbrev=%d\n", ci->force_abbrev_connstr, abbrev);
    /* fundamental info */
-   sprintf(connect_string, "%s=%s;DATABASE=%s;SERVER=%s;PORT=%s;SSLMODE=%s;UID=%s;PWD=%s",
+   nlen = MAX_CONNECT_STRING;
+   olen = snprintf(connect_string, nlen, "%s=%s;DATABASE=%s;SERVER=%s;PORT=%s;UID=%s;PWD=%s",
            got_dsn ? "DSN" : "DRIVER",
            got_dsn ? ci->dsn : ci->drivername,
            ci->database,
            ci->server,
            ci->port,
-            ci->sslmode,
            ci->username,
            ci->password);
+   if (olen < 0 || olen >= nlen)
+   {
+       connect_string[0] = '\0';
+       return;
+   }
 
    encode(ci->conn_settings, encoded_conn_settings);
 
    /* extra info */
    hlen = strlen(connect_string);
+   nlen = MAX_CONNECT_STRING - hlen;
+inolog("hlen=%d", hlen);
    if (!abbrev)
-       sprintf(&connect_string[hlen],
-               ";%s=%s;%s=%s;%s=%s;%s=%s;%s=%s;%s=%s;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%s;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d",
-               INI_READONLY,
-               ci->onlyread,
-               INI_FAKEOIDINDEX,
-               ci->fake_oid_index,
-               INI_SHOWOIDCOLUMN,
-               ci->show_oid_column,
-               INI_ROWVERSIONING,
-               ci->row_versioning,
-               INI_SHOWSYSTEMTABLES,
-               ci->show_system_tables,
-               INI_CONNSETTINGS,
-               encoded_conn_settings,
-               INI_FETCH,
-               ci->drivers.fetch_max,
-               INI_SOCKET,
-               ci->drivers.socket_buffersize,
-               INI_UNKNOWNSIZES,
-               ci->drivers.unknown_sizes,
-               INI_MAXVARCHARSIZE,
-               ci->drivers.max_varchar_size,
-               INI_MAXLONGVARCHARSIZE,
-               ci->drivers.max_longvarchar_size,
-               INI_DEBUG,
-               ci->drivers.debug,
-               INI_COMMLOG,
-               ci->drivers.commlog,
-               INI_OPTIMIZER,
-               ci->drivers.disable_optimizer,
-               INI_KSQO,
-               ci->drivers.ksqo,
-               INI_USEDECLAREFETCH,
-               ci->drivers.use_declarefetch,
-               INI_TEXTASLONGVARCHAR,
-               ci->drivers.text_as_longvarchar,
-               INI_UNKNOWNSASLONGVARCHAR,
-               ci->drivers.unknowns_as_longvarchar,
-               INI_BOOLSASCHAR,
-               ci->drivers.bools_as_char,
-               INI_PARSE,
-               ci->drivers.parse,
-               INI_CANCELASFREESTMT,
-               ci->drivers.cancel_as_freestmt,
-               INI_EXTRASYSTABLEPREFIXES,
-               ci->drivers.extra_systable_prefixes,
-               INI_LFCONVERSION,
-               ci->lf_conversion,
-               INI_UPDATABLECURSORS,
-               ci->allow_keyset,
-               INI_DISALLOWPREMATURE,
-               ci->disallow_premature,
-               INI_TRUEISMINUS1,
-               ci->true_is_minus1,
-               INI_INT8AS,
-               ci->int8_as,
-               INI_BYTEAASLONGVARBINARY,
-               ci->bytea_as_longvarbinary,
-               INI_USESERVERSIDEPREPARE,
-               ci->use_server_side_prepare,
-               INI_LOWERCASEIDENTIFIER,
-               ci->lower_case_identifier);
+   {
+       char    protocol_and[16];
+       
+       if (ci->rollback_on_error >= 0)
+           snprintf(protocol_and, sizeof(protocol_and), "%s-%d", ci->protocol, ci->rollback_on_error);
+       else
+           strncpy(protocol_and, ci->protocol, sizeof(protocol_and));
+       olen = snprintf(&connect_string[hlen], nlen, ";"
+           INI_SSLMODE "=%s;"
+           INI_READONLY "=%s;"
+           INI_PROTOCOL "=%s;"
+           INI_FAKEOIDINDEX "=%s;"
+           INI_SHOWOIDCOLUMN "=%s;"
+           INI_ROWVERSIONING "=%s;"
+           INI_SHOWSYSTEMTABLES "=%s;"
+           INI_CONNSETTINGS "=%s;"
+           INI_FETCH "=%d;"
+           INI_SOCKET "=%d;"
+           INI_UNKNOWNSIZES "=%d;"
+           INI_MAXVARCHARSIZE "=%d;"
+           INI_MAXLONGVARCHARSIZE "=%d;"
+           INI_DEBUG "=%d;"
+           INI_COMMLOG "=%d;"
+           INI_OPTIMIZER "=%d;"
+           INI_KSQO "=%d;"
+           INI_USEDECLAREFETCH "=%d;"
+           INI_TEXTASLONGVARCHAR "=%d;"
+           INI_UNKNOWNSASLONGVARCHAR "=%d;"
+           INI_BOOLSASCHAR "=%d;"
+           INI_PARSE "=%d;"
+           INI_CANCELASFREESTMT "=%d;"
+           INI_EXTRASYSTABLEPREFIXES "=%s;"
+           INI_LFCONVERSION "=%d;"
+           INI_UPDATABLECURSORS "=%d;"
+           INI_DISALLOWPREMATURE "=%d;"
+           INI_TRUEISMINUS1 "=%d;"
+           INI_INT8AS "=%d;"
+           INI_BYTEAASLONGVARBINARY "=%d;"
+           INI_USESERVERSIDEPREPARE "=%d;"
+           INI_LOWERCASEIDENTIFIER "=%d;"
+#ifdef _HANDLE_ENLIST_IN_DTC_
+           INI_XAOPT "=%d" /* XAOPT */
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
+           ,ci->sslmode
+           ,ci->onlyread
+           ,protocol_and
+           ,ci->fake_oid_index
+           ,ci->show_oid_column
+           ,ci->row_versioning
+           ,ci->show_system_tables
+           ,encoded_conn_settings
+           ,ci->drivers.fetch_max
+           ,ci->drivers.socket_buffersize
+           ,ci->drivers.unknown_sizes
+           ,ci->drivers.max_varchar_size
+           ,ci->drivers.max_longvarchar_size
+           ,ci->drivers.debug
+           ,ci->drivers.commlog
+           ,ci->drivers.disable_optimizer
+           ,ci->drivers.ksqo
+           ,ci->drivers.use_declarefetch
+           ,ci->drivers.text_as_longvarchar
+           ,ci->drivers.unknowns_as_longvarchar
+           ,ci->drivers.bools_as_char
+           ,ci->drivers.parse
+           ,ci->drivers.cancel_as_freestmt
+           ,ci->drivers.extra_systable_prefixes
+           ,ci->lf_conversion
+           ,ci->allow_keyset
+           ,ci->disallow_premature
+           ,ci->true_is_minus1
+           ,ci->int8_as
+           ,ci->bytea_as_longvarbinary
+           ,ci->use_server_side_prepare
+           ,ci->lower_case_identifier
+#ifdef _HANDLE_ENLIST_IN_DTC_
+           ,ci->xa_opt
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
+               );
+   }
    /* Abbrebiation is needed ? */
-   if (abbrev || strlen(connect_string) >= len)
+   if (abbrev || olen >= nlen || olen < 0)
    {
-       UInt4 flag = 0;
+       UInt4 long flag = 0;
        if (ci->disallow_premature)
            flag |= BIT_DISALLOWPREMATURE;
        if (ci->allow_keyset)
@@ -139,6 +154,12 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
            flag |= BIT_LFCONVERSION;
        if (ci->drivers.unique_index)
            flag |= BIT_UNIQUEINDEX;
+       if (PROTOCOL_74(ci))
+           flag |= (BIT_PROTOCOL_64 | BIT_PROTOCOL_63);
+       else if (PROTOCOL_64(ci))
+           flag |= BIT_PROTOCOL_64;
+       else if (PROTOCOL_63(ci))
+           flag |= BIT_PROTOCOL_63;
        switch (ci->drivers.unknown_sizes)
        {
            case UNKNOWNS_AS_DONTKNOW:
@@ -187,31 +208,61 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
        if (ci->lower_case_identifier)
            flag |= BIT_LOWERCASEIDENTIFIER;
 
-       sprintf(&connect_string[hlen],
-               ";A6=%s;A7=%d;A8=%d;B0=%d;B1=%d;%s=%d;C2=%s;CX=%02x%lx",
+       if (ci->sslmode[0])
+           olen = snprintf(&connect_string[hlen], nlen, ";"
+               ABBR_SSLMODE "=%c", ci->sslmode[0]);
+       hlen = strlen(connect_string);
+       nlen = MAX_CONNECT_STRING - hlen;
+       olen = snprintf(&connect_string[hlen], nlen, ";"
+               ABBR_CONNSETTINGS "=%s;"
+               ABBR_FETCH "=%d;"
+               ABBR_SOCKET "=%d;"
+               ABBR_MAXVARCHARSIZE "=%d;"
+               ABBR_MAXLONGVARCHARSIZE "=%d;"
+               INI_INT8AS "=%d;"
+               ABBR_EXTRASYSTABLEPREFIXES "=%s;"
+               INI_ABBREVIATE "=%02x%lx",
                encoded_conn_settings,
                ci->drivers.fetch_max,
                ci->drivers.socket_buffersize,
                ci->drivers.max_varchar_size,
                ci->drivers.max_longvarchar_size,
-               INI_INT8AS,
                ci->int8_as,
                ci->drivers.extra_systable_prefixes,
                EFFECTIVE_BIT_COUNT,
-               (long unsigned int) flag);
+               flag);
+       if (olen < nlen && (PROTOCOL_74(ci) || ci->rollback_on_error >= 0))
+       {
+           hlen = strlen(connect_string);
+           nlen = MAX_CONNECT_STRING - hlen;
+           /*
+            * The PROTOCOL setting must be placed after CX flag
+            * so that this option can override the CX setting.
+            */
+           if (ci->rollback_on_error >= 0)
+               olen = snprintf(&connect_string[hlen], nlen, ";"
+               ABBR_PROTOCOL "=%s-%d",
+               ci->protocol, ci->rollback_on_error);
+           else
+               olen = snprintf(&connect_string[hlen], nlen, ";"
+               ABBR_PROTOCOL "=%s",
+               ci->protocol);
+       }
+       if (olen < 0 || olen >= nlen) /* failed */
+           connect_string[0] = '\0';
    }
 }
 
 static void
 unfoldCXAttribute(ConnInfo *ci, const char *value)
 {
-   int     count;
-   UInt4       flag;
+   int count;
+   UInt4   flag;
 
    if (strlen(value) < 2)
    {
        count = 3;
-       sscanf(value, "%lx", (long unsigned int *) &flag);
+       sscanf(value, "%lx", &flag);
    }
    else
    {
@@ -219,7 +270,7 @@ unfoldCXAttribute(ConnInfo *ci, const char *value)
        memcpy(cnt, value, 2);
        cnt[2] = '\0';
        sscanf(cnt, "%x", &count);
-       sscanf(value + 2, "%lx", (long unsigned int *) &flag);
+       sscanf(value + 2, "%lx", &flag);
    }
    ci->disallow_premature = (char)((flag & BIT_DISALLOWPREMATURE) != 0);
    ci->allow_keyset = (char)((flag & BIT_UPDATABLECURSORS) != 0);
@@ -227,6 +278,17 @@ unfoldCXAttribute(ConnInfo *ci, const char *value)
    if (count < 4)
        return;
    ci->drivers.unique_index = (char)((flag & BIT_UNIQUEINDEX) != 0);
+   if ((flag & BIT_PROTOCOL_64) != 0)
+   {
+       if ((flag & BIT_PROTOCOL_63) != 0)
+           strcpy(ci->protocol, PG74);
+       else
+           strcpy(ci->protocol, PG64);
+   }
+   else if ((flag & BIT_PROTOCOL_63) != 0)
+       strcpy(ci->protocol, PG63);
+   else
+       strcpy(ci->protocol, PG62);
    if ((flag & BIT_UNKNOWN_DONTKNOW) != 0)
        ci->drivers.unknown_sizes = UNKNOWNS_AS_DONTKNOW;
    else if ((flag & BIT_UNKNOWN_ASMAX) != 0)
@@ -265,7 +327,7 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
    else if (stricmp(attribute, INI_DATABASE) == 0)
        strcpy(ci->database, value);
 
-   else if (stricmp(attribute, INI_SERVER) == 0 || stricmp(attribute, "server") == 0)
+   else if (stricmp(attribute, INI_SERVER) == 0 || stricmp(attribute, SPEC_SERVER) == 0)
        strcpy(ci->server, value);
 
    else if (stricmp(attribute, INI_USER) == 0 || stricmp(attribute, "uid") == 0)
@@ -276,66 +338,105 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
 
    else if (stricmp(attribute, INI_PORT) == 0)
        strcpy(ci->port, value);
-    
-   else if (stricmp(attribute, INI_SSLMODE) == 0 || stricmp(attribute, "sslmode") == 0)
-       strcpy(ci->sslmode, value);
 
-   else if (stricmp(attribute, INI_READONLY) == 0 || stricmp(attribute, "A0") == 0)
+   else if (stricmp(attribute, INI_READONLY) == 0 || stricmp(attribute, ABBR_READONLY) == 0)
        strcpy(ci->onlyread, value);
 
-   else if (stricmp(attribute, INI_SHOWOIDCOLUMN) == 0 || stricmp(attribute, "A3") == 0)
+   else if (stricmp(attribute, INI_PROTOCOL) == 0 || stricmp(attribute, ABBR_PROTOCOL) == 0)
+   {
+       char    *ptr;
+
+       ptr = strchr(value, '-');
+       if (ptr)
+       {
+           if ('-' != *value)
+           {
+               strcpy(ci->protocol, value);
+           }
+           *ptr = '\0';
+           ci->rollback_on_error = atoi(ptr + 1);
+           mylog("rollback_on_error=%d\n", ci->rollback_on_error);
+       }
+       else
+           strcpy(ci->protocol, value);
+   }
+
+   else if (stricmp(attribute, INI_SHOWOIDCOLUMN) == 0 || stricmp(attribute, ABBR_SHOWOIDCOLUMN) == 0)
        strcpy(ci->show_oid_column, value);
 
-   else if (stricmp(attribute, INI_FAKEOIDINDEX) == 0 || stricmp(attribute, "A2") == 0)
+   else if (stricmp(attribute, INI_FAKEOIDINDEX) == 0 || stricmp(attribute, ABBR_FAKEOIDINDEX) == 0)
        strcpy(ci->fake_oid_index, value);
 
-   else if (stricmp(attribute, INI_ROWVERSIONING) == 0 || stricmp(attribute, "A4") == 0)
+   else if (stricmp(attribute, INI_ROWVERSIONING) == 0 || stricmp(attribute, ABBR_ROWVERSIONING) == 0)
        strcpy(ci->row_versioning, value);
 
-   else if (stricmp(attribute, INI_SHOWSYSTEMTABLES) == 0 || stricmp(attribute, "A5") == 0)
+   else if (stricmp(attribute, INI_SHOWSYSTEMTABLES) == 0 || stricmp(attribute, ABBR_SHOWSYSTEMTABLES) == 0)
        strcpy(ci->show_system_tables, value);
 
-   else if (stricmp(attribute, INI_CONNSETTINGS) == 0 || stricmp(attribute, "A6") == 0)
+   else if (stricmp(attribute, INI_CONNSETTINGS) == 0 || stricmp(attribute, ABBR_CONNSETTINGS) == 0)
    {
        decode(value, ci->conn_settings);
        /* strcpy(ci->conn_settings, value); */
    }
-   else if (stricmp(attribute, INI_DISALLOWPREMATURE) == 0 || stricmp(attribute, "C3") == 0)
+   else if (stricmp(attribute, INI_DISALLOWPREMATURE) == 0 || stricmp(attribute, ABBR_DISALLOWPREMATURE) == 0)
        ci->disallow_premature = atoi(value);
-   else if (stricmp(attribute, INI_UPDATABLECURSORS) == 0 || stricmp(attribute, "C4") == 0)
+   else if (stricmp(attribute, INI_UPDATABLECURSORS) == 0 || stricmp(attribute, ABBR_UPDATABLECURSORS) == 0)
        ci->allow_keyset = atoi(value);
-   else if (stricmp(attribute, INI_LFCONVERSION) == 0)
+   else if (stricmp(attribute, INI_LFCONVERSION) == 0 || stricmp(attribute, ABBR_LFCONVERSION) == 0)
        ci->lf_conversion = atoi(value);
-   else if (stricmp(attribute, INI_TRUEISMINUS1) == 0)
+   else if (stricmp(attribute, INI_TRUEISMINUS1) == 0 || stricmp(attribute, ABBR_TRUEISMINUS1) == 0)
        ci->true_is_minus1 = atoi(value);
    else if (stricmp(attribute, INI_INT8AS) == 0)
        ci->int8_as = atoi(value);
-   else if (stricmp(attribute, INI_BYTEAASLONGVARBINARY) == 0)
+   else if (stricmp(attribute, INI_BYTEAASLONGVARBINARY) == 0 || stricmp(attribute, ABBR_BYTEAASLONGVARBINARY) == 0)
        ci->bytea_as_longvarbinary = atoi(value);
-   else if (stricmp(attribute, INI_USESERVERSIDEPREPARE) == 0)
+   else if (stricmp(attribute, INI_USESERVERSIDEPREPARE) == 0 || stricmp(attribute, ABBR_USESERVERSIDEPREPARE) == 0)
        ci->use_server_side_prepare = atoi(value);
-   else if (stricmp(attribute, INI_LOWERCASEIDENTIFIER) == 0)
+   else if (stricmp(attribute, INI_LOWERCASEIDENTIFIER) == 0 || stricmp(attribute, ABBR_LOWERCASEIDENTIFIER) == 0)
        ci->lower_case_identifier = atoi(value);
-   else if (stricmp(attribute, "CX") == 0)
+   else if (stricmp(attribute, INI_SSLMODE) == 0 || stricmp(attribute, ABBR_SSLMODE) == 0)
+   {
+       switch (value[0])
+       {
+           case 'a':
+               strcpy(ci->sslmode, SSLMODE_ALLOW);
+               break;
+           case 'p':
+               strcpy(ci->sslmode, SSLMODE_PREFER);
+               break;
+           case 'r':
+               strcpy(ci->sslmode, SSLMODE_REQUIRE);
+               break;
+           case 'd':
+           default:
+               strcpy(ci->sslmode, SSLMODE_DISABLE);
+               break;
+       }
+   }
+   else if (stricmp(attribute, INI_ABBREVIATE) == 0)
        unfoldCXAttribute(ci, value);
+#ifdef _HANDLE_ENLIST_IN_DTC_
+   else if (stricmp(attribute, INI_XAOPT) == 0)
+       ci->xa_opt = atoi(value);
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
 
-   mylog("copyAttributes: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',sslmode='%s',onlyread='%s',conn_settings='%s',disallow_premature=%d)\n", ci->dsn, ci->server, ci->database, ci->username, ci->password ? "xxxxx" : "", ci->port, ci->sslmode, ci->onlyread, ci->conn_settings, ci->disallow_premature);
+   mylog("copyAttributes: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',onlyread='%s',protocol='%s',conn_settings='%s',disallow_premature=%d)\n", ci->dsn, ci->server, ci->database, ci->username, ci->password ? "xxxxx" : "", ci->port, ci->onlyread, ci->protocol, ci->conn_settings, ci->disallow_premature);
 }
 
 void
 copyCommonAttributes(ConnInfo *ci, const char *attribute, const char *value)
 {
-   if (stricmp(attribute, INI_FETCH) == 0 || stricmp(attribute, "A7") == 0)
+   if (stricmp(attribute, INI_FETCH) == 0 || stricmp(attribute, ABBR_FETCH) == 0)
        ci->drivers.fetch_max = atoi(value);
-   else if (stricmp(attribute, INI_SOCKET) == 0 || stricmp(attribute, "A8") == 0)
+   else if (stricmp(attribute, INI_SOCKET) == 0 || stricmp(attribute, ABBR_SOCKET) == 0)
        ci->drivers.socket_buffersize = atoi(value);
-   else if (stricmp(attribute, INI_DEBUG) == 0 || stricmp(attribute, "B2") == 0)
+   else if (stricmp(attribute, INI_DEBUG) == 0 || stricmp(attribute, ABBR_DEBUG) == 0)
        ci->drivers.debug = atoi(value);
-   else if (stricmp(attribute, INI_COMMLOG) == 0 || stricmp(attribute, "B3") == 0)
+   else if (stricmp(attribute, INI_COMMLOG) == 0 || stricmp(attribute, ABBR_COMMLOG) == 0)
        ci->drivers.commlog = atoi(value);
-   else if (stricmp(attribute, INI_OPTIMIZER) == 0 || stricmp(attribute, "B4") == 0)
+   else if (stricmp(attribute, INI_OPTIMIZER) == 0 || stricmp(attribute, ABBR_OPTIMIZER) == 0)
        ci->drivers.disable_optimizer = atoi(value);
-   else if (stricmp(attribute, INI_KSQO) == 0 || stricmp(attribute, "B5") == 0)
+   else if (stricmp(attribute, INI_KSQO) == 0 || stricmp(attribute, ABBR_KSQO) == 0)
        ci->drivers.ksqo = atoi(value);
 
    /*
@@ -343,28 +444,30 @@ copyCommonAttributes(ConnInfo *ci, const char *attribute, const char *value)
     * stricmp(attribute, "UIX") == 0) ci->drivers.unique_index =
     * atoi(value);
     */
-   else if (stricmp(attribute, INI_UNKNOWNSIZES) == 0 || stricmp(attribute, "A9") == 0)
+   else if (stricmp(attribute, INI_UNKNOWNSIZES) == 0 || stricmp(attribute, ABBR_UNKNOWNSIZES) == 0)
        ci->drivers.unknown_sizes = atoi(value);
    else if (stricmp(attribute, INI_LIE) == 0)
        ci->drivers.lie = atoi(value);
-   else if (stricmp(attribute, INI_PARSE) == 0 || stricmp(attribute, "C0") == 0)
+   else if (stricmp(attribute, INI_PARSE) == 0 || stricmp(attribute, ABBR_PARSE) == 0)
        ci->drivers.parse = atoi(value);
-   else if (stricmp(attribute, INI_CANCELASFREESTMT) == 0 || stricmp(attribute, "C1") == 0)
+   else if (stricmp(attribute, INI_CANCELASFREESTMT) == 0 || stricmp(attribute, ABBR_CANCELASFREESTMT) == 0)
        ci->drivers.cancel_as_freestmt = atoi(value);
-   else if (stricmp(attribute, INI_USEDECLAREFETCH) == 0 || stricmp(attribute, "B6") == 0)
+   else if (stricmp(attribute, INI_USEDECLAREFETCH) == 0 || stricmp(attribute, ABBR_USEDECLAREFETCH) == 0)
        ci->drivers.use_declarefetch = atoi(value);
-   else if (stricmp(attribute, INI_MAXVARCHARSIZE) == 0 || stricmp(attribute, "B0") == 0)
+   else if (stricmp(attribute, INI_MAXVARCHARSIZE) == 0 || stricmp(attribute, ABBR_MAXVARCHARSIZE) == 0)
        ci->drivers.max_varchar_size = atoi(value);
-   else if (stricmp(attribute, INI_MAXLONGVARCHARSIZE) == 0 || stricmp(attribute, "B1") == 0)
+   else if (stricmp(attribute, INI_MAXLONGVARCHARSIZE) == 0 || stricmp(attribute, ABBR_MAXLONGVARCHARSIZE) == 0)
        ci->drivers.max_longvarchar_size = atoi(value);
-   else if (stricmp(attribute, INI_TEXTASLONGVARCHAR) == 0 || stricmp(attribute, "B7") == 0)
+   else if (stricmp(attribute, INI_TEXTASLONGVARCHAR) == 0 || stricmp(attribute, ABBR_TEXTASLONGVARCHAR) == 0)
        ci->drivers.text_as_longvarchar = atoi(value);
-   else if (stricmp(attribute, INI_UNKNOWNSASLONGVARCHAR) == 0 || stricmp(attribute, "B8") == 0)
+   else if (stricmp(attribute, INI_UNKNOWNSASLONGVARCHAR) == 0 || stricmp(attribute, ABBR_UNKNOWNSASLONGVARCHAR) == 0)
        ci->drivers.unknowns_as_longvarchar = atoi(value);
-   else if (stricmp(attribute, INI_BOOLSASCHAR) == 0 || stricmp(attribute, "B9") == 0)
+   else if (stricmp(attribute, INI_BOOLSASCHAR) == 0 || stricmp(attribute, ABBR_BOOLSASCHAR) == 0)
        ci->drivers.bools_as_char = atoi(value);
-   else if (stricmp(attribute, INI_EXTRASYSTABLEPREFIXES) == 0 || stricmp(attribute, "C2") == 0)
+   else if (stricmp(attribute, INI_EXTRASYSTABLEPREFIXES) == 0 || stricmp(attribute, ABBR_EXTRASYSTABLEPREFIXES) == 0)
        strcpy(ci->drivers.extra_systable_prefixes, value);
+   else if (stricmp(attribute, INI_FORCEABBREVCONNSTR) == 0)
+       ci->force_abbrev_connstr = atoi(value);
    mylog("CopyCommonAttributes: A7=%d;A8=%d;A9=%d;B0=%d;B1=%d;B2=%d;B3=%d;B4=%d;B5=%d;B6=%d;B7=%d;B8=%d;B9=%d;C0=%d;C1=%d;C2=%s",
          ci->drivers.fetch_max,
          ci->drivers.socket_buffersize,
@@ -388,15 +491,17 @@ copyCommonAttributes(ConnInfo *ci, const char *attribute, const char *value)
 void
 getDSNdefaults(ConnInfo *ci)
 {
+   mylog("calling getDSNdefaults\n");
+
    if (ci->port[0] == '\0')
        strcpy(ci->port, DEFAULT_PORT);
-    
-   if (ci->sslmode[0] == '\0')
-       strcpy(ci->sslmode, DEFAULT_SSLMODE);
 
    if (ci->onlyread[0] == '\0')
        sprintf(ci->onlyread, "%d", globals.onlyread);
 
+   if (ci->protocol[0] == '\0')
+       strcpy(ci->protocol, globals.protocol);
+
    if (ci->fake_oid_index[0] == '\0')
        sprintf(ci->fake_oid_index, "%d", DEFAULT_FAKEOIDINDEX);
 
@@ -425,6 +530,12 @@ getDSNdefaults(ConnInfo *ci)
        ci->use_server_side_prepare = DEFAULT_USESERVERSIDEPREPARE;
    if (ci->lower_case_identifier < 0)
        ci->lower_case_identifier = DEFAULT_LOWERCASEIDENTIFIER;
+   if (ci->sslmode[0] == '\0')
+       strcpy(ci->sslmode, DEFAULT_SSLMODE);
+#ifdef _HANDLE_ENLIST_IN_DTC_
+   if (ci->xa_opt < 0)
+       ci->xa_opt = DEFAULT_XAOPT;
+#endif /* HANDLE_ENLIST_IN_DTC_ */
 }
 
 int
@@ -436,6 +547,7 @@ getDriverNameFromDSN(const char *dsn, char *driver_name, int namelen)
 void
 getDSNinfo(ConnInfo *ci, char overwrite)
 {
+   CSTR    func = "getDSNinfo";
    char       *DSN = ci->dsn;
    char        encoded_conn_settings[LARGE_REGISTRY_LEN],
                temp[SMALL_REGISTRY_LEN];
@@ -444,12 +556,13 @@ getDSNinfo(ConnInfo *ci, char overwrite)
  * If a driver keyword was present, then dont use a DSN and return.
  * If DSN is null and no driver, then use the default datasource.
  */
+   mylog("%s: DSN=%s overwrite=%d\n", func, DSN, overwrite);
    if (DSN[0] == '\0')
    {
        if (ci->drivername[0] != '\0')
            return;
        else
-           strcpy(DSN, INI_DSN);
+           strncpy_null(DSN, INI_DSN, sizeof(ci->dsn));
    }
 
    /* brute-force chop off trailing blanks... */
@@ -483,9 +596,6 @@ getDSNinfo(ConnInfo *ci, char overwrite)
    if (ci->port[0] == '\0' || overwrite)
        SQLGetPrivateProfileString(DSN, INI_PORT, "", ci->port, sizeof(ci->port), ODBC_INI);
 
-   if (ci->sslmode[0] == '\0' || overwrite)
-       SQLGetPrivateProfileString(DSN, INI_SSLMODE, "", ci->sslmode, sizeof(ci->sslmode), ODBC_INI);
-    
    if (ci->onlyread[0] == '\0' || overwrite)
        SQLGetPrivateProfileString(DSN, INI_READONLY, "", ci->onlyread, sizeof(ci->onlyread), ODBC_INI);
 
@@ -501,6 +611,21 @@ getDSNinfo(ConnInfo *ci, char overwrite)
    if (ci->show_system_tables[0] == '\0' || overwrite)
        SQLGetPrivateProfileString(DSN, INI_SHOWSYSTEMTABLES, "", ci->show_system_tables, sizeof(ci->show_system_tables), ODBC_INI);
 
+   if (ci->protocol[0] == '\0' || overwrite)
+   {
+       char    *ptr;
+       SQLGetPrivateProfileString(DSN, INI_PROTOCOL, "", ci->protocol, sizeof(ci->protocol), ODBC_INI);
+       if (ptr = strchr(ci->protocol, '-'))
+       {
+           *ptr = '\0';
+           if (overwrite || ci->rollback_on_error < 0)
+           {
+               ci->rollback_on_error = atoi(ptr + 1);
+               mylog("rollback_on_error=%d\n", ci->rollback_on_error);
+           }
+       }
+   }
+
    if (ci->conn_settings[0] == '\0' || overwrite)
    {
        SQLGetPrivateProfileString(DSN, INI_CONNSETTINGS, "", encoded_conn_settings, sizeof(encoded_conn_settings), ODBC_INI);
@@ -569,6 +694,18 @@ getDSNinfo(ConnInfo *ci, char overwrite)
            ci->lower_case_identifier = atoi(temp);
    }
 
+   if (ci->sslmode[0] == '\0' || overwrite)
+       SQLGetPrivateProfileString(DSN, INI_SSLMODE, "", ci->sslmode, sizeof(ci->sslmode), ODBC_INI);
+
+#ifdef _HANDLE_ENLIST_IN_DTC_
+   if (ci->xa_opt < 0 || overwrite)
+   {
+       SQLGetPrivateProfileString(DSN, INI_XAOPT, "", temp, sizeof(temp), ODBC_INI);
+       if (temp[0])
+           ci->xa_opt = atoi(temp);
+   }
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
+
    /* Allow override of odbcinst.ini parameters here */
    getCommonDefaults(DSN, ODBC_INI, ci);
 
@@ -579,8 +716,9 @@ getDSNinfo(ConnInfo *ci, char overwrite)
         ci->database,
         ci->username,
         ci->password ? "xxxxx" : "");
-   qlog("          onlyread='%s',showoid='%s',fakeoidindex='%s',showsystable='%s'\n",
+   qlog("          onlyread='%s',protocol='%s',showoid='%s',fakeoidindex='%s',showsystable='%s'\n",
         ci->onlyread,
+        ci->protocol,
         ci->show_oid_column,
         ci->fake_oid_index,
         ci->show_system_tables);
@@ -714,11 +852,6 @@ writeDSNinfo(const ConnInfo *ci)
                                 INI_PORT,
                                 ci->port,
                                 ODBC_INI);
-                                 
-   SQLWritePrivateProfileString(DSN,
-                                INI_SSLMODE,
-                                ci->sslmode,
-                                ODBC_INI);
 
    SQLWritePrivateProfileString(DSN,
                                 INI_USER,
@@ -755,6 +888,12 @@ writeDSNinfo(const ConnInfo *ci)
                                 ci->show_system_tables,
                                 ODBC_INI);
 
+   sprintf(temp, "%s-%d", ci->protocol, ci->rollback_on_error);
+   SQLWritePrivateProfileString(DSN,
+                                INI_PROTOCOL,
+                                temp,
+                                ODBC_INI);
+
    SQLWritePrivateProfileString(DSN,
                                 INI_CONNSETTINGS,
                                 encoded_conn_settings,
@@ -800,6 +939,14 @@ writeDSNinfo(const ConnInfo *ci)
                                 INI_LOWERCASEIDENTIFIER,
                                 temp,
                                 ODBC_INI);
+   SQLWritePrivateProfileString(DSN,
+                                INI_SSLMODE,
+                                ci->sslmode,
+                                ODBC_INI);
+#ifdef _HANDLE_ENLIST_IN_DTC_
+   sprintf(temp, "%d", ci->xa_opt);
+   SQLWritePrivateProfileString(DSN, INI_XAOPT, temp, ODBC_INI);
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
 }
 
 
@@ -996,5 +1143,87 @@ getCommonDefaults(const char *section, const char *filename, ConnInfo *ci)
        else
            comval->onlyread = DEFAULT_READONLY;
 
+       /*
+        * Default state for future DSN's protocol attribute This isn't a
+        * real driver option YET.  This is more intended for
+        * customization from the install.
+        */
+       SQLGetPrivateProfileString(section, INI_PROTOCOL, "@@@",
+                                  temp, sizeof(temp), filename);
+       if (strcmp(temp, "@@@"))
+           strcpy(comval->protocol, temp);
+       else
+           strcpy(comval->protocol, DEFAULT_PROTOCOL);
+   }
+}
+
+static void
+encode(const char *in, char *out)
+{
+   unsigned int i,
+               ilen = strlen(in),
+               o = 0;
+
+   for (i = 0; i < ilen; i++)
+   {
+       if (in[i] == '+')
+       {
+           sprintf(&out[o], "%%2B");
+           o += 3;
+       }
+       else if (isspace((UCHAR) in[i]))
+           out[o++] = '+';
+       else if (!isalnum((UCHAR) in[i]))
+       {
+           sprintf(&out[o], "%%%02x", (UCHAR) in[i]);
+           o += 3;
+       }
+       else
+           out[o++] = in[i];
+   }
+   out[o++] = '\0';
+}
+
+static unsigned int
+conv_from_hex(const UCHAR *s)
+{
+   int         i,
+               y = 0,
+               val;
+
+   for (i = 1; i <= 2; i++)
+   {
+       if (s[i] >= 'a' && s[i] <= 'f')
+           val = s[i] - 'a' + 10;
+       else if (s[i] >= 'A' && s[i] <= 'F')
+           val = s[i] - 'A' + 10;
+       else
+           val = s[i] - '0';
+
+       y += val << (4 * (2 - i));
+   }
+
+   return y;
+}
+
+static void
+decode(const char *in, char *out)
+{
+   unsigned int i,
+               ilen = strlen(in),
+               o = 0;
+
+   for (i = 0; i < ilen; i++)
+   {
+       if (in[i] == '+')
+           out[o++] = ' ';
+       else if (in[i] == '%')
+       {
+           sprintf(&out[o++], "%c", conv_from_hex(&in[i]));
+           i += 2;
+       }
+       else
+           out[o++] = in[i];
    }
+   out[o++] = '\0';
 }
index edc8cdf7c55f03b38f21aa3f6906913c473eee5a..261621c5ee46c289977c3c851c0481c6cd8dc6d3 100644 (file)
 #endif
 
 /* Unknown data type sizes */
-#define UNKNOWNS_AS_MAX            0
-#define UNKNOWNS_AS_DONTKNOW       1
-#define UNKNOWNS_AS_LONGEST        2
+#define UNKNOWNS_AS_MAX                0
+#define UNKNOWNS_AS_DONTKNOW           1
+#define UNKNOWNS_AS_LONGEST            2
 
 /* ODBC initialization files */
 #ifndef WIN32
-#define ODBC_INI           ".odbc.ini"
-#define ODBCINST_INI           "odbcinst.ini"
+#define ODBC_INI               ".odbc.ini"
+#define ODBCINST_INI               "odbcinst.ini"
 #else
-#define ODBC_INI           "ODBC.INI"
-#define ODBCINST_INI           "ODBCINST.INI"
+#define ODBC_INI               "ODBC.INI"
+#define ODBCINST_INI               "ODBCINST.INI"
 #endif
 
-#define    ODBC_DATASOURCES        "ODBC Data Sources"
+#define    ODBC_DATASOURCES    "ODBC Data Sources"
 
-#define INI_DSN                DRIVERNAME
-
-#define INI_KDESC          "Description"   /* Data source description */
-#define INI_SERVER         "Servername"    /* Name of Server running PostgreSQL */
-#define INI_PORT           "Port"      /* Port on which the Postmaster is listening */
-#define INI_SSLMODE                "SSLmode"
-
-#if !defined WIN32 && defined HAVE_SYS_UN_H
-#ifndef HAVE_UNIX_SOCKETS
-#define HAVE_UNIX_SOCKETS
-#endif
-#define INI_UDS                "Uds"       /* Unix domain socket path*/
-#endif
+#if (ODBCVER >= 0x0300)
+#ifdef  UNICODE_SUPPORT
+#define INI_DSN                "PostgreSQL30W"
+#else
+#define INI_DSN                "PostgreSQL30"
+#endif /* UNICODE_SUPPORT */
+#else
+#define INI_DSN                DBMS_NAME
+#endif   /* ODBCVER */
 
+#define INI_KDESC          "Description"   /* Data source
+                            * description */
+#define INI_SERVER         "Servername"    /* Name of Server
+                            * running the Postgres
+                            * service */
+#define SPEC_SERVER            "server"
+#define INI_PORT           "Port"  /* Port on which the
+                        * Postmaster is listening */
 #define INI_DATABASE           "Database"  /* Database Name */
 #define INI_USER           "Username"  /* Default User Name */
 #define INI_PASSWORD           "Password"  /* Default Password */
-#define INI_DEBUG          "Debug"     /* Debug flag */
-#define INI_FETCH          "Fetch"     /* Fetch Max Count */
+
+#define    INI_ABBREVIATE          "CX"
+#define INI_DEBUG          "Debug"     /* Debug flag */
+#define ABBR_DEBUG         "B2"
+#define INI_FETCH          "Fetch"     /* Fetch Max Count */
+#define ABBR_FETCH         "A7"
 #define INI_SOCKET         "Socket"    /* Socket buffer size */
+#define ABBR_SOCKET            "A8"
 #define INI_READONLY           "ReadOnly"  /* Database is read only */
-#define INI_COMMLOG            "CommLog"   /* Communication to backend logging */
-#define INI_OPTIMIZER          "Optimizer" /* Use backend genetic optimizer */
-#define INI_KSQO           "Ksqo"      /* Keyset query optimization */
-#define INI_CONNSETTINGS       "ConnSettings"  /* Anything to send to backend on successful connection */
-#define INI_UNIQUEINDEX            "UniqueIndex"   /* Recognize unique indexes */
-#define INI_UNKNOWNSIZES       "UnknownSizes"  /* How to handle unknown result set sizes */
+#define ABBR_READONLY          "A0"
+#define INI_COMMLOG            "CommLog"   /* Communication to
+                            * backend logging */
+#define ABBR_COMMLOG           "B3"
+#define INI_PROTOCOL           "Protocol"  /* What protocol (6.2) */
+#define ABBR_PROTOCOL          "A1"
+#define INI_OPTIMIZER          "Optimizer" /* Use backend genetic
+                            * optimizer */
+#define ABBR_OPTIMIZER         "B4"
+#define INI_KSQO           "Ksqo"      /* Keyset query
+                            * optimization */
+#define ABBR_KSQO          "B5"
+#define INI_CONNSETTINGS        "ConnSettings" /* Anything to send to
+                            * backend on successful
+                            * connection */
+#define ABBR_CONNSETTINGS   "A6"
+#define INI_UNIQUEINDEX            "UniqueIndex"   /* Recognize unique
+                            * indexes */
+#define INI_UNKNOWNSIZES       "UnknownSizes"  /* How to handle unknown
+                            * result set sizes */
+#define ABBR_UNKNOWNSIZES      "A9"
+
 #define INI_CANCELASFREESTMT       "CancelAsFreeStmt"
-#define INI_USEDECLAREFETCH        "UseDeclareFetch"   /* Use Declare/Fetch cursors */
+#define ABBR_CANCELASFREESTMT  "C1"
+#define INI_USEDECLAREFETCH        "UseDeclareFetch"   /* Use Declare/Fetch
+                                * cursors */
+#define ABBR_USEDECLAREFETCH       "B6"
 
 /* More ini stuff */
 #define INI_TEXTASLONGVARCHAR      "TextAsLongVarchar"
+#define ABBR_TEXTASLONGVARCHAR     "B7"
 #define INI_UNKNOWNSASLONGVARCHAR  "UnknownsAsLongVarchar"
+#define ABBR_UNKNOWNSASLONGVARCHAR "B8"
 #define INI_BOOLSASCHAR            "BoolsAsChar"
+#define ABBR_BOOLSASCHAR       "B9"
 #define INI_MAXVARCHARSIZE     "MaxVarcharSize"
+#define ABBR_MAXVARCHARSIZE        "B0"
 #define INI_MAXLONGVARCHARSIZE     "MaxLongVarcharSize"
+#define ABBR_MAXLONGVARCHARSIZE        "B1"
 
 #define INI_FAKEOIDINDEX       "FakeOidIndex"
+#define ABBR_FAKEOIDINDEX      "A2"
 #define INI_SHOWOIDCOLUMN      "ShowOidColumn"
+#define ABBR_SHOWOIDCOLUMN     "A3"
 #define INI_ROWVERSIONING      "RowVersioning"
+#define ABBR_ROWVERSIONING     "A4"
 #define INI_SHOWSYSTEMTABLES       "ShowSystemTables"
+#define ABBR_SHOWSYSTEMTABLES      "A5"
 #define INI_LIE                "Lie"
 #define INI_PARSE          "Parse"
+#define ABBR_PARSE         "C0"
 #define INI_EXTRASYSTABLEPREFIXES  "ExtraSysTablePrefixes"
+#define ABBR_EXTRASYSTABLEPREFIXES "C2"
 
 #define INI_TRANSLATIONNAME        "TranslationName"
 #define INI_TRANSLATIONDLL     "TranslationDLL"
 #define INI_TRANSLATIONOPTION      "TranslationOption"
 #define INI_DISALLOWPREMATURE      "DisallowPremature"
+#define ABBR_DISALLOWPREMATURE     "C3"
 #define INI_UPDATABLECURSORS       "UpdatableCursors"
+#define ABBR_UPDATABLECURSORS      "C4"
 #define INI_LFCONVERSION       "LFConversion"
+#define ABBR_LFCONVERSION      "C5"
 #define INI_TRUEISMINUS1       "TrueIsMinus1"
+#define ABBR_TRUEISMINUS1      "C6"
 #define INI_INT8AS         "BI"
 #define INI_BYTEAASLONGVARBINARY   "ByteaAsLongVarBinary"
+#define ABBR_BYTEAASLONGVARBINARY  "C7"
 #define INI_USESERVERSIDEPREPARE   "UseServerSidePrepare"
+#define ABBR_USESERVERSIDEPREPARE  "C8"
 #define INI_LOWERCASEIDENTIFIER        "LowerCaseIdentifier"
+#define ABBR_LOWERCASEIDENTIFIER   "C9"
+#define INI_SSLMODE            "SSLmode"
+#define ABBR_SSLMODE           "CA"
+#define INI_FORCEABBREVCONNSTR     "AB"
 
+#define    SSLMODE_DISABLE     "disable"
+#define    SSLMODE_ALLOW       "allow"
+#define    SSLMODE_PREFER      "prefer"
+#define    SSLMODE_REQUIRE     "require"
+
+#ifdef _HANDLE_ENLIST_IN_DTC_
+#define INI_XAOPT          "XaOpt"
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
 /* Bit representaion for abbreviated connection strings */
-#define BIT_LFCONVERSION       (1L)
-#define BIT_UPDATABLECURSORS       (1L<<1)
-#define BIT_DISALLOWPREMATURE      (1L<<2)
-#define BIT_UNIQUEINDEX            (1L<<3)
-#define BIT_UNKNOWN_DONTKNOW       (1L<<6)
-#define BIT_UNKNOWN_ASMAX      (1L<<7)
-#define BIT_OPTIMIZER          (1L<<8)
-#define BIT_KSQO           (1L<<9)
-#define BIT_COMMLOG            (1L<<10)
-#define BIT_DEBUG          (1L<<11)
-#define BIT_PARSE          (1L<<12)
-#define BIT_CANCELASFREESTMT       (1L<<13)
-#define BIT_USEDECLAREFETCH        (1L<<14)
-#define BIT_READONLY           (1L<<15)
-#define BIT_TEXTASLONGVARCHAR      (1L<<16)
-#define BIT_UNKNOWNSASLONGVARCHAR  (1L<<17)
-#define BIT_BOOLSASCHAR            (1L<<18)
-#define BIT_ROWVERSIONING      (1L<<19)
-#define BIT_SHOWSYSTEMTABLES       (1L<<20)
-#define BIT_SHOWOIDCOLUMN      (1L<<21)
-#define BIT_FAKEOIDINDEX       (1L<<22)
-#define BIT_TRUEISMINUS1       (1L<<23)
-#define BIT_BYTEAASLONGVARBINARY   (1L<<24)
-#define BIT_USESERVERSIDEPREPARE   (1L<<25)
-#define BIT_LOWERCASEIDENTIFIER        (1L<<26)
-
-#define EFFECTIVE_BIT_COUNT        27
+#define BIT_LFCONVERSION           (1L)
+#define BIT_UPDATABLECURSORS           (1L<<1)
+#define BIT_DISALLOWPREMATURE          (1L<<2)
+#define BIT_UNIQUEINDEX                (1L<<3)
+#define BIT_PROTOCOL_63                (1L<<4)
+#define BIT_PROTOCOL_64                (1L<<5)
+#define BIT_UNKNOWN_DONTKNOW           (1L<<6)
+#define BIT_UNKNOWN_ASMAX          (1L<<7)
+#define BIT_OPTIMIZER              (1L<<8)
+#define BIT_KSQO               (1L<<9)
+#define BIT_COMMLOG                (1L<<10)
+#define BIT_DEBUG              (1L<<11)
+#define BIT_PARSE              (1L<<12)
+#define BIT_CANCELASFREESTMT           (1L<<13)
+#define BIT_USEDECLAREFETCH            (1L<<14)
+#define BIT_READONLY               (1L<<15)
+#define BIT_TEXTASLONGVARCHAR          (1L<<16)
+#define BIT_UNKNOWNSASLONGVARCHAR      (1L<<17)
+#define BIT_BOOLSASCHAR                (1L<<18)
+#define BIT_ROWVERSIONING          (1L<<19)
+#define BIT_SHOWSYSTEMTABLES           (1L<<20)
+#define BIT_SHOWOIDCOLUMN          (1L<<21)
+#define BIT_FAKEOIDINDEX           (1L<<22)
+#define BIT_TRUEISMINUS1           (1L<<23)
+#define BIT_BYTEAASLONGVARBINARY       (1L<<24)
+#define BIT_USESERVERSIDEPREPARE       (1L<<25)
+#define BIT_LOWERCASEIDENTIFIER            (1L<<26)
+
+#define EFFECTIVE_BIT_COUNT            27
 
 
 /* Connection Defaults */
-#define DEFAULT_PORT           "5432"
-#define DEFAULT_SSLMODE         "prefer"
-#define DEFAULT_READONLY       0
-#define DEFAULT_USEDECLAREFETCH        0
-#define DEFAULT_TEXTASLONGVARCHAR  1
-#define DEFAULT_UNKNOWNSASLONGVARCHAR  0
-#define DEFAULT_BOOLSASCHAR        1
-#define DEFAULT_OPTIMIZER      1   /* disable */
-#define DEFAULT_KSQO           1   /* on */
-#define DEFAULT_UNIQUEINDEX        1   /* dont recognize */
-#define DEFAULT_COMMLOG            0   /* dont log */
-#define DEFAULT_DEBUG          0
-#define DEFAULT_UNKNOWNSIZES       UNKNOWNS_AS_MAX
-
-
-#define DEFAULT_FAKEOIDINDEX       0
-#define DEFAULT_SHOWOIDCOLUMN      0
-#define DEFAULT_ROWVERSIONING      0
-#define DEFAULT_SHOWSYSTEMTABLES   0   /* dont show system tables */
-#define DEFAULT_LIE            0
-#define DEFAULT_PARSE          0
-
-#define DEFAULT_CANCELASFREESTMT   0
+#define DEFAULT_PORT               "5432"
+#define DEFAULT_READONLY           0
+#define DEFAULT_PROTOCOL           "7.4"   /* the latest protocol is
+                                                * the default */
+#define DEFAULT_USEDECLAREFETCH            0
+#define DEFAULT_TEXTASLONGVARCHAR      1
+#define DEFAULT_UNKNOWNSASLONGVARCHAR      0
+#define DEFAULT_BOOLSASCHAR            1
+#define DEFAULT_OPTIMIZER          1       /* disable */
+#define DEFAULT_KSQO               1       /* on */
+#define DEFAULT_UNIQUEINDEX            1       /* dont recognize */
+#define DEFAULT_COMMLOG                0       /* dont log */
+#define DEFAULT_DEBUG              0
+#define DEFAULT_UNKNOWNSIZES           UNKNOWNS_AS_MAX
+
+
+#define DEFAULT_FAKEOIDINDEX           0
+#define DEFAULT_SHOWOIDCOLUMN          0
+#define DEFAULT_ROWVERSIONING          0
+#define DEFAULT_SHOWSYSTEMTABLES       0       /* dont show system tables */
+#define DEFAULT_LIE                0
+#define DEFAULT_PARSE              0
+
+#define DEFAULT_CANCELASFREESTMT       0
 
 #define DEFAULT_EXTRASYSTABLEPREFIXES  "dd_;"
 
 #define DEFAULT_DISALLOWPREMATURE  0
 #define DEFAULT_TRUEISMINUS1       0
-#ifdef DRIVER_CURSOR_IMPLEMENT
-#define DEFAULT_UPDATABLECURSORS   0   /* Made non-default due to stability issues - DJP, 2004-1004 */
-#else
-#define DEFAULT_UPDATABLECURSORS   0
-#endif /* DRIVER_CURSOR_IMPLEMENT */
+#define DEFAULT_UPDATABLECURSORS   1
 #ifdef WIN32
 #define DEFAULT_LFCONVERSION       1
 #else
 #define DEFAULT_BYTEAASLONGVARBINARY   0
 #define DEFAULT_USESERVERSIDEPREPARE   0
 #define DEFAULT_LOWERCASEIDENTIFIER    0
+#define DEFAULT_SSLMODE            SSLMODE_DISABLE
+
+#ifdef _HANDLE_ENLIST_IN_DTC_
+#define DEFAULT_XAOPT          0
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
 
 /* prototypes */
 void       getCommonDefaults(const char *section, const char *filename, ConnInfo *ci);
@@ -193,14 +254,15 @@ int CALLBACK manage_dsnProc(HWND hdlg,
               LPARAM lParam);
 #endif   /* WIN32 */
 
-void   updateGlobals(void);
-void   writeDriverCommoninfo(const char *fileName, const char *sectionName, const GLOBAL_VALUES *);
-void   writeDSNinfo(const ConnInfo *ci);
-void   getDSNdefaults(ConnInfo *ci);
-void   getDSNinfo(ConnInfo *ci, char overwrite);
-void   makeConnectString(char *connect_string, const ConnInfo *ci, UWORD);
-void   copyAttributes(ConnInfo *ci, const char *attribute, const char *value);
-void   copyCommonAttributes(ConnInfo *ci, const char *attribute, const char *value);
+void       updateGlobals(void);
+void       writeDriverCommoninfo(const char *fileName, const char *sectionName,
+       const GLOBAL_VALUES *);
+void       writeDSNinfo(const ConnInfo *ci);
+void       getDSNdefaults(ConnInfo *ci);
+void       getDSNinfo(ConnInfo *ci, char overwrite);
+void       makeConnectString(char *connect_string, const ConnInfo *ci, UWORD);
+void       copyAttributes(ConnInfo *ci, const char *attribute, const char *value);
+void       copyCommonAttributes(ConnInfo *ci, const char *attribute, const char *value);
 int    getDriverNameFromDSN(const char *dsn, char *driver_name, int namelen);
 int     changeDriverNameOfaDSN(const char *dsn, const char *driver_name, DWORD *errcode);
 
index e69cbab69c63ae61fc2cdc5b63ea0320d0c8e5fa..5b42ac80af93e4800ba744287a636c1233d8b9a0 100644 (file)
 #include "win_setup.h"
 
 #include "convert.h"
+#include "loadlib.h"
 
 #include "multibyte.h"
 #include "pgapifunc.h"
 
-#ifndef BOOL
-#define BOOL   int
-#endif
-#ifndef FALSE
-#define FALSE  (BOOL)0
-#endif
-#ifndef TRUE
-#define TRUE   (BOOL)1
-#endif
-
 extern GLOBAL_VALUES globals;
 
 extern HINSTANCE NEAR s_hModule;
@@ -45,17 +36,15 @@ static int  driver_options_update(HWND hdlg, ConnInfo *ci, const char *);
 void
 SetDlgStuff(HWND hdlg, const ConnInfo *ci)
 {
-   char buff[MEDIUM_REGISTRY_LEN+1]; 
+   char    buff[MEDIUM_REGISTRY_LEN + 1];
+   BOOL    libpq_exist = FALSE;
 
    /*
     * If driver attribute NOT present, then set the datasource name and
     * description
     */
-   /**if (ci->driver[0] == '\0')
-   {**/
-       SetDlgItemText(hdlg, IDC_DSNAME, ci->dsn);
-       SetDlgItemText(hdlg, IDC_DESC, ci->desc);
-   /**}**/
+   SetDlgItemText(hdlg, IDC_DSNAME, ci->dsn);
+   SetDlgItemText(hdlg, IDC_DESC, ci->desc);
 
    SetDlgItemText(hdlg, IDC_DATABASE, ci->database);
    SetDlgItemText(hdlg, IDC_SERVER, ci->server);
@@ -63,34 +52,43 @@ SetDlgStuff(HWND hdlg, const ConnInfo *ci)
    SetDlgItemText(hdlg, IDC_PASSWORD, ci->password);
    SetDlgItemText(hdlg, IDC_PORT, ci->port);
 
-   LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_PREFER, buff, MEDIUM_REGISTRY_LEN);
-   SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
-   LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_ALLOW, buff, MEDIUM_REGISTRY_LEN);
-   SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
-   LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_REQUIRE, buff, MEDIUM_REGISTRY_LEN);
-   SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
+   libpq_exist = LIBPQ_check();
+mylog("libpq_exist=%d\n", libpq_exist);
+   if (libpq_exist)
+       ShowWindow(GetDlgItem(hdlg, IDC_NOTICE_USER), SW_HIDE);
+   else
+   {
+mylog("SendMessage CTL_COLOR\n");
+       SendMessage(GetDlgItem(hdlg, IDC_NOTICE_USER), WM_CTLCOLOR, 0, 0);
+   }
    LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_DISABLE, buff, MEDIUM_REGISTRY_LEN);
    SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
-
-    
-   if (!strcmp(ci->sslmode, "allow"))
+   if (libpq_exist || (ci->sslmode[0] && stricmp(ci->sslmode, "disable")))
+   {
+       LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_PREFER, buff, MEDIUM_REGISTRY_LEN);
+       SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
+       LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_ALLOW, buff, MEDIUM_REGISTRY_LEN);
+       SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
+       LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_REQUIRE, buff, MEDIUM_REGISTRY_LEN);
+       SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
+   }
+   if (!stricmp(ci->sslmode, "allow"))
        LoadString(GetWindowInstance(hdlg), IDS_SSLREQUEST_ALLOW, buff, MEDIUM_REGISTRY_LEN);
-   else if (!strcmp(ci->sslmode, "require"))
-        LoadString(GetWindowInstance(hdlg), IDS_SSLREQUEST_REQUIRE, buff, MEDIUM_REGISTRY_LEN);
-    else if (!strcmp(ci->sslmode, "disable"))
-       LoadString(GetWindowInstance(hdlg), IDS_SSLREQUEST_DISABLE, buff, MEDIUM_REGISTRY_LEN);
-    else
+   else if (!stricmp(ci->sslmode, "require"))
+       LoadString(GetWindowInstance(hdlg), IDS_SSLREQUEST_REQUIRE, buff, MEDIUM_REGISTRY_LEN);
+   else if (!stricmp(ci->sslmode, "prefer"))
        LoadString(GetWindowInstance(hdlg), IDS_SSLREQUEST_PREFER, buff, MEDIUM_REGISTRY_LEN);
+   else
+       LoadString(GetWindowInstance(hdlg), IDS_SSLREQUEST_DISABLE, buff, MEDIUM_REGISTRY_LEN);
 
    SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_SELECTSTRING, -1, (WPARAM) ((LPSTR) buff));
-
 }
 
 
 void
 GetDlgStuff(HWND hdlg, ConnInfo *ci)
 {
-   int sslposition;
+   int sslposition;
 
    GetDlgItemText(hdlg, IDC_DESC, ci->desc, sizeof(ci->desc));
 
@@ -100,17 +98,17 @@ GetDlgStuff(HWND hdlg, ConnInfo *ci)
    GetDlgItemText(hdlg, IDC_PASSWORD, ci->password, sizeof(ci->password));
    GetDlgItemText(hdlg, IDC_PORT, ci->port, sizeof(ci->port));
    sslposition = (int)(DWORD)SendMessage(GetDlgItem(hdlg, IDC_SSLMODE), CB_GETCURSEL, 0L, 0L);
-   switch(sslposition)
+   switch (sslposition)
    {
-       case 1: strcpy(ci->sslmode, "allow");
-               break;
-       case 2: strcpy(ci->sslmode, "require");
-               break;
-       case 3: strcpy(ci->sslmode, "disable");
-               break;
-       default: strcpy(ci->sslmode, "prefer");
+       case 1: strcpy(ci->sslmode, "prefer");
+           break;
+       case 2: strcpy(ci->sslmode, "allow");
+           break;
+       case 3: strcpy(ci->sslmode, "require");
+           break;
+       default:strcpy(ci->sslmode, "disable");
+           break;
    }
-
 }
 
 
@@ -456,6 +454,31 @@ ds_options2Proc(HWND hdlg,
            /* Readonly */
            CheckDlgButton(hdlg, DS_READONLY, atoi(ci->onlyread));
 
+           /* Protocol */
+           if (PROTOCOL_62(ci))
+               CheckDlgButton(hdlg, DS_PG62, 1);
+           else if (PROTOCOL_63(ci))
+               CheckDlgButton(hdlg, DS_PG63, 1);
+           else if (PROTOCOL_64(ci))
+               CheckDlgButton(hdlg, DS_PG64, 1);
+           else
+               /* latest */
+               CheckDlgButton(hdlg, DS_PG74, 1);
+
+           /* How to issue Rollback */
+           switch (ci->rollback_on_error)
+           {
+               case 0:
+                   CheckDlgButton(hdlg, DS_NO_ROLLBACK, 1);
+                   break;
+               case 1:
+                   CheckDlgButton(hdlg, DS_TRANSACTION_ROLLBACK, 1);
+                   break;
+               case 2:
+                   CheckDlgButton(hdlg, DS_STATEMENT_ROLLBACK, 1);
+                   break;
+           }
+
            /* Int8 As */
            switch (ci->int8_as)
            {
@@ -486,9 +509,6 @@ ds_options2Proc(HWND hdlg,
            CheckDlgButton(hdlg, DS_LFCONVERSION, ci->lf_conversion);
            CheckDlgButton(hdlg, DS_TRUEISMINUS1, ci->true_is_minus1);
            CheckDlgButton(hdlg, DS_UPDATABLECURSORS, ci->allow_keyset);
-#ifndef DRIVER_CURSOR_IMPLEMENT
-           EnableWindow(GetDlgItem(hdlg, DS_UPDATABLECURSORS), FALSE);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
            CheckDlgButton(hdlg, DS_SERVERSIDEPREPARE, ci->use_server_side_prepare);
            CheckDlgButton(hdlg, DS_BYTEAASLONGVARBINARY, ci->bytea_as_longvarbinary);
            /*CheckDlgButton(hdlg, DS_LOWERCASEIDENTIFIER, ci->lower_case_identifier);*/
@@ -511,11 +531,33 @@ ds_options2Proc(HWND hdlg,
                case IDAPPLY:
                case IDPREVPAGE:
                    ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER);
-                   mylog("IDOK: got ci = %u\n", ci);
+                   mylog("IDOK: got ci = %x\n", ci);
 
                    /* Readonly */
                    sprintf(ci->onlyread, "%d", IsDlgButtonChecked(hdlg, DS_READONLY));
 
+                   /* Protocol */
+                   if (IsDlgButtonChecked(hdlg, DS_PG62))
+                       strcpy(ci->protocol, PG62);
+                   else if (IsDlgButtonChecked(hdlg, DS_PG63))
+                       strcpy(ci->protocol, PG63);
+                   else if (IsDlgButtonChecked(hdlg, DS_PG64))
+                       strcpy(ci->protocol, PG64);
+                   else
+                       /* latest */
+                       strcpy(ci->protocol, PG74);
+
+                   /* Issue rollback command on error */
+                   if (IsDlgButtonChecked(hdlg, DS_NO_ROLLBACK))
+                       ci->rollback_on_error = 0;
+                   else if (IsDlgButtonChecked(hdlg, DS_TRANSACTION_ROLLBACK))
+                       ci->rollback_on_error = 1;
+                   else if (IsDlgButtonChecked(hdlg, DS_STATEMENT_ROLLBACK))
+                       ci->rollback_on_error = 2;
+                   else
+                       /* legacy */
+                       ci->rollback_on_error = 1;
+
                    /* Int8 As */
                    if (IsDlgButtonChecked(hdlg, DS_INT8_AS_DEFAULT))
                        ci->int8_as = 0;
@@ -536,9 +578,7 @@ ds_options2Proc(HWND hdlg,
                    ci->disallow_premature = IsDlgButtonChecked(hdlg, DS_DISALLOWPREMATURE);
                    ci->lf_conversion = IsDlgButtonChecked(hdlg, DS_LFCONVERSION);
                    ci->true_is_minus1 = IsDlgButtonChecked(hdlg, DS_TRUEISMINUS1);
-#ifdef DRIVER_CURSOR_IMPLEMENT
                    ci->allow_keyset = IsDlgButtonChecked(hdlg, DS_UPDATABLECURSORS);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
                    ci->use_server_side_prepare = IsDlgButtonChecked(hdlg, DS_SERVERSIDEPREPARE);
                    ci->bytea_as_longvarbinary = IsDlgButtonChecked(hdlg, DS_BYTEAASLONGVARBINARY);
                    /*ci->lower_case_identifier = IsDlgButtonChecked(hdlg, DS_LOWERCASEIDENTIFIER);*/
index 26378558280e48ee62ebb56088b92d2d63a228f6..1be465156ae5be670b94e020fa4072c0a515bb6d 100644 (file)
--- a/drvconn.c
+++ b/drvconn.c
 
 #include <stdio.h>
 #include <stdlib.h>
+
 #include "connection.h"
 
 #ifndef WIN32
 #include <sys/types.h>
+#include <sys/socket.h>
 #define NEAR
+#else
+#include <winsock.h>
 #endif
 
 #include <string.h>
 #endif
 #include "pgapifunc.h"
 
-#ifndef TRUE
-#define TRUE   (BOOL)1
-#endif
-#ifndef FALSE
-#define FALSE  (BOOL)0
-#endif
-
 #include "dlg_specific.h"
 
 #define    NULL_IF_NULL(a) (a ? a : "(NULL)")
@@ -61,8 +58,8 @@ static char * hide_password(const char *str)
 }
 
 /* prototypes */
-void       dconn_get_connect_attributes(const UCHAR FAR * connect_string, ConnInfo *ci);
-static void dconn_get_common_attributes(const UCHAR FAR * connect_string, ConnInfo *ci);
+void       dconn_get_connect_attributes(const SQLCHAR FAR * connect_string, ConnInfo *ci);
+static void dconn_get_common_attributes(const SQLCHAR FAR * connect_string, ConnInfo *ci);
 
 #ifdef WIN32
 BOOL FAR PASCAL dconn_FDriverConnectProc(HWND hdlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
@@ -76,12 +73,12 @@ RETCODE     SQL_API
 PGAPI_DriverConnect(
                    HDBC hdbc,
                    HWND hwnd,
-                   UCHAR FAR * szConnStrIn,
-                   SWORD cbConnStrIn,
-                   UCHAR FAR * szConnStrOut,
-                   SWORD cbConnStrOutMax,
-                   SWORD FAR * pcbConnStrOut,
-                   UWORD fDriverCompletion)
+                   const SQLCHAR FAR * szConnStrIn,
+                   SQLSMALLINT cbConnStrIn,
+                   SQLCHAR FAR * szConnStrOut,
+                   SQLSMALLINT cbConnStrOutMax,
+                   SQLSMALLINT FAR * pcbConnStrOut,
+                   SQLUSMALLINT fDriverCompletion)
 {
    CSTR func = "PGAPI_DriverConnect";
    ConnectionClass *conn = (ConnectionClass *) hdbc;
@@ -90,8 +87,9 @@ PGAPI_DriverConnect(
 #ifdef WIN32
    RETCODE     dialog_result;
 #endif
+   BOOL        paramRequired;
    RETCODE     result;
-   char       *connStrIn;
+   char        *connStrIn = NULL;
    char        connStrOut[MAX_CONNECT_STRING];
    int         retval;
    char        salt[5];
@@ -112,14 +110,14 @@ PGAPI_DriverConnect(
 
 #ifdef FORCE_PASSWORD_DISPLAY
    mylog("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, connStrIn);
-   qlog("conn=%u, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, connStrIn, fDriverCompletion);
+   qlog("conn=%x, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, connStrIn, fDriverCompletion);
 #else
    if (get_qlog() || get_mylog())
    {
        char    *hide_str = hide_password(connStrIn);
 
        mylog("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, NULL_IF_NULL(hide_str));
-       qlog("conn=%u, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, NULL_IF_NULL(hide_str), fDriverCompletion);
+       qlog("conn=%x, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, NULL_IF_NULL(hide_str), fDriverCompletion);
        if (hide_str)
            free(hide_str);
    }
@@ -138,9 +136,16 @@ PGAPI_DriverConnect(
    getDSNinfo(ci, CONN_DONT_OVERWRITE);
    dconn_get_common_attributes(connStrIn, ci);
    logs_on_off(1, ci->drivers.debug, ci->drivers.commlog);
+   if (connStrIn)
+   {
+       free(connStrIn);
+       connStrIn = NULL;
+   }
 
    /* Fill in any default parameters if they are not there. */
    getDSNdefaults(ci);
+   /* initialize pg_version */
+   CC_initialize_pg_version(conn);
    salt[0] = '\0';
 
 #ifdef WIN32
@@ -148,6 +153,7 @@ dialog:
 #endif
    ci->focus_password = password_required;
 
+inolog("DriverCompletion=%d\n", fDriverCompletion);
    switch (fDriverCompletion)
    {
 #ifdef WIN32
@@ -163,7 +169,9 @@ dialog:
 
        case SQL_DRIVER_COMPLETE:
 
+           paramRequired = password_required;
            /* Password is not a required parameter. */
+#ifdef NOT_USED
            if (ci->username[0] == '\0' ||
 #ifdef WIN32
                ci->server[0] == '\0' ||
@@ -171,6 +179,18 @@ dialog:
                ci->database[0] == '\0' ||
                ci->port[0] == '\0' ||
                password_required)
+#endif /* NOT_USED */
+           if (ci->database[0] == '\0')
+               paramRequired = TRUE;
+           else if (ci->port[0] == '\0')
+               paramRequired = TRUE;
+#ifdef WIN32
+           else if (ci->server[0] == '\0')
+               paramRequired = TRUE;
+#endif /* WIN32 */
+           else if (ci->username[0] == '\0' && 'd' == ci->sslmode[0])
+               paramRequired = TRUE;
+           if (paramRequired)
            {
                dialog_result = dconn_DoDialog(hwnd, ci);
                if (dialog_result != SQL_SUCCESS)
@@ -192,18 +212,33 @@ dialog:
     * over and over until a password is entered (the user can always hit
     * Cancel to get out)
     */
+#ifdef NOT_USED
    if (ci->username[0] == '\0' ||
 #ifdef WIN32
        ci->server[0] == '\0' ||
 #endif /* WIN32 */
        ci->database[0] == '\0' ||
        ci->port[0] == '\0')
+#endif /* NOT_USED */
+   paramRequired = FALSE;
+   if (ci->database[0] == '\0')
+       paramRequired = TRUE;
+   else if (ci->port[0] == '\0')
+       paramRequired = TRUE;
+#ifdef WIN32
+   else if (ci->server[0] == '\0')
+       paramRequired = TRUE;
+#endif /* WIN32 */
+   else if (ci->username[0] == '\0' && 'd' == ci->sslmode[0])
+       paramRequired = TRUE;
+   if (paramRequired)
    {
        /* (password_required && ci->password[0] == '\0')) */
 
        return SQL_NO_DATA_FOUND;
    }
 
+inolog("before CC_connect\n");
    /* do the actual connect */
    retval = CC_connect(conn, password_required, salt);
    if (retval < 0)
@@ -253,21 +288,17 @@ dialog:
         * applications (Access) by implementing the correct behavior,
         * anyway.
         */
-       strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax);
+       /*strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax);*/
+       strncpy(szConnStrOut, connStrOut, cbConnStrOutMax);
 
-       if (cbConnStrOutMax == 0)
-           szConnStrOut = NULL;    
-       else
+       if (len >= cbConnStrOutMax)
        {
-           if (len >= cbConnStrOutMax)
-           {
-               int         clen;
+           int         clen;
 
-               for (clen = strlen(szConnStrOut) - 1; clen >= 0 && szConnStrOut[clen] != ';'; clen--)
-                   szConnStrOut[clen] = '\0';
-               result = SQL_SUCCESS_WITH_INFO;
-               CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the ConnStrOut.");
-           }
+           for (clen = cbConnStrOutMax - 1; clen >= 0 && szConnStrOut[clen] != ';'; clen--)
+               szConnStrOut[clen] = '\0';
+           result = SQL_SUCCESS_WITH_INFO;
+           CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the ConnStrOut.", func);
        }
    }
 
@@ -275,24 +306,27 @@ dialog:
        *pcbConnStrOut = len;
 
 #ifdef FORCE_PASSWORD_DISPLAY
-   mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(szConnStrOut), len, cbConnStrOutMax);
-   qlog("conn=%u, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL(szConnStrOut));
+   if (cbConnStrOutMax > 0)
+   {
+       mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(szConnStrOut), len, cbConnStrOutMax);
+       qlog("conn=%x, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL(szConnStrOut));
+   }
 #else
    if (get_qlog() || get_mylog())
    {
-       char    *hide_str = hide_password(szConnStrOut);
+       char    *hide_str = NULL;
 
+       if (cbConnStrOutMax > 0)
+           hide_str = hide_password(szConnStrOut);
        mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(hide_str), len, cbConnStrOutMax);
-       qlog("conn=%u, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL(hide_str));
+       qlog("conn=%x, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL(hide_str));
        if (hide_str)
            free(hide_str);
    }
 #endif /* FORCE_PASSWORD_DISPLAY */
 
-
    if (connStrIn)
        free(connStrIn);
-
    mylog("PGAPI_DriverConnect: returning %d\n", result);
    return result;
 }
@@ -304,7 +338,7 @@ dconn_DoDialog(HWND hwnd, ConnInfo *ci)
 {
    int         dialog_result;
 
-   mylog("dconn_DoDialog: ci = %u\n", ci);
+   mylog("dconn_DoDialog: ci = %x\n", ci);
 
    if (hwnd)
    {
@@ -395,21 +429,20 @@ dconn_FDriverConnectProc(
 #endif   /* WIN32 */
 
 
-void
-dconn_get_connect_attributes(const UCHAR FAR * connect_string, ConnInfo *ci)
+typedef    void (*copyfunc)(ConnInfo *, const char *attribute, const char *value);
+static void
+dconn_get_attributes(copyfunc func, const SQLCHAR FAR * connect_string, ConnInfo *ci)
 {
    char       *our_connect_string;
-   char       *pair,
+   const   char       *pair,
               *attribute,
-              *value,
-              *equals;
+              *value;
+   char    *equals;
    char       *strtok_arg;
 #ifdef HAVE_STRTOK_R
    char       *last;
 #endif /* HAVE_STRTOK_R */
 
-   CC_conninfo_init(ci);
-
    our_connect_string = strdup(connect_string);
    strtok_arg = our_connect_string;
 
@@ -457,76 +490,23 @@ dconn_get_connect_attributes(const UCHAR FAR * connect_string, ConnInfo *ci)
            continue;
 
        /* Copy the appropriate value to the conninfo  */
-       copyAttributes(ci, attribute, value);
+       (*func)(ci, attribute, value);
 
    }
 
    free(our_connect_string);
 }
 
-static void
-dconn_get_common_attributes(const UCHAR FAR * connect_string, ConnInfo *ci)
+void
+dconn_get_connect_attributes(const SQLCHAR FAR * connect_string, ConnInfo *ci)
 {
-   char       *our_connect_string;
-   char       *pair,
-              *attribute,
-              *value,
-              *equals;
-   char       *strtok_arg;
-#ifdef HAVE_STRTOK_R
-   char       *last;
-#endif /* HAVE_STRTOK_R */
-
-   our_connect_string = strdup(connect_string);
-   strtok_arg = our_connect_string;
-
-#ifdef FORCE_PASSWORD_DISPLAY
-   mylog("our_connect_string = '%s'\n", our_connect_string);
-#else
-   if (get_mylog())
-   {
-       char    *hide_str = hide_password(our_connect_string);
 
-       mylog("our_connect_string = '%s'\n", hide_str);
-       free(hide_str);
-   }
-#endif /* FORCE_PASSWORD_DISPLAY */
-
-   while (1)
-   {
-#ifdef HAVE_STRTOK_R
-       pair = strtok_r(strtok_arg, ";", &last);
-#else
-       pair = strtok(strtok_arg, ";");
-#endif /* HAVE_STRTOK_R */
-       if (strtok_arg)
-           strtok_arg = 0;
-       if (!pair)
-           break;
-
-       equals = strchr(pair, '=');
-       if (!equals)
-           continue;
-
-       *equals = '\0';
-       attribute = pair;       /* ex. DSN */
-       value = equals + 1;     /* ex. 'CEO co1' */
-
-#ifndef    FORCE_PASSWORD_DISPLAY
-       if (stricmp(attribute, INI_PASSWORD) == 0 ||
-           stricmp(attribute, "pwd") == 0)
-           mylog("attribute = '%s', value = 'xxxxx'\n", attribute);
-       else
-#endif /* FORCE_PASSWORD_DISPLAY */
-           mylog("attribute = '%s', value = '%s'\n", attribute, value);
-
-       if (!attribute || !value)
-           continue;
-
-       /* Copy the appropriate value to the conninfo  */
-       copyCommonAttributes(ci, attribute, value);
-
-   }
+   CC_conninfo_init(ci);
+   dconn_get_attributes(copyAttributes, connect_string, ci);
+}
 
-   free(our_connect_string);
+static void
+dconn_get_common_attributes(const SQLCHAR FAR * connect_string, ConnInfo *ci)
+{
+   dconn_get_attributes(copyCommonAttributes, connect_string, ci);
 }
index 70d500e58c45d29a6bfa6dbde44491321cad6ab9..b25e793ddf4e832d784b31cdcc39f904f04ae8e1 100644 (file)
--- a/environ.c
+++ b/environ.c
@@ -14,6 +14,7 @@
  */
 
 #include "environ.h"
+
 #include "connection.h"
 #include "dlg_specific.h"
 #include "statement.h"
@@ -27,8 +28,10 @@ extern GLOBAL_VALUES globals;
 ConnectionClass *conns[MAX_CONNECTIONS];
 #if defined(WIN_MULTITHREAD_SUPPORT)
 CRITICAL_SECTION   conns_cs;
+CRITICAL_SECTION   common_cs; /* commonly used for short term blocking */
 #elif defined(POSIX_MULTITHREAD_SUPPORT)
 pthread_mutex_t     conns_cs;
+pthread_mutex_t     common_cs;
 #endif /* WIN_MULTITHREAD_SUPPORT */
 
 
@@ -60,7 +63,7 @@ PGAPI_AllocEnv(HENV FAR * phenv)
        return SQL_ERROR;
    }
 
-   mylog("** exit PGAPI_AllocEnv: phenv = %u **\n", *phenv);
+   mylog("** exit PGAPI_AllocEnv: phenv = %x **\n", *phenv);
    return SQL_SUCCESS;
 }
 
@@ -71,7 +74,7 @@ PGAPI_FreeEnv(HENV henv)
    CSTR func = "PGAPI_FreeEnv";
    EnvironmentClass *env = (EnvironmentClass *) henv;
 
-   mylog("**** in PGAPI_FreeEnv: env = %u ** \n", env);
+   mylog("**** in PGAPI_FreeEnv: env = %x ** \n", env);
 
    if (env && EN_Destructor(env))
    {
@@ -121,41 +124,59 @@ PG_ErrorInfo  *ER_Constructor(SDWORD errnumber, const char *msg)
    }
    return error;
 }
+
 void
 ER_Destructor(PG_ErrorInfo *self)
 {
-        if (self->__error_message)
-                free(self->__error_message);
    free(self);
 }
 
+PG_ErrorInfo *ER_Dup(const PG_ErrorInfo *self)
+{
+   PG_ErrorInfo    *new;
+   Int4        alsize;
+
+   if (!self)
+       return NULL;
+   alsize = sizeof(PG_ErrorInfo);
+   if (self->errorsize  > 0)
+       alsize += self->errorsize;
+   new = (PG_ErrorInfo *) malloc(alsize);
+   memcpy(new, self, alsize);
+
+   return new;
+}
+
 #define    DRVMNGRDIV  511
 /*     Returns the next SQL error information. */
 RETCODE        SQL_API
-ER_ReturnError(PG_ErrorInfo *error,
-       SWORD   RecNumber,
-       UCHAR FAR * szSqlState,
-       SDWORD FAR * pfNativeError,
-       UCHAR FAR * szErrorMsg,
-       SWORD cbErrorMsgMax,
-       SWORD FAR * pcbErrorMsg,
+ER_ReturnError(PG_ErrorInfo **pgerror,
+       SQLSMALLINT RecNumber,
+       SQLCHAR FAR * szSqlState,
+       SQLINTEGER FAR * pfNativeError,
+       SQLCHAR FAR * szErrorMsg,
+       SQLSMALLINT cbErrorMsgMax,
+       SQLSMALLINT FAR * pcbErrorMsg,
        UWORD flag)
 {
+   CSTR func = "ER_ReturnError";
    /* CC: return an error of a hstmt  */
+   PG_ErrorInfo    *error;
    BOOL        partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
            clear_str = ((flag & PODBC_ERROR_CLEAR) != 0);
    const char  *msg;
    SWORD       msglen, stapos, wrtlen, pcblen;
 
-   if (!error)
+   if (!pgerror || !*pgerror)
        return SQL_NO_DATA_FOUND;
+   error = *pgerror;
    msg = error->__error_message;
-   mylog("ER_GetError: status = %d, msg = #%s#\n", error->status, msg);
-   msglen = (SWORD) strlen(msg);
+   mylog("%s: status = %d, msg = #%s#\n", func, error->status, msg);
+   msglen = (SQLSMALLINT) strlen(msg);
    /*
     *  Even though an application specifies a larger error message
     *  buffer, the driver manager changes it silently.
-    *  Therefore we divide the error message into ...
+    *  Therefore we divide the error message into ... 
     */
    if (error->recsize < 0)
    {
@@ -173,19 +194,19 @@ ER_ReturnError(PG_ErrorInfo *error,
    }
    stapos = (RecNumber - 1) * error->recsize;
    if (stapos > msglen)
-       return SQL_NO_DATA_FOUND;
+       return SQL_NO_DATA_FOUND; 
    pcblen = wrtlen = msglen - stapos;
    if (pcblen > error->recsize)
        pcblen = error->recsize;
    if (0 == cbErrorMsgMax)
-       wrtlen = 0;
+       wrtlen = 0; 
    else if (wrtlen >= cbErrorMsgMax)
    {
        if (partial_ok)
            wrtlen = cbErrorMsgMax - 1;
        else if (cbErrorMsgMax <= error->recsize)
            wrtlen = 0;
-       else
+       else 
            wrtlen = error->recsize;
    }
    if (wrtlen > pcblen)
@@ -210,7 +231,10 @@ ER_ReturnError(PG_ErrorInfo *error,
    {
        error->errorpos = stapos + wrtlen;
        if (error->errorpos >= msglen)
+       {
            ER_Destructor(error);
+           *pgerror = NULL;
+       }
    }
    if (wrtlen == 0)
        return SQL_SUCCESS_WITH_INFO;
@@ -218,248 +242,15 @@ ER_ReturnError(PG_ErrorInfo *error,
        return SQL_SUCCESS;
 }
 
-#define    DRVMNGRDIV  511
-/*     Returns the next SQL error information. */
-RETCODE        SQL_API
-PGAPI_StmtError(   HSTMT hstmt, 
-           SWORD RecNumber,
-           SQLCHAR *szSqlState, 
-           SQLINTEGER *pfNativeError,
-           SQLCHAR *szErrorMsg, 
-           SQLSMALLINT cbErrorMsgMax,
-           SQLSMALLINT *pcbErrorMsg, 
-           UWORD flag)
-{
-   /* CC: return an error of a hstmt  */
-   StatementClass *stmt = (StatementClass *) hstmt;
-   EnvironmentClass *env = (EnvironmentClass *) SC_get_conn(stmt)->henv;
-   char        *msg;
-   int     status;
-   BOOL        partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
-           clear_str = ((flag & PODBC_ERROR_CLEAR) != 0);
-   SWORD       msglen, stapos, wrtlen, pcblen;
-
-   mylog("**** PGAPI_StmtError: hstmt=%u <%d>\n", hstmt, cbErrorMsgMax);
-
-   if (cbErrorMsgMax < 0)
-       return SQL_ERROR;
-
-   if (STMT_EXECUTING == stmt->status || !SC_get_error(stmt, &status, &msg)
-        || NULL == msg || !msg[0])
-   {
-       mylog("SC_Get_error returned nothing.\n");
-       if (NULL != szSqlState)
-           strcpy(szSqlState, "00000");
-       if (NULL != pcbErrorMsg)
-           *pcbErrorMsg = 0;
-       if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
-           szErrorMsg[0] = '\0';
-
-       return SQL_NO_DATA_FOUND;
-   }
-   mylog("SC_get_error: status = %d, msg = #%s#\n", status, msg);
-   msglen = (SWORD) strlen(msg);
-   /*
-    *  Even though an application specifies a larger error message
-    *  buffer, the driver manager changes it silently.
-    *  Therefore we divide the error message into ...
-    */
-   if (stmt->error_recsize < 0)
-   {
-       if (cbErrorMsgMax > 0)
-           stmt->error_recsize = cbErrorMsgMax - 1; /* apply the first request */
-       else
-           stmt->error_recsize = DRVMNGRDIV;
-   }
-   if (RecNumber < 0)
-   {
-       if (0 == stmt->errorpos)
-           RecNumber = 1;
-       else
-           RecNumber = 2 + (stmt->errorpos - 1) / stmt->error_recsize;
-   }
-   stapos = (RecNumber - 1) * stmt->error_recsize;
-   if (stapos > msglen)
-       return SQL_NO_DATA_FOUND;
-   pcblen = wrtlen = msglen - stapos;
-   if (pcblen > stmt->error_recsize)
-       pcblen = stmt->error_recsize;
-   if (0 == cbErrorMsgMax)
-       wrtlen = 0;
-   else if (wrtlen >= cbErrorMsgMax)
-   {
-       if (partial_ok)
-           wrtlen = cbErrorMsgMax - 1;
-       else if (cbErrorMsgMax <= stmt->error_recsize)
-           wrtlen = 0;
-       else
-           wrtlen = stmt->error_recsize;
-   }
-   if (wrtlen > pcblen)
-       wrtlen = pcblen;
-   if (NULL != pcbErrorMsg)
-       *pcbErrorMsg = pcblen;
-
-   if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
-   {
-       memcpy(szErrorMsg, msg + stapos, wrtlen);
-       szErrorMsg[wrtlen] = '\0';
-   }
-
-   if (NULL != pfNativeError)
-       *pfNativeError = status;
-
-   if (NULL != szSqlState)
-
-       if ((stmt->__sqlstate != NULL) && (stmt->__sqlstate[0] != '\0'))
-               pg_sqlstate_set(env, szSqlState, stmt->__sqlstate, stmt->__sqlstate);
-       else
-           switch (status)
-           {
-                   /* now determine the SQLSTATE to be returned */
-               case STMT_ROW_VERSION_CHANGED:
-                   pg_sqlstate_set(env, szSqlState, "01001", "01001");
-                   /* data truncated */
-                   break;
-               case STMT_TRUNCATED:
-                   pg_sqlstate_set(env, szSqlState, "01004", "01004");
-                   /* data truncated */
-                   break;
-               case STMT_INFO_ONLY:
-                   pg_sqlstate_set(env, szSqlState, "00000", "0000");
-                   /* just information that is returned, no error */
-                   break;
-               case STMT_BAD_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
-                   /* communication link failure */
-                   break;
-               case STMT_CREATE_TABLE_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "42S01", "S0001");
-                   /* table already exists */
-                   break;
-               case STMT_STATUS_ERROR:
-               case STMT_SEQUENCE_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
-                   /* Function sequence error */
-                   break;
-               case STMT_NO_MEMORY_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
-                   /* memory allocation failure */
-                   break;
-               case STMT_COLNUM_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "07009", "S1002");
-                   /* invalid column number */
-                   break;
-               case STMT_NO_STMTSTRING:
-                   pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
-                   /* having no stmtstring is also a malloc problem */
-                   break;
-               case STMT_ERROR_TAKEN_FROM_BACKEND:
-                   pg_sqlstate_set(env, szSqlState, SC_get_sqlstate(stmt), "S1000");
-                   /* Use the ODBC 3 sqlstate reported by the backend. */
-                   break;
-               case STMT_INTERNAL_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
-                   /* general error */
-                   break;
-               case STMT_FETCH_OUT_OF_RANGE:
-                   pg_sqlstate_set(env, szSqlState, "HY106", "S1106");
-                   break;
-               case STMT_ROW_OUT_OF_RANGE:
-                   pg_sqlstate_set(env, szSqlState, "HY107", "S1107");
-                   break;
-               case STMT_OPERATION_CANCELLED:
-                   pg_sqlstate_set(env, szSqlState, "HY008", "S1008");
-                   break;
-               case STMT_NOT_IMPLEMENTED_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00"); /* == 'driver not
-                                                        * capable' */
-                   break;
-               case STMT_OPTION_OUT_OF_RANGE_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "HY092", "S1092");
-                   break;
-               case STMT_BAD_PARAMETER_NUMBER_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "07009", "S1093");
-                   break;
-               case STMT_INVALID_COLUMN_NUMBER_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "07009", "S1002");
-                   break;
-               case STMT_RESTRICTED_DATA_TYPE_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "07006", "07006");
-                   break;
-               case STMT_INVALID_CURSOR_STATE_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "07005", "24000");
-                   break;
-               case STMT_ERROR_IN_ROW:
-                   pg_sqlstate_set(env, szSqlState, "01S01", "01S01");
-                   break;
-               case STMT_OPTION_VALUE_CHANGED:
-                   pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
-                   break;
-               case STMT_POS_BEFORE_RECORDSET:
-                   pg_sqlstate_set(env, szSqlState, "01S06", "01S06");
-                   break;
-               case STMT_INVALID_CURSOR_NAME:
-                   pg_sqlstate_set(env, szSqlState, "34000", "34000");
-                   break;
-               case STMT_NO_CURSOR_NAME:
-                   pg_sqlstate_set(env, szSqlState, "S1015", "S1015");
-                   break;
-               case STMT_INVALID_ARGUMENT_NO:
-                   pg_sqlstate_set(env, szSqlState, "HY024", "S1009");
-                   /* invalid argument value */
-                   break;
-               case STMT_INVALID_CURSOR_POSITION:
-                   pg_sqlstate_set(env, szSqlState, "HY109", "S1109");
-                   break;
-               case STMT_RETURN_NULL_WITHOUT_INDICATOR:
-                   pg_sqlstate_set(env, szSqlState, "22002", "22002");
-                   break;
-               case STMT_VALUE_OUT_OF_RANGE:
-                   pg_sqlstate_set(env, szSqlState, "HY019", "22003");
-                   break;
-               case STMT_OPERATION_INVALID:
-                   pg_sqlstate_set(env, szSqlState, "HY011", "S1011");
-                   break;
-               case STMT_INVALID_DESCRIPTOR_IDENTIFIER:
-                   pg_sqlstate_set(env, szSqlState, "HY091", "HY091");
-                   break;
-               case STMT_INVALID_OPTION_IDENTIFIER:
-                   pg_sqlstate_set(env, szSqlState, "HY092", "HY092");
-                   break;
-               case STMT_OPTION_NOT_FOR_THE_DRIVER:
-                   pg_sqlstate_set(env, szSqlState, "HYC00", "HYC00");
-                   break;
-               case STMT_COUNT_FIELD_INCORRECT:
-                   pg_sqlstate_set(env, szSqlState, "07002", "07002");
-                   break;
-               case STMT_EXEC_ERROR:
-               default:
-                   pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
-                   /* also a general error */
-                   break;
-           }
-   mylog("      szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, pcblen, szErrorMsg);
-   if (clear_str)
-   {
-       stmt->errorpos = stapos + wrtlen;
-       if (stmt->errorpos >= msglen)
-           SC_clear_error(stmt);
-   }
-   if (wrtlen == 0)
-       return SQL_SUCCESS_WITH_INFO;
-   else
-       return SQL_SUCCESS;
-}
 
 RETCODE        SQL_API
-PGAPI_ConnectError(HDBC hdbc, 
-           SWORD RecNumber,
-           SQLCHAR *szSqlState, 
-           SQLINTEGER *pfNativeError,
-           SQLCHAR *szErrorMsg, 
+PGAPI_ConnectError(    HDBC hdbc,
+           SQLSMALLINT RecNumber,
+           SQLCHAR FAR * szSqlState,
+           SQLINTEGER FAR * pfNativeError,
+           SQLCHAR FAR * szErrorMsg,
            SQLSMALLINT cbErrorMsgMax,
-           SQLSMALLINT *pcbErrorMsg, 
+           SQLSMALLINT FAR * pcbErrorMsg,
            UWORD flag)
 {
    ConnectionClass *conn = (ConnectionClass *) hdbc;
@@ -469,7 +260,7 @@ PGAPI_ConnectError(HDBC hdbc,
    BOOL    once_again = FALSE;
    SWORD       msglen;
 
-   mylog("**** PGAPI_ConnectError: hdbc=%u <%d>\n", hdbc, cbErrorMsgMax);
+   mylog("**** PGAPI_ConnectError: hdbc=%x <%d>\n", hdbc, cbErrorMsgMax);
    if (RecNumber != 1 && RecNumber != -1)
        return SQL_NO_DATA_FOUND;
    if (cbErrorMsgMax < 0)
@@ -503,79 +294,75 @@ PGAPI_ConnectError(HDBC hdbc,
        *pfNativeError = status;
 
    if (NULL != szSqlState)
-       if ((conn->__sqlstate != NULL) && (conn->__sqlstate[0] != '\0'))
-           pg_sqlstate_set(env, szSqlState, conn->__sqlstate, conn->__sqlstate);
-       else
-           switch (status)
-           {
-               case STMT_OPTION_VALUE_CHANGED:
-               case CONN_OPTION_VALUE_CHANGED:
-                   pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
-                   break;
-               case STMT_TRUNCATED:
-               case CONN_TRUNCATED:
-                   pg_sqlstate_set(env, szSqlState, "01004", "01004");
-                   /* data truncated */
-                   break;
-               case CONN_INIREAD_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "IM002", "IM002");
-                   /* data source not found */
-                   break;
-               case CONNECTION_SERVER_NOT_REACHED:
-               case CONN_OPENDB_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "08001", "08001");
-                   /* unable to connect to data source */
-                   break;
-               case CONN_INVALID_AUTHENTICATION:
-               case CONN_AUTH_TYPE_UNSUPPORTED:
-                   pg_sqlstate_set(env, szSqlState, "28000", "28000");
-                   break;
-               case CONN_STMT_ALLOC_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
-                   /* memory allocation failure */
-                   break;
-               case CONN_IN_USE:
-                   pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
-                   /* general error */
-                   break;
-               case CONN_UNSUPPORTED_OPTION:
-                   pg_sqlstate_set(env, szSqlState, "IM001", "IM001");
-                   /* driver does not support this function */
-               case CONN_INVALID_ARGUMENT_NO:
-                   pg_sqlstate_set(env, szSqlState, "HY009", "S1009");
-                   /* invalid argument value */
-                   break;
-               case CONN_TRANSACT_IN_PROGRES:
-                   pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
-                   /*
-                    * when the user tries to switch commit mode in a
-                    * transaction
-                    */
-                   /* -> function sequence error */
-                   break;
-               case CONN_NO_MEMORY_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
-                   break;
-               case CONN_NOT_IMPLEMENTED_ERROR:
-               case STMT_NOT_IMPLEMENTED_ERROR:
-                   pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");
-                   break;
-               case STMT_RETURN_NULL_WITHOUT_INDICATOR:
-                   pg_sqlstate_set(env, szSqlState, "22002", "22002");
-                   break;
-               case CONN_VALUE_OUT_OF_RANGE:
-               case STMT_VALUE_OUT_OF_RANGE:
-                   pg_sqlstate_set(env, szSqlState, "HY019", "22003");
-                   break;
-               case CONNECTION_COULD_NOT_SEND:
-               case CONNECTION_COULD_NOT_RECEIVE:
-                   pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
-                   break;
-               default:
-                   pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
-                   /* general error */
-                   break;
-           }
+   {
+       if (conn->sqlstate[0])
+           strcpy(szSqlState, conn->sqlstate);
+       else    
+       switch (status)
+       {
+           case CONN_OPTION_VALUE_CHANGED:
+               pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
+               break;
+           case CONN_TRUNCATED:
+               pg_sqlstate_set(env, szSqlState, "01004", "01004");
+               /* data truncated */
+               break;
+           case CONN_INIREAD_ERROR:
+               pg_sqlstate_set(env, szSqlState, "IM002", "IM002");
+               /* data source not found */
+               break;
+           case CONNECTION_SERVER_NOT_REACHED:
+           case CONN_OPENDB_ERROR:
+               pg_sqlstate_set(env, szSqlState, "08001", "08001");
+               /* unable to connect to data source */
+               break;
+           case CONN_INVALID_AUTHENTICATION:
+           case CONN_AUTH_TYPE_UNSUPPORTED:
+               pg_sqlstate_set(env, szSqlState, "28000", "28000");
+               break;
+           case CONN_STMT_ALLOC_ERROR:
+               pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
+               /* memory allocation failure */
+               break;
+           case CONN_IN_USE:
+               pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
+               /* general error */
+               break;
+           case CONN_UNSUPPORTED_OPTION:
+               pg_sqlstate_set(env, szSqlState, "IM001", "IM001");
+               /* driver does not support this function */
+           case CONN_INVALID_ARGUMENT_NO:
+               pg_sqlstate_set(env, szSqlState, "HY009", "S1009");
+               /* invalid argument value */
+               break;
+           case CONN_TRANSACT_IN_PROGRES:
+               pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
+
+               /*
+                * when the user tries to switch commit mode in a
+                * transaction
+                */
+               /* -> function sequence error */
+               break;
+           case CONN_NO_MEMORY_ERROR:
+               pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
+               break;
+           case CONN_NOT_IMPLEMENTED_ERROR:
+               pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");
+               break;
+           case CONN_VALUE_OUT_OF_RANGE:
+               pg_sqlstate_set(env, szSqlState, "HY019", "22003");
+               break;
+           case CONNECTION_COULD_NOT_SEND:
+           case CONNECTION_COULD_NOT_RECEIVE:
+               pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
+               break;
+           default:
+               pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
+               /* general error */
+               break;
+       }
+   }
 
    mylog("      szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, msglen, szErrorMsg);
    if (once_again)
@@ -588,20 +375,20 @@ PGAPI_ConnectError(HDBC hdbc,
 }
 
 RETCODE        SQL_API
-PGAPI_EnvError(        HENV henv, 
-           SWORD RecNumber,
-           SQLCHAR *szSqlState, 
-           SQLINTEGER *pfNativeError,
-           SQLCHAR *szErrorMsg, 
+PGAPI_EnvError(        HENV henv,
+           SQLSMALLINT RecNumber,
+           SQLCHAR FAR * szSqlState,
+           SQLINTEGER FAR * pfNativeError,
+           SQLCHAR FAR * szErrorMsg,
            SQLSMALLINT cbErrorMsgMax,
-           SQLSMALLINT *pcbErrorMsg, 
+           SQLSMALLINT FAR * pcbErrorMsg,
            UWORD flag)
 {
    EnvironmentClass *env = (EnvironmentClass *) henv;
    char        *msg;
    int     status;
 
-   mylog("**** PGAPI_EnvError: henv=%u <%d>\n", henv, cbErrorMsgMax);
+   mylog("**** PGAPI_EnvError: henv=%x <%d>\n", henv, cbErrorMsgMax);
    if (RecNumber != 1 && RecNumber != -1)
        return SQL_NO_DATA_FOUND;
    if (cbErrorMsgMax < 0)
@@ -609,7 +396,7 @@ PGAPI_EnvError(     HENV henv,
    if (!EN_get_error(env, &status, &msg) || NULL == msg)
    {
            mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
-
+       
        if (NULL != szSqlState)
            pg_sqlstate_set(env, szSqlState, "00000", "00000");
        if (NULL != pcbErrorMsg)
@@ -622,7 +409,7 @@ PGAPI_EnvError(     HENV henv,
    mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
 
    if (NULL != pcbErrorMsg)
-       *pcbErrorMsg = (SWORD) strlen(msg);
+       *pcbErrorMsg = (SQLSMALLINT) strlen(msg);
    if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
        strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
    if (NULL != pfNativeError)
@@ -649,19 +436,20 @@ PGAPI_EnvError(       HENV henv,
 
 /*     Returns the next SQL error information. */
 RETCODE        SQL_API
-PGAPI_Error(       HENV henv,
-           HDBC hdbc, 
+PGAPI_Error(
+           HENV henv,
+           HDBC hdbc,
            HSTMT hstmt,
-           SQLCHAR *szSqlState,
-           SQLINTEGER *pfNativeError,
-           SQLCHAR *szErrorMsg, 
+           SQLCHAR FAR * szSqlState,
+           SQLINTEGER FAR * pfNativeError,
+           SQLCHAR FAR * szErrorMsg,
            SQLSMALLINT cbErrorMsgMax,
-           SQLSMALLINT *pcbErrorMsg)
+           SQLSMALLINT FAR * pcbErrorMsg)
 {
    RETCODE ret;
    UWORD   flag = PODBC_ALLOW_PARTIAL_EXTRACT | PODBC_ERROR_CLEAR;
 
-   mylog("**** PGAPI_Error: henv=%u, hdbc=%u hstmt=%d\n", henv, hdbc, hstmt);
+   mylog("**** PGAPI_Error: henv=%x, hdbc=%x hstmt=%d\n", henv, hdbc, hstmt);
 
    if (cbErrorMsgMax < 0)
        return SQL_ERROR;
@@ -716,7 +504,7 @@ EN_Destructor(EnvironmentClass *self)
    int         lf;
    char        rv = 1;
 
-   mylog("in EN_Destructor, self=%u\n", self);
+   mylog("in EN_Destructor, self=%x\n", self);
 
    /*
     * the error messages are static strings distributed throughout the
@@ -724,16 +512,16 @@ EN_Destructor(EnvironmentClass *self)
     */
 
    /* Free any connections belonging to this environment */
-   ENTER_CONNS_CS;
    for (lf = 0; lf < MAX_CONNECTIONS; lf++)
    {
        if (conns[lf] && conns[lf]->henv == self)
        {
-           rv = rv && CC_Destructor(conns[lf]);
-           conns[lf] = NULL;
+           if (CC_Destructor(conns[lf]))
+               conns[lf] = NULL;
+           else
+               rv = 0;
        }
    }
-   LEAVE_CONNS_CS;
    DELETE_ENV_CS(self);
    free(self);
 
@@ -766,7 +554,7 @@ EN_add_connection(EnvironmentClass *self, ConnectionClass *conn)
 {
    int         i;
 
-   mylog("EN_add_connection: self = %u, conn = %u\n", self, conn);
+   mylog("EN_add_connection: self = %x, conn = %x\n", self, conn);
 
    ENTER_CONNS_CS;
    for (i = 0; i < MAX_CONNECTIONS; i++)
@@ -777,7 +565,7 @@ EN_add_connection(EnvironmentClass *self, ConnectionClass *conn)
            conns[i] = conn;
            LEAVE_CONNS_CS;
 
-           mylog("       added at i =%d, conn->henv = %u, conns[i]->henv = %u\n", i, conn->henv, conns[i]->henv);
+           mylog("       added at i =%d, conn->henv = %x, conns[i]->henv = %x\n", i, conn->henv, conns[i]->henv);
 
            return TRUE;
        }
index 7807ae52f2df5ffe64d297f22a77c503272a5875..190198dada75a227e683b7695ccc7e9d60f08c02 100644 (file)
--- a/environ.h
+++ b/environ.h
@@ -1,4 +1,4 @@
-/* File:           environ.h
+/*
  *
  * Description:        See "environ.c"
  *
@@ -58,6 +58,10 @@ void     EN_log_error(const char *func, char *desc, EnvironmentClass *self);
 #define ENTER_ENV_CS(x)    EnterCriticalSection(&((x)->cs))
 #define LEAVE_ENV_CS(x)        LeaveCriticalSection(&((x)->cs))
 #define DELETE_ENV_CS(x)   DeleteCriticalSection(&((x)->cs))
+#define INIT_COMMON_CS     InitializeCriticalSection(&common_cs)
+#define ENTER_COMMON_CS        EnterCriticalSection(&common_cs)
+#define LEAVE_COMMON_CS        LeaveCriticalSection(&common_cs)
+#define DELETE_COMMON_CS   DeleteCriticalSection(&common_cs)
 #elif defined(POSIX_MULTITHREAD_SUPPORT)
 #define    INIT_CONNS_CS   pthread_mutex_init(&conns_cs,0)
 #define    ENTER_CONNS_CS  pthread_mutex_lock(&conns_cs)
@@ -67,14 +71,23 @@ void        EN_log_error(const char *func, char *desc, EnvironmentClass *self);
 #define ENTER_ENV_CS(x)        pthread_mutex_lock(&((x)->cs))
 #define LEAVE_ENV_CS(x)        pthread_mutex_unlock(&((x)->cs))
 #define DELETE_ENV_CS(x)   pthread_mutex_destroy(&((x)->cs))
+#define INIT_COMMON_CS     pthread_mutex_init(&common_cs,0)
+#define ENTER_COMMON_CS        pthread_mutex_lock(&common_cs)
+#define LEAVE_COMMON_CS        pthread_mutex_unlock(&common_cs)
+#define DELETE_COMMON_CS   pthread_mutex_destroy(&common_cs)
 #else
 #define    INIT_CONNS_CS
 #define    ENTER_CONNS_CS
 #define    LEAVE_CONNS_CS
 #define    DELETE_CONNS_CS
 #define INIT_ENV_CS(x)
-#define ENTER_ENV_CS(x)        ((void)(0))
-#define LEAVE_ENV_CS(x)        ((void)(0))
+#define ENTER_ENV_CS(x)
+#define LEAVE_ENV_CS(x)
 #define DELETE_ENV_CS(x)
+#define INIT_COMMON_CS
+#define ENTER_COMMON_CS
+#define LEAVE_COMMON_CS
+#define DELETE_COMMON_CS
 #endif /* WIN_MULTITHREAD_SUPPORT */
-#endif
+
+#endif /* __ENVIRON_H_ */
index 5eb36d018c342228cb3db7a6cb0c012c552feea7..ec0c94a43e743506360bb1129d572f92e7bedfa6 100644 (file)
--- a/execute.c
+++ b/execute.c
@@ -18,7 +18,6 @@
 #include <stdio.h>
 #include <string.h>
 
-#include <libpq/libpq-fs.h>
 #include "environ.h"
 #include "connection.h"
 #include "statement.h"
@@ -26,6 +25,7 @@
 #include "convert.h"
 #include "bind.h"
 #include "pgtypes.h"
+#include "lobj.h"
 #include "pgapifunc.h"
 
 /*extern GLOBAL_VALUES globals;*/
 
 /*     Perform a Prepare on the SQL statement */
 RETCODE        SQL_API
-PGAPI_Prepare( HSTMT hstmt,
-       SQLCHAR *szSqlStr, 
-       SQLINTEGER cbSqlStr)
+PGAPI_Prepare(HSTMT hstmt,
+             const SQLCHAR FAR * szSqlStr,
+             SQLINTEGER cbSqlStr)
 {
    CSTR func = "PGAPI_Prepare";
    StatementClass *self = (StatementClass *) hstmt;
+   RETCODE retval = SQL_SUCCESS;
 
    mylog("%s: entering...\n", func);
 
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(self); */
    if (!self)
    {
        SC_log_error(func, "", NULL);
-       return SQL_INVALID_HANDLE;
+       retval = SQL_INVALID_HANDLE;
+       goto cleanup;
    }
 
    /*
@@ -54,6 +58,7 @@ PGAPI_Prepare(    HSTMT hstmt,
     * one
     */
 
+   SC_set_prepared(self, NOT_YET_PREPARED);
    switch (self->status)
    {
        case STMT_PREMATURE:
@@ -80,24 +85,24 @@ PGAPI_Prepare(  HSTMT hstmt,
        case STMT_EXECUTING:
            mylog("**** PGAPI_Prepare: STMT_EXECUTING, error!\n");
 
-           SC_set_error(self, STMT_SEQUENCE_ERROR, "PGAPI_Prepare(): The handle does not point to a statement that is ready to be executed");
-           SC_log_error(func, "", self);
+           SC_set_error(self, STMT_SEQUENCE_ERROR, "PGAPI_Prepare(): The handle does not point to a statement that is ready to be executed", func);
 
-           return SQL_ERROR;
+           retval = SQL_ERROR;
+           goto cleanup;
 
        default:
-           SC_set_error(self, STMT_INTERNAL_ERROR, "An Internal Error has occured -- Unknown statement status.");
-           SC_log_error(func, "", self);
-           return SQL_ERROR;
+           SC_set_error(self, STMT_INTERNAL_ERROR, "An Internal Error has occured -- Unknown statement status.", func);
+           retval = SQL_ERROR;
+           goto cleanup;
    }
 
    SC_initialize_stmts(self, TRUE);
 
    if (!szSqlStr)
    {
-       SC_set_error(self, STMT_NO_MEMORY_ERROR, "the query is NULL");
-       SC_log_error(func, "", self);
-       return SQL_ERROR;
+       SC_set_error(self, STMT_NO_MEMORY_ERROR, "the query is NULL", func);
+       retval = SQL_ERROR;
+       goto cleanup;
    }
    if (!szSqlStr[0])
        self->statement = strdup("");
@@ -105,39 +110,46 @@ PGAPI_Prepare(    HSTMT hstmt,
        self->statement = make_string(szSqlStr, cbSqlStr, NULL, 0);
    if (!self->statement)
    {
-       SC_set_error(self, STMT_NO_MEMORY_ERROR, "No memory available to store statement");
-       SC_log_error(func, "", self);
-       return SQL_ERROR;
+       SC_set_error(self, STMT_NO_MEMORY_ERROR, "No memory available to store statement", func);
+       retval = SQL_ERROR;
+       goto cleanup;
    }
 
-   self->prepare = TRUE;
-   SC_set_prepared(self, FALSE);
+   self->prepare = PREPARE_STATEMENT;
    self->statement_type = statement_type(self->statement);
 
    /* Check if connection is onlyread (only selects are allowed) */
-   if (CC_is_onlyread(self->hdbc) && STMT_UPDATE(self))
+   if (CC_is_onlyread(SC_get_conn(self)) && STMT_UPDATE(self))
    {
-       SC_set_error(self, STMT_EXEC_ERROR, "Connection is readonly, only select statements are allowed.");
-       SC_log_error(func, "", self);
-       return SQL_ERROR;
+       SC_set_error(self, STMT_EXEC_ERROR, "Connection is readonly, only select statements are allowed.", func);
+       retval = SQL_ERROR;
+       goto cleanup;
    }
 
-   return SQL_SUCCESS;
+cleanup:
+#undef return
+inolog("SQLPrepare return=%d\n", retval);
+   if (self->internal)
+       retval = DiscardStatementSvp(self, retval, FALSE);
+   return retval;
 }
 
 
 /*     Performs the equivalent of SQLPrepare, followed by SQLExecute. */
 RETCODE        SQL_API
-PGAPI_ExecDirect(HSTMT hstmt,
-           SQLCHAR *szSqlStr, 
-           SQLINTEGER cbSqlStr, 
-           UWORD flag)
+PGAPI_ExecDirect(
+                HSTMT hstmt,
+                const SQLCHAR FAR * szSqlStr,
+                SQLINTEGER cbSqlStr,
+                UWORD flag)
 {
    StatementClass *stmt = (StatementClass *) hstmt;
    RETCODE     result;
    CSTR func = "PGAPI_ExecDirect";
+   const ConnectionClass   *conn = SC_get_conn(stmt);
+   const ConnInfo  *ci = &(conn->connInfo);
 
-   mylog("%s: entering...\n", func);
+   mylog("%s: entering...%x\n", func, flag);
 
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
        return result;
@@ -147,14 +159,17 @@ PGAPI_ExecDirect(HSTMT hstmt,
     * execute this statement again
     */
    stmt->statement = make_string(szSqlStr, cbSqlStr, NULL, 0);
+inolog("a2\n");
    if (!stmt->statement)
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "No memory available to store statement");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "No memory available to store statement", func);
        return SQL_ERROR;
    }
 
-   mylog("**** %s: hstmt=%u, statement='%s'\n", func, hstmt, stmt->statement);
+   mylog("**** %s: hstmt=%x, statement='%s'\n", func, hstmt, stmt->statement);
+
+   if (0 != (flag & PODBC_WITH_HOLD))
+       SC_set_with_hold(stmt);
 
    /*
     * If an SQLPrepare was performed prior to this, but was left in the
@@ -167,21 +182,86 @@ PGAPI_ExecDirect(HSTMT hstmt,
    stmt->statement_type = statement_type(stmt->statement);
 
    /* Check if connection is onlyread (only selects are allowed) */
-   if (CC_is_onlyread(stmt->hdbc) && STMT_UPDATE(stmt))
+   if (CC_is_onlyread(conn) && STMT_UPDATE(stmt))
    {
-       SC_set_error(stmt, STMT_EXEC_ERROR, "Connection is readonly, only select statements are allowed.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_EXEC_ERROR, "Connection is readonly, only select statements are allowed.", func);
        return SQL_ERROR;
    }
 
    mylog("%s: calling PGAPI_Execute...\n", func);
 
+   flag = SC_is_with_hold(stmt) ? PODBC_WITH_HOLD : 0;
    result = PGAPI_Execute(hstmt, flag);
 
    mylog("%s: returned %hd from PGAPI_Execute\n", func, result);
    return result;
 }
 
+void
+decideHowToPrepare(StatementClass *stmt)
+{
+   ConnectionClass *conn;
+   ConnInfo    *ci;
+
+   if (PREPARE_STATEMENT != stmt->prepare) /* not a prepare statement or already decided */
+       return;
+   if (stmt->inaccurate_result)
+       return;
+   conn = SC_get_conn(stmt);
+   ci = &(conn->connInfo);
+   if (!ci->use_server_side_prepare ||
+       PG_VERSION_LT(conn, 7.3))
+   {
+       /* Do prepare operations by the driver itself */
+       stmt->prepare |= PREPARE_BY_THE_DRIVER;
+       goto cleanup;
+   }
+   if (NOT_YET_PREPARED == stmt->prepared)
+   {
+       SQLSMALLINT num_params;
+
+       if (STMT_TYPE_DECLARE == stmt->statement_type &&
+           PG_VERSION_LT(conn, 8.0))
+       {
+           stmt->prepare |= PREPARE_BY_THE_DRIVER;
+           goto cleanup;
+       }
+       if (stmt->multi_statement < 0)
+           PGAPI_NumParams(stmt, &num_params);
+       if (stmt->multi_statement > 0) /* server-side prepare mechanism coundn' handle multi statement */
+           stmt->prepare |= PREPARE_BY_THE_DRIVER;
+       else if (PROTOCOL_74(ci))
+       {
+           if (STMT_TYPE_SELECT == stmt->statement_type)
+           {
+               if (ci->drivers.use_declarefetch)
+                   /* stmt->prepare |= PREPARE_BY_THE_DRIVER; */
+                   stmt->prepare |= USING_UNNAMED_PARSE_REQUEST;
+               else if (SQL_CURSOR_FORWARD_ONLY != stmt->options.cursor_type)
+                   stmt->prepare |= USING_UNNAMED_PARSE_REQUEST;
+               else
+                   stmt->prepare |= USING_PARSE_REQUEST;
+           }
+           else
+               stmt->prepare |= USING_PARSE_REQUEST;
+       }
+       else
+       {
+           if (STMT_TYPE_SELECT == stmt->statement_type &&
+               (SQL_CURSOR_FORWARD_ONLY != stmt->options.cursor_type ||
+               ci->drivers.use_declarefetch))
+               stmt->prepare |= PREPARE_BY_THE_DRIVER;
+           else
+               stmt->prepare |= USING_PREPARE_COMMAND;
+       }
+   }
+
+cleanup:
+   if (PREPARE_BY_THE_DRIVER == stmt->prepare)
+       stmt->discard_output_params = 1;
+   return;
+}
+
 /*
  * The execution after all parameters were resolved.
  */
@@ -205,12 +285,17 @@ RETCODE   Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end)
    cursor_type = stmt->options.cursor_type;
    scroll_concurrency = stmt->options.scroll_concurrency;
    /* Prepare the statement if possible at backend side */
-   if (stmt->prepare &&
-       !stmt->prepared &&
-       !stmt->inaccurate_result &&
-       conn->connInfo.use_server_side_prepare &&
-       PG_VERSION_GE(conn, 7.3))
-       prepare_before_exec = TRUE;
+   if (!stmt->inaccurate_result)
+   {
+       decideHowToPrepare(stmt);
+       switch (SC_get_prepare_method(stmt))
+       {
+           case USING_PREPARE_COMMAND:
+           case USING_PARSE_REQUEST:
+               prepare_before_exec = TRUE;
+       }
+   }
+inolog("prepare_before_exec=%d srv=%d\n", prepare_before_exec, conn->connInfo.use_server_side_prepare);
    /* Create the statement with parameters substituted. */
    retval = copy_statement_with_parameters(stmt, prepare_before_exec);
    stmt->current_exec_param = -1;
@@ -225,7 +310,7 @@ RETCODE Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end)
 
    /*
     *  Dummy exection to get the column info.
-    */
+    */ 
    if (stmt->inaccurate_result && conn->connInfo.disallow_premature)
    {
        BOOL        in_trans = CC_is_in_trans(conn);
@@ -243,20 +328,24 @@ RETCODE   Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end)
        {
            if (issued_begin = CC_begin(conn), !issued_begin)
            {
-               SC_set_error(stmt, STMT_EXEC_ERROR,  "Handle prepare error");
+               SC_set_error(stmt, STMT_EXEC_ERROR,  "Handle prepare error", func);
                return SQL_ERROR;
            }
        }
        /* we are now in a transaction */
-       res = CC_send_query(conn, stmt->stmt_with_params, NULL, CLEAR_RESULT_ON_ABORT);
-       if (!res)
+       res = CC_send_query(conn, stmt->stmt_with_params, NULL, 0, SC_get_ancestor(stmt));
+       if (!QR_command_maybe_successful(res))
        {
-           CC_abort(conn);
-           SC_set_error(stmt, STMT_EXEC_ERROR, "Handle prepare error");
+#ifndef    _LEGACY_MODE_
+           if (PG_VERSION_LT(conn, 8.0))
+               CC_abort(conn);
+#endif /* LEGACY_MODE_ */
+           SC_set_error(stmt, STMT_EXEC_ERROR, "Handle prepare error", func);
+           QR_Destructor(res);
            return SQL_ERROR;
        }
        SC_set_Result(stmt, res);
-       for (curres = res; curres && !curres->num_fields; curres = curres->next)
+       for (curres = res; !curres->num_fields; curres = curres->next)
            ;
        SC_set_Curres(stmt, curres);
        if (CC_is_in_autocommit(conn))
@@ -286,30 +375,29 @@ RETCODE   Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end)
 
        if (kres = res->next, kres)
        {
+           if (kres->fields)
+               CI_Destructor(kres->fields);
            kres->fields = res->fields;
            res->fields = NULL;
            kres->num_fields = res->num_fields;
            res->next = NULL;
-           QR_Destructor(res);
            SC_set_Result(stmt, kres);
            res = kres;
        }
    }
-   else if (SC_is_prepare_before_exec(stmt))
+#ifdef NOT_USED
+   else if (SC_is_concat_prepare_exec(stmt))
    {
        if (res && QR_command_maybe_successful(res))
        {
            QResultClass    *kres;
-
-           if (kres = res->next, kres)
-           {
-               kres = res->next;
-               SC_set_Result(stmt, kres);
-               res->next = NULL;
-               QR_Destructor(res);
-               res = kres;
-           }
-           SC_set_prepared(stmt, TRUE);
+       
+           kres = res->next;
+inolog("res->next=%x\n", kres);
+           res->next = NULL;
+           SC_set_Result(stmt, kres);
+           res = kres;
+           SC_set_prepared(stmt, PREPARED_PERMANENTLY);
        }
        else
        {
@@ -319,24 +407,25 @@ RETCODE   Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end)
            stmt->execute_statement = NULL;
        }
    }
-
+#endif /* NOT_USED */
+#if (ODBCVER >= 0x0300)
    ipdopts = SC_get_IPDF(stmt);
    if (ipdopts->param_status_ptr)
    {
        switch (retval)
        {
-           case SQL_SUCCESS:
+           case SQL_SUCCESS: 
                ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
                break;
-           case SQL_SUCCESS_WITH_INFO:
+           case SQL_SUCCESS_WITH_INFO: 
                ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
                break;
-           default:
+           default: 
                ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
                break;
        }
    }
-
+#endif /* ODBCVER */
    if (end_row = stmt->exec_end_row, end_row < 0)
    {
        apdopts = SC_get_APDF(stmt);
@@ -352,14 +441,24 @@ RETCODE   Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end)
        stmt->exec_current_row++;
    if (res)
    {
+#if (ODBCVER >= 0x0300)
+       EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
+       const char *cmd = QR_get_command(res);
 
-           EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
-       if (!res->recent_processed_row_count && res->status == PGRES_COMMAND_OK && EN_is_odbc3(env))
+       if (retval == SQL_SUCCESS && cmd && EN_is_odbc3(env))
        {
-           if ((strnicmp(stmt->statement, "UPDATE", 6) == 0) || 
-               (strnicmp(stmt->statement, "DELETE", 6) == 0))
-               retval = SQL_NO_DATA_FOUND;
+           int     count;
+
+           if (sscanf(cmd , "UPDATE %d", &count) == 1)
+               ;
+           else if (sscanf(cmd , "DELETE %d", &count) == 1)
+               ;
+           else
+               count = -1;
+           if (0 == count)
+               retval = SQL_NO_DATA;
        }
+#endif /* ODBCVER */
        stmt->diag_row_count = res->recent_processed_row_count;
    }
    /*
@@ -369,24 +468,190 @@ RETCODE  Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end)
        (stmt->options.cursor_type != cursor_type ||
         stmt->options.scroll_concurrency != scroll_concurrency))
    {
-       SC_set_error(stmt, STMT_OPTION_VALUE_CHANGED, "cursor updatability changed");
+       SC_set_error(stmt, STMT_OPTION_VALUE_CHANGED, "cursor updatability changed", func);
        retval = SQL_SUCCESS_WITH_INFO;
    }
    return retval;
 }
 
+int
+StartRollbackState(StatementClass *stmt)
+{
+   CSTR    func = "StartRollbackState";
+   int ret;
+   ConnectionClass *conn;
+   ConnInfo    *ci = NULL;
+   
+inolog("%s:%x->internal=%d\n", func, stmt, stmt->internal);
+   conn = SC_get_conn(stmt);
+   if (conn)
+       ci = &conn->connInfo;
+   ret = 0;
+   if (!ci || ci->rollback_on_error < 0) /* default */
+   {
+       if (conn && PG_VERSION_GE(conn, 8.0))
+           ret = 2; /* statement rollback */
+       else
+           ret = 1; /* transaction rollback */
+   }
+   else
+   {
+       ret = ci->rollback_on_error;
+       if (2 == ret && PG_VERSION_LT(conn, 8.0))
+           ret = 1;
+   }
+   switch (ret)
+   {
+       case 1:
+           SC_start_tc_stmt(stmt);
+           break;
+       case 2:
+           SC_start_rb_stmt(stmt);
+           break;
+   }
+   return  ret;
+}
+
+/*
+ * Must be in a transaction or the subsequent execution
+ * invokes a transaction.
+ */
+RETCODE
+SetStatementSvp(StatementClass *stmt)
+{
+   CSTR    func = "SetStatementSvp";
+   char    esavepoint[32], cmd[64];
+   ConnectionClass *conn = SC_get_conn(stmt);
+   QResultClass *res;
+   RETCODE ret = SQL_SUCCESS_WITH_INFO;
+
+   if (CC_is_in_error_trans(conn))
+       return ret;
+
+   switch (stmt->statement_type)
+   {
+       case STMT_TYPE_SPECIAL:
+       case STMT_TYPE_TRANSACTION:
+           return ret;
+   }
+   if (!SC_accessed_db(stmt))
+   {
+       if (stmt->internal)
+       {
+           if (PG_VERSION_GE(conn, 8.0))
+               SC_start_rb_stmt(stmt);
+           else
+               SC_start_tc_stmt(stmt);
+       }
+       if (SC_is_rb_stmt(stmt) && CC_is_in_trans(conn))
+       {
+           sprintf(esavepoint, "_EXEC_SVP_%08x", stmt);
+           snprintf(cmd, sizeof(cmd), "SAVEPOINT %s", esavepoint);
+           res = CC_send_query(conn, cmd, NULL, 0, NULL);
+           if (QR_command_maybe_successful(res))
+           {
+               SC_set_accessed_db(stmt);
+               SC_start_rbpoint(stmt);
+               ret = SQL_SUCCESS;
+           }
+           else
+           {
+               SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal SAVEPOINT failed", func);
+               ret = SQL_ERROR;
+           }
+           QR_Destructor(res);
+       }
+       else
+           SC_set_accessed_db(stmt);
+   }
+inolog("%s:%x->accessed=%d\n", func, stmt, SC_accessed_db(stmt));
+   return ret;
+}
+
+RETCODE
+DiscardStatementSvp(StatementClass *stmt, RETCODE ret, BOOL errorOnly)
+{
+   CSTR    func = "DiscardStatementSvp";
+   char    esavepoint[32], cmd[64];
+   ConnectionClass *conn = SC_get_conn(stmt);
+   QResultClass *res;
+   BOOL    cmd_success, start_stmt = FALSE;    
+
+inolog("%s:%x->accessed=%d is_in=%d is_rb=%d is_tc=%d\n", func, stmt, SC_accessed_db(stmt),
+CC_is_in_trans(conn), SC_is_rb_stmt(stmt), SC_is_tc_stmt(stmt));
+   switch (ret)
+   {
+       case SQL_NEED_DATA:
+           break;
+       case SQL_ERROR:
+           start_stmt = TRUE;
+           break;
+       default:
+           if (!errorOnly)
+               start_stmt = TRUE;
+           break;
+   }
+   if (!SC_accessed_db(stmt) || !CC_is_in_trans(conn))
+       goto cleanup;
+   if (!SC_is_rb_stmt(stmt) && !SC_is_tc_stmt(stmt))
+       goto cleanup;
+   sprintf(esavepoint, "_EXEC_SVP_%08x", stmt);
+   if (SQL_ERROR == ret)
+   {
+       if (SC_started_rbpoint(stmt))
+       {
+           snprintf(cmd, sizeof(cmd), "ROLLBACK to %s", esavepoint);
+           res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN, NULL);
+           cmd_success = QR_command_maybe_successful(res);
+           QR_Destructor(res);
+           if (!cmd_success)
+           {
+               SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal ROLLBACK failed", func);
+               goto cleanup;
+           }
+       }
+       else
+       {
+           CC_abort(conn);
+           goto cleanup;
+       }
+   }
+   else if (errorOnly)
+       return ret;
+inolog("ret=%d\n", ret);
+   if (SQL_NEED_DATA != ret && SC_started_rbpoint(stmt))
+   {
+       snprintf(cmd, sizeof(cmd), "RELEASE %s", esavepoint);
+       res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN, NULL);
+       cmd_success = QR_command_maybe_successful(res);
+       QR_Destructor(res);
+       if (!cmd_success)
+       {
+           SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal RELEASE failed", func);
+           ret = SQL_ERROR;
+       }
+   }
+cleanup:
+   if (start_stmt || SQL_ERROR == ret)
+       SC_start_stmt(stmt);
+   return ret;
+}
+
 /* Execute a prepared SQL statement */
 RETCODE        SQL_API
 PGAPI_Execute(HSTMT hstmt, UWORD flag)
 {
    CSTR func = "PGAPI_Execute";
    StatementClass *stmt = (StatementClass *) hstmt;
+   RETCODE     retval = SQL_SUCCESS;
+   ConnectionClass *conn;
    APDFields   *apdopts;
    IPDFields   *ipdopts;
-   int i,  retval, start_row, end_row;
+   int         i, start_row, end_row;
    BOOL    exec_end, recycled = FALSE, recycle = TRUE;
+   SQLSMALLINT num_params;
 
-   mylog("%s: entering...\n", func);
+   mylog("%s: entering...%x\n", func, flag);
 
    if (!stmt)
    {
@@ -395,6 +660,7 @@ PGAPI_Execute(HSTMT hstmt, UWORD flag)
        return SQL_INVALID_HANDLE;
    }
 
+   conn = SC_get_conn(stmt);
    apdopts = SC_get_APDF(stmt);
    /*
     * If the statement is premature, it means we already executed it from
@@ -414,13 +680,14 @@ PGAPI_Execute(HSTMT hstmt, UWORD flag)
            if (NULL == SC_get_errormsg(stmt))
            {
                mylog("%s: premature statement but return SQL_SUCCESS\n", func);
-               return SQL_SUCCESS;
+               retval = SQL_SUCCESS;
+               goto cleanup;
            }
            else
            {
-               SC_log_error(func, "", stmt);
-               mylog("%s: premature statement so return SQL_ERROR\n", func);
-               return SQL_ERROR;
+               SC_set_error(stmt,STMT_INTERNAL_ERROR, "premature statement so return SQL_ERROR", func);
+               retval = SQL_ERROR;
+               goto cleanup;
            }
        }
    }
@@ -428,15 +695,15 @@ PGAPI_Execute(HSTMT hstmt, UWORD flag)
    mylog("%s: clear errors...\n", func);
 
    SC_clear_error(stmt);
-
    if (!stmt->statement)
    {
-       SC_set_error(stmt, STMT_NO_STMTSTRING, "This handle does not have a SQL statement stored in it");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_NO_STMTSTRING, "This handle does not have a SQL statement stored in it", func);
        mylog("%s: problem with handle\n", func);
        return SQL_ERROR;
    }
 
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+
    if (stmt->exec_current_row > 0)
    {
        /*
@@ -445,7 +712,7 @@ PGAPI_Execute(HSTMT hstmt, UWORD flag)
         */
        recycle = FALSE;
    }
-   else if (stmt->prepared)
+   else if (PREPARED_PERMANENTLY == stmt->prepared)
    {
        QResultClass    *res;
 
@@ -456,10 +723,7 @@ PGAPI_Execute(HSTMT hstmt, UWORD flag)
         */
        recycle = FALSE;
        if (res = SC_get_Result(stmt), res)
-       {
-               QR_Destructor(res);
-               SC_set_Result(stmt, NULL);
-       }
+               QR_close_result(res, FALSE);
    }
    /*
     * If SQLExecute is being called again, recycle the statement. Note
@@ -477,39 +741,78 @@ PGAPI_Execute(HSTMT hstmt, UWORD flag)
    else if ((stmt->prepare && stmt->status != STMT_READY) ||
        (stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY))
    {
-       SC_set_error(stmt, STMT_STATUS_ERROR, "The handle does not point to a statement that is ready to be executed");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_STATUS_ERROR, "The handle does not point to a statement that is ready to be executed", func);
        mylog("%s: problem with statement\n", func);
-       return SQL_ERROR;
+       retval = SQL_ERROR;
+       goto cleanup;
    }
 
    if (start_row = stmt->exec_start_row, start_row < 0)
-       start_row = 0;
+       start_row = 0; 
    if (end_row = stmt->exec_end_row, end_row < 0)
-       end_row = apdopts->paramset_size - 1;
+       end_row = apdopts->paramset_size - 1; 
    if (stmt->exec_current_row < 0)
        stmt->exec_current_row = start_row;
    ipdopts = SC_get_IPDF(stmt);
+   num_params = stmt->num_params;
+   if (num_params < 0)
+       PGAPI_NumParams(stmt, &num_params);
    if (stmt->exec_current_row == start_row)
    {
+       ConnInfo *ci = &(conn->connInfo);
+       if (NOT_YET_PREPARED == stmt->prepared &&
+           PROTOCOL_74(ci) &&
+           ci->use_server_side_prepare &&
+           ci->bytea_as_longvarbinary) /* both lo and bytea are LO */
+       {
+           SQLSMALLINT num_params = stmt->num_params;
+           if (num_params < 0)
+               PGAPI_NumParams(stmt, &num_params);
+           if (num_params > 0)
+           {
+               int param_number = -1;
+               ParameterImplClass *ipara;
+               BOOL    bCallPrepare = FALSE;
+
+               while (1)
+               {
+                   SC_param_next(stmt, &param_number, NULL, &ipara);
+                   if (!ipara)
+                       break;
+                   if (SQL_LONGVARBINARY == ipara->SQLType)
+                   {
+                       bCallPrepare = TRUE;
+                       break;
+                   }
+               }
+               if (bCallPrepare)
+               {
+                   if (retval = prepareParameters(stmt), SQL_ERROR == retval)
+                       goto cleanup;
+               }
+           }
+       }
+
        if (ipdopts->param_processed_ptr)
            *ipdopts->param_processed_ptr = 0;
-
+#if (ODBCVER >= 0x0300)
        /*
-        *  Initialize the param_status_ptr
+        *  Initialize the param_status_ptr 
         */
        if (ipdopts->param_status_ptr)
        {
            for (i = 0; i <= end_row; i++)
                ipdopts->param_status_ptr[i] = SQL_PARAM_UNUSED;
        }
-
+#endif /* ODBCVER */
        if (recycle && !recycled)
            SC_recycle_statement(stmt);
    }
 
+   /* StartRollbackState must be called after SC_recycle_statement */
+   /* StartRollbackState(stmt); */
 next_param_row:
-
+#if (ODBCVER >= 0x0300)
    if (apdopts->param_operation_ptr)
    {
        while (apdopts->param_operation_ptr[stmt->exec_current_row] == SQL_PARAM_IGNORE)
@@ -517,17 +820,18 @@ next_param_row:
            if (stmt->exec_current_row >= end_row)
            {
                stmt->exec_current_row = -1;
-               return SQL_SUCCESS;
+               retval = SQL_SUCCESS;
+               goto cleanup;
            }
            ++stmt->exec_current_row;
        }
    }
    /*
-    *  Initialize the current row status
+    *  Initialize the current row status 
     */
    if (ipdopts->param_status_ptr)
        ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
-
+#endif /* ODBCVER */
    /*
     * Check if statement has any data-at-execute parameters when it is
     * not in SC_pre_execute.
@@ -542,34 +846,25 @@ next_param_row:
        UInt4   offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0;
        Int4    bind_size = apdopts->param_bind_type;
        Int4    current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
-       SWORD   param_count;
+       Int4    num_p = num_params < apdopts->allocated ? num_params : apdopts->allocated;
 
        /*
-        *  Increment the  number of currently processed rows
+        *  Increment the  number of currently processed rows 
         */
        if (ipdopts->param_processed_ptr)
            (*ipdopts->param_processed_ptr)++;
        stmt->data_at_exec = -1;
-       /* Check bind parameters count */
-       if (SQL_SUCCESS != PGAPI_NumParams(stmt, &param_count))
-           return SQL_ERROR;
-       if (param_count > apdopts->allocated)
-       {
-           SC_set_error(stmt, STMT_COUNT_FIELD_INCORRECT, "The # of binded parameters < the # of parameter markers");
-           SC_set_sqlstate(stmt, "07002");
-           return SQL_ERROR;
-       }
-       for (i = 0; i < param_count; i++)
+       for (i = 0; i < num_p; i++)
        {
-           Int4       *pcVal = apdopts->parameters[i].used;
+           SQLLEN     *pcVal = apdopts->parameters[i].used;
 
            apdopts->parameters[i].data_at_exec = FALSE;
            if (pcVal)
            {
                if (bind_size > 0)
-                   pcVal = (Int4 *)((char *)pcVal + offset + bind_size * current_row);
+                   pcVal = (SQLLEN *)((char *)pcVal + offset + bind_size * current_row);
                else
-                   pcVal = (Int4 *)((char *)pcVal + offset + sizeof(SDWORD) * current_row);
+                   pcVal = (SQLLEN *)((char *)pcVal + offset + sizeof(SDWORD) * current_row);
                if (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET)
                    apdopts->parameters[i].data_at_exec = TRUE;
            }
@@ -593,13 +888,21 @@ next_param_row:
         * execute the statement.
         */
        if (stmt->data_at_exec > 0)
-           return SQL_NEED_DATA;
-
+       {
+           retval = SQL_NEED_DATA;
+           goto cleanup;
+       }
    }
 
+   if (0 != (flag & PODBC_WITH_HOLD))
+       SC_set_with_hold(stmt);
    retval = Exec_with_parameters_resolved(stmt, &exec_end);
    if (!exec_end)
        goto next_param_row;
+cleanup:
+#undef return
+   if (stmt->internal)
+       retval = DiscardStatementSvp(stmt, retval, FALSE);
    return retval;
 }
 
@@ -608,7 +911,7 @@ RETCODE     SQL_API
 PGAPI_Transact(
               HENV henv,
               HDBC hdbc,
-              UWORD fType)
+              SQLUSMALLINT fType)
 {
    CSTR func = "PGAPI_Transact";
    extern ConnectionClass *conns[];
@@ -618,7 +921,7 @@ PGAPI_Transact(
               *stmt_string;
    int         lf;
 
-   mylog("entering %s: hdbc=%u, henv=%u\n", func, hdbc, henv);
+   mylog("entering %s: hdbc=%x, henv=%x\n", func, hdbc, henv);
 
    if (hdbc == SQL_NULL_HDBC && henv == SQL_NULL_HENV)
    {
@@ -651,8 +954,7 @@ PGAPI_Transact(
        stmt_string = "ROLLBACK";
    else
    {
-       CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "PGAPI_Transact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter");
-       CC_log_error(func, "", conn);
+       CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "PGAPI_Transact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter", func);
        return SQL_ERROR;
    }
 
@@ -661,20 +963,12 @@ PGAPI_Transact(
    {
        mylog("PGAPI_Transact: sending on conn %d '%s'\n", conn, stmt_string);
 
-       res = CC_send_query(conn, stmt_string, NULL, CLEAR_RESULT_ON_ABORT);
-       if (!res)
-       {
-           /* error msg will be in the connection */
-           CC_on_abort(conn, NO_TRANS);
-           CC_log_error(func, "", conn);
-           return SQL_ERROR;
-       }
-
+       res = CC_send_query(conn, stmt_string, NULL, 0, NULL);
        ok = QR_command_maybe_successful(res);
        QR_Destructor(res);
-
        if (!ok)
        {
+           /* error msg will be in the connection */
            CC_on_abort(conn, NO_TRANS);
            CC_log_error(func, "", conn);
            return SQL_ERROR;
@@ -689,16 +983,12 @@ PGAPI_Cancel(
             HSTMT hstmt)       /* Statement to cancel. */
 {
    CSTR func = "PGAPI_Cancel";
-   StatementClass *stmt = (StatementClass *) hstmt;
+   StatementClass *stmt = (StatementClass *) hstmt, *estmt;
    ConnectionClass *conn;
-   RETCODE     result;
+   RETCODE     ret = SQL_SUCCESS;
+   BOOL    entered_cs = FALSE;
    ConnInfo   *ci;
 
-#ifdef WIN32
-   HMODULE     hmodule;
-   FARPROC     addr;
-#endif
-
    mylog("%s: entering...\n", func);
 
    /* Check if this can handle canceling in the middle of a SQLPutData? */
@@ -710,17 +1000,30 @@ PGAPI_Cancel(
    conn = SC_get_conn(stmt);
    ci = &(conn->connInfo);
 
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
+
+   if (stmt->execute_delegate)
+       estmt = stmt->execute_delegate;
+   else
+       estmt = stmt;
    /*
     * Not in the middle of SQLParamData/SQLPutData so cancel like a
     * close.
     */
-   if (stmt->data_at_exec < 0)
+   if (estmt->data_at_exec < 0)
    {
        /*
         * Tell the Backend that we're cancelling this request
         */
-       if (stmt->status == STMT_EXECUTING)
-           CC_send_cancel_request(conn);
+       if (estmt->status == STMT_EXECUTING)
+       {
+           if (!CC_send_cancel_request(conn))
+           {
+               ret = SQL_ERROR;
+           }
+           goto cleanup;
+       }
        /*
         * MAJOR HACK for Windows to reset the driver manager's cursor
         * state: Because of what seems like a bug in the Odbc driver
@@ -730,32 +1033,55 @@ PGAPI_Cancel(
         * the application.
         */
 
+#if (ODBCVER < 0x0350)
 #ifdef WIN32
        if (ci->drivers.cancel_as_freestmt)
        {
+           HMODULE     hmodule;
+           FARPROC     addr;
+
            hmodule = GetModuleHandle("ODBC32");
            addr = GetProcAddress(hmodule, "SQLFreeStmt");
-           result = addr((char *) (stmt->phstmt) - 96, SQL_CLOSE);
+           ret = addr((char *) (stmt->phstmt) - 96, SQL_CLOSE);
        }
        else
-           result = PGAPI_FreeStmt(hstmt, SQL_CLOSE);
-#else
-       result = PGAPI_FreeStmt(hstmt, SQL_CLOSE);
-#endif
-
-       mylog("PGAPI_Cancel:  PGAPI_FreeStmt returned %d\n", result);
+#endif /* WIN32 */
+       {
+           ENTER_STMT_CS(stmt);
+           entered_cs = TRUE;
+           SC_clear_error(hstmt);
+           ret = PGAPI_FreeStmt(hstmt, SQL_CLOSE);
+       }
 
-       SC_clear_error(hstmt);
-       return SQL_SUCCESS;
+       mylog("PGAPI_Cancel:  PGAPI_FreeStmt returned %d\n", ret);
+#endif /* ODBCVER */
+       goto cleanup;
    }
 
    /* In the middle of SQLParamData/SQLPutData, so cancel that. */
-   stmt->data_at_exec = -1;
-   stmt->current_exec_param = -1;
-   stmt->put_data = FALSE;
-   cancelNeedDataState(stmt);
+   /*
+    * Note, any previous data-at-exec buffers will be freed in the
+    * recycle
+    */
+   /* if they call SQLExecDirect or SQLExecute again. */
 
-   return SQL_SUCCESS;
+   ENTER_STMT_CS(stmt);
+   entered_cs = TRUE;
+   SC_clear_error(stmt);
+   estmt->data_at_exec = -1;
+   estmt->current_exec_param = -1;
+   estmt->put_data = FALSE;
+   cancelNeedDataState(estmt);
+
+cleanup:
+#undef return
+   if (entered_cs)
+   {
+       if (stmt->internal)
+           ret = DiscardStatementSvp(stmt, ret, FALSE);
+       LEAVE_STMT_CS(stmt);
+   }
+   return ret;
 }
 
 
@@ -765,12 +1091,13 @@ PGAPI_Cancel(
  * observing buffer limits and truncation.
  */
 RETCODE        SQL_API
-PGAPI_NativeSql(HDBC hdbc,
-       SQLCHAR *szSqlStrIn,
-       SQLINTEGER cbSqlStrIn,
-       SQLCHAR *szSqlStr,
-       SQLINTEGER cbSqlStrMax,
-       SQLINTEGER *pcbSqlStr)
+PGAPI_NativeSql(
+               HDBC hdbc,
+               const SQLCHAR FAR * szSqlStrIn,
+               SQLINTEGER cbSqlStrIn,
+               SQLCHAR FAR * szSqlStr,
+               SQLINTEGER cbSqlStrMax,
+               SQLINTEGER FAR * pcbSqlStr)
 {
    CSTR func = "PGAPI_NativeSql";
    int         len = 0;
@@ -783,8 +1110,7 @@ PGAPI_NativeSql(HDBC hdbc,
    ptr = (cbSqlStrIn == 0) ? "" : make_string(szSqlStrIn, cbSqlStrIn, NULL, 0);
    if (!ptr)
    {
-       CC_set_error(conn, CONN_NO_MEMORY_ERROR, "No memory available to store native sql string");
-       CC_log_error(func, "", conn);
+       CC_set_error(conn, CONN_NO_MEMORY_ERROR, "No memory available to store native sql string", func);
        return SQL_ERROR;
    }
 
@@ -798,7 +1124,7 @@ PGAPI_NativeSql(HDBC hdbc,
        if (len >= cbSqlStrMax)
        {
            result = SQL_SUCCESS_WITH_INFO;
-           CC_set_error(conn, STMT_TRUNCATED, "The buffer was too small for the NativeSQL.");
+           CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the NativeSQL.", func);
        }
    }
 
@@ -824,20 +1150,19 @@ PGAPI_ParamData(
    CSTR func = "PGAPI_ParamData";
    StatementClass *stmt = (StatementClass *) hstmt, *estmt;
    APDFields   *apdopts;
-/* not used
    IPDFields   *ipdopts;
- */
    RETCODE     retval;
    int     i;
+   Int2        num_p;
    ConnInfo   *ci;
-   SWORD       param_count;
 
    mylog("%s: entering...\n", func);
 
    if (!stmt)
    {
        SC_log_error(func, "", NULL);
-       return SQL_INVALID_HANDLE;
+       retval = SQL_INVALID_HANDLE;
+       goto cleanup;
    }
    ci = &(SC_get_conn(stmt)->connInfo);
 
@@ -845,52 +1170,50 @@ PGAPI_ParamData(
    apdopts = SC_get_APDF(estmt);
    mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, estmt->data_at_exec, apdopts->allocated);
 
-   if (estmt->data_at_exec < 0)
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   if (SC_AcceptedCancelRequest(stmt))
    {
-       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "No execution-time parameters for this statement");
-       SC_log_error(func, "", stmt);
-       return SQL_ERROR;
+       SC_set_error(stmt, STMT_OPERATION_CANCELLED, "Cancel the statement, sorry", func);
+       retval = SQL_ERROR;
+       goto cleanup;
    }
-
-   /* Check bind parameters count */
-   if (SQL_SUCCESS != PGAPI_NumParams(stmt, &param_count))
-       return SQL_ERROR;
-   if (param_count > apdopts->allocated)
+   if (estmt->data_at_exec < 0)
    {
-       SC_set_error(stmt, STMT_COUNT_FIELD_INCORRECT, "The # of binded parameters < the # of parameter markers");
-       SC_set_sqlstate(stmt, "07002");
-       return SQL_ERROR;
+       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "No execution-time parameters for this statement", func);
+       retval = SQL_ERROR;
+       goto cleanup;
    }
 
-   if (estmt->data_at_exec > param_count)
+   if (estmt->data_at_exec > apdopts->allocated)
    {
-       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Too many execution-time parameters were present");
-       SC_log_error(func, "", stmt);
-       return SQL_ERROR;
+       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Too many execution-time parameters were present", func);
+       retval = SQL_ERROR;
+       goto cleanup;
    }
 
    /* close the large object */
    if (estmt->lobj_fd >= 0)
    {
-       lo_close(estmt->hdbc->pgconn, estmt->lobj_fd);
+       ConnectionClass *conn = SC_get_conn(estmt);
+
+       odbc_lo_close(conn, estmt->lobj_fd);
 
        /* commit transaction if needed */
-       if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(estmt->hdbc))
+       if (!CC_cursor_count(conn) && CC_is_in_autocommit(conn))
        {
-           if (!CC_commit(estmt->hdbc))
+           if (!CC_commit(conn))
            {
-               SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction");
-               SC_log_error(func, "", stmt);
-               return SQL_ERROR;
+               SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction", func);
+               retval = SQL_ERROR;
+               goto cleanup;
            }
        }
        estmt->lobj_fd = -1;
    }
 
    /* Done, now copy the params and then execute the statement */
-/* Luf - I don't see why this is called
    ipdopts = SC_get_IPDF(estmt);
- */
+inolog("ipdopts=%x\n", ipdopts);
    if (estmt->data_at_exec == 0)
    {
        BOOL    exec_end;
@@ -898,11 +1221,14 @@ PGAPI_ParamData(
        retval = Exec_with_parameters_resolved(estmt, &exec_end);
        if (exec_end)
        {
-           stmt->execute_delegate = NULL;
-           return dequeueNeedDataCallback(retval, stmt);
+           /**SC_reset_delegate(retval, stmt);**/
+           retval = dequeueNeedDataCallback(retval, stmt);
+           goto cleanup;
        }
        if (retval = PGAPI_Execute(estmt, 0), SQL_NEED_DATA != retval)
-           return retval;
+       {
+           goto cleanup;
+       }
    }
 
    /*
@@ -911,11 +1237,19 @@ PGAPI_ParamData(
     */
    i = estmt->current_exec_param >= 0 ? estmt->current_exec_param + 1 : 0;
 
+   num_p = estmt->num_params;
+   if (num_p < 0)
+       PGAPI_NumParams(estmt, &num_p);
+inolog("i=%d allocated=%d num_p=%d\n", i, apdopts->allocated, num_p);
+   if (num_p > apdopts->allocated)
+       num_p = apdopts->allocated;
    /* At least 1 data at execution parameter, so Fill in the token value */
-   for (; i < param_count; i++)
+   for (; i < num_p; i++)
    {
+inolog("i=%d", i);
        if (apdopts->parameters[i].data_at_exec)
        {
+inolog(" at exec buffer=%x", apdopts->parameters[i].buffer);
            estmt->data_at_exec--;
            estmt->current_exec_param = i;
            estmt->put_data = FALSE;
@@ -925,8 +1259,9 @@ PGAPI_ParamData(
                if (stmt->execute_delegate)
                {
                    UInt4   offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0;
-                   UInt4   perrow = apdopts->param_bind_type > 0 ? apdopts->param_bind_type : apdopts->parameters[i].buflen;
+                   UInt4   perrow = apdopts->param_bind_type > 0 ? apdopts->param_bind_type : apdopts->parameters[i].buflen; 
 
+inolog(" offset=%d perrow=%d", offset, perrow);
                    *prgbValue = apdopts->parameters[i].buffer + offset + estmt->exec_current_row * perrow;
                }
                else
@@ -934,9 +1269,17 @@ PGAPI_ParamData(
            }
            break;
        }
+inolog("\n");
    }
 
-   return SQL_NEED_DATA;
+   retval = SQL_NEED_DATA;
+inolog("return SQL_NEED_DATA\n");
+cleanup:
+#undef return
+   if (stmt->internal)
+       retval = DiscardStatementSvp(stmt, retval, FALSE);
+   mylog("%s: returning %d\n", func, retval);
+   return retval;
 }
 
 
@@ -945,41 +1288,50 @@ PGAPI_ParamData(
  * Used in conjunction with SQLParamData.
  */
 RETCODE        SQL_API
-PGAPI_PutData(HSTMT hstmt,
-       PTR rgbValue, 
-       SQLINTEGER cbValue)
+PGAPI_PutData(
+             HSTMT hstmt,
+             PTR rgbValue,
+             SQLLEN cbValue)
 {
    CSTR func = "PGAPI_PutData";
    StatementClass *stmt = (StatementClass *) hstmt, *estmt;
    ConnectionClass *conn;
+   RETCODE     retval = SQL_SUCCESS;
    APDFields   *apdopts;
    IPDFields   *ipdopts;
    PutDataInfo *pdata;
-   int         old_pos,
-               retval;
+   int         old_pos;
    ParameterInfoClass *current_param;
    ParameterImplClass *current_iparam;
    PutDataClass    *current_pdata;
    char       *buffer, *putbuf, *allocbuf = NULL;
    Int2        ctype;
-   SDWORD          putlen;
+   SQLLEN      putlen;
    BOOL        lenset = FALSE;
 
    mylog("%s: entering...\n", func);
 
+#define    return  DONT_CALL_RETURN_FROM_HERE???
    if (!stmt)
    {
        SC_log_error(func, "", NULL);
-       return SQL_INVALID_HANDLE;
+       retval = SQL_INVALID_HANDLE;
+       goto cleanup;
+   }
+   if (SC_AcceptedCancelRequest(stmt))
+   {
+       SC_set_error(stmt, STMT_OPERATION_CANCELLED, "Cancel the statement, sorry.", func);
+       retval = SQL_ERROR;
+       goto cleanup;
    }
 
    estmt = stmt->execute_delegate ? stmt->execute_delegate : stmt;
    apdopts = SC_get_APDF(estmt);
    if (estmt->current_exec_param < 0)
    {
-       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Previous call was not SQLPutData or SQLParamData");
-       SC_log_error(func, "", stmt);
-       return SQL_ERROR;
+       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Previous call was not SQLPutData or SQLParamData", func);
+       retval = SQL_ERROR;
+       goto cleanup;
    }
 
    current_param = &(apdopts->parameters[estmt->current_exec_param]);
@@ -991,10 +1343,17 @@ PGAPI_PutData(HSTMT hstmt,
 
    conn = SC_get_conn(estmt);
    if (ctype == SQL_C_DEFAULT)
+   {
        ctype = sqltype_to_default_ctype(conn, current_iparam->SQLType);
+       if (SQL_C_WCHAR == ctype &&
+           (CC_is_in_ansi_app(conn)
+           || conn->ms_jet /* not only but for any other ? */
+          ))
+           ctype = SQL_C_CHAR;
+   }
    if (SQL_NTS == cbValue)
    {
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
        if (SQL_C_WCHAR == ctype)
        {
            putlen = WCLEN * ucs2strlen((SQLWCHAR *) rgbValue);
@@ -1013,10 +1372,10 @@ PGAPI_PutData(HSTMT hstmt,
        if (cbValue < 0)
            putlen = cbValue;
        else
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
        if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY || ctype == SQL_C_WCHAR)
-#else   
-       if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY)    
+#else
+       if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY)
 #endif /* UNICODE_SUPPORT */
            putlen = cbValue;
        else
@@ -1040,18 +1399,21 @@ PGAPI_PutData(HSTMT hstmt,
 
        estmt->put_data = TRUE;
 
-       current_pdata->EXEC_used = malloc(sizeof(SDWORD));
+       current_pdata->EXEC_used = (SDWORD *) malloc(sizeof(SDWORD));
        if (!current_pdata->EXEC_used)
        {
-           SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (1)");
-           SC_log_error(func, "", stmt);
-           return SQL_ERROR;
+           SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (1)", func);
+           retval = SQL_ERROR;
+           goto cleanup;
        }
 
        *current_pdata->EXEC_used = putlen;
 
        if (cbValue == SQL_NULL_DATA)
-           return SQL_SUCCESS;
+       {
+           retval = SQL_SUCCESS;
+           goto cleanup;
+       }
 
        /* Handle Long Var Binary with Large Objects */
        /* if (current_iparam->SQLType == SQL_LONGVARBINARY) */
@@ -1062,20 +1424,19 @@ PGAPI_PutData(HSTMT hstmt,
            {
                if (!CC_begin(conn))
                {
-                   SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction");
-                   SC_log_error(func, "", stmt);
-                   return SQL_ERROR;
+                   SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction", func);
+                   retval = SQL_ERROR;
+                   goto cleanup;
                }
            }
 
            /* store the oid */
-           current_pdata->lobj_oid = lo_creat(conn->pgconn, INV_READ | INV_WRITE);
-
+           current_pdata->lobj_oid = odbc_lo_creat(conn, INV_READ | INV_WRITE);
            if (current_pdata->lobj_oid == 0)
            {
-               SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt create large object.");
-               SC_log_error(func, "", stmt);
-               return SQL_ERROR;
+               SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt create large object.", func);
+               retval = SQL_ERROR;
+               goto cleanup;
            }
 
            /*
@@ -1085,15 +1446,15 @@ PGAPI_PutData(HSTMT hstmt,
            /***current_param->EXEC_buffer = (char *) &current_param->lobj_oid;***/
 
            /* store the fd */
-           estmt->lobj_fd = lo_open(conn->pgconn, current_pdata->lobj_oid, INV_WRITE);
+           estmt->lobj_fd = odbc_lo_open(conn, current_pdata->lobj_oid, INV_WRITE);
            if (estmt->lobj_fd < 0)
            {
-               SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open large object for writing.");
-               SC_log_error(func, "", stmt);
-               return SQL_ERROR;
+               SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open large object for writing.", func);
+               retval = SQL_ERROR;
+               goto cleanup;
            }
 
-           retval = lo_write(conn->pgconn, estmt->lobj_fd, putbuf, putlen);
+           retval = odbc_lo_write(conn, estmt->lobj_fd, putbuf, putlen);
            mylog("lo_write: cbValue=%d, wrote %d bytes\n", putlen, retval);
        }
        else
@@ -1101,9 +1462,9 @@ PGAPI_PutData(HSTMT hstmt,
            current_pdata->EXEC_buffer = malloc(putlen + 1);
            if (!current_pdata->EXEC_buffer)
            {
-               SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (2)");
-               SC_log_error(func, "", stmt);
-               return SQL_ERROR;
+               SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (2)", func);
+               retval = SQL_ERROR;
+               goto cleanup;
            }
            memcpy(current_pdata->EXEC_buffer, putbuf, putlen);
            current_pdata->EXEC_buffer[putlen] = '\0';
@@ -1118,7 +1479,7 @@ PGAPI_PutData(HSTMT hstmt,
        if (current_iparam->PGType == conn->lobj_type)
        {
            /* the large object fd is in EXEC_buffer */
-           retval = lo_write(conn->pgconn, estmt->lobj_fd, putbuf, putlen);
+           retval = odbc_lo_write(conn, estmt->lobj_fd, putbuf, putlen);
            mylog("lo_write(2): cbValue = %d, wrote %d bytes\n", putlen, retval);
 
            *current_pdata->EXEC_used += putlen;
@@ -1129,34 +1490,42 @@ PGAPI_PutData(HSTMT hstmt,
            old_pos = *current_pdata->EXEC_used;
            if (putlen > 0)
            {
-               *current_pdata->EXEC_used += putlen;
-
-               mylog("        cbValue = %d, old_pos = %d, *used = %d\n", putlen, old_pos, *current_pdata->EXEC_used);
+               SQLLEN  used = *current_pdata->EXEC_used + putlen, allocsize;
+               for (allocsize = (1 << 4); allocsize <= used; allocsize <<= 1) ;
+               mylog("        cbValue = %d, old_pos = %d, *used = %d\n", putlen, old_pos, used);
 
                /* dont lose the old pointer in case out of memory */
-               buffer = realloc(current_pdata->EXEC_buffer, *current_pdata->EXEC_used + 1);
+               buffer = realloc(current_pdata->EXEC_buffer, allocsize);
                if (!buffer)
                {
-                   SC_set_error(stmt, STMT_NO_MEMORY_ERROR,"Out of memory in PGAPI_PutData (3)");
-                   SC_log_error(func, "", stmt);
-                   return SQL_ERROR;
+                   SC_set_error(stmt, STMT_NO_MEMORY_ERROR,"Out of memory in PGAPI_PutData (3)", func);
+                   retval = SQL_ERROR;
+                   goto cleanup;
                }
 
                memcpy(&buffer[old_pos], putbuf, putlen);
-               buffer[*current_pdata->EXEC_used] = '\0';
+               buffer[used] = '\0';
 
                /* reassign buffer incase realloc moved it */
+               *current_pdata->EXEC_used = used;
                current_pdata->EXEC_buffer = buffer;
            }
            else
            {
-               SC_log_error(func, "bad cbValue", stmt);
-               return SQL_ERROR;
+               SC_set_error(stmt, STMT_INTERNAL_ERROR, "bad cbValue", func);
+               retval = SQL_ERROR;
+               goto cleanup;
            }
        }
    }
+
+   retval = SQL_SUCCESS;
+cleanup:
+#undef return
    if (allocbuf)
        free(allocbuf);
+   if (stmt->internal)
+       retval = DiscardStatementSvp(stmt, retval, TRUE);
 
-   return SQL_SUCCESS;
+   return retval;
 }
diff --git a/info.c b/info.c
index 20e1b707d037adfa310ffeb59e34548fd382cbfe..6f6c2dfb2d6ef2514e5c30cc3236933a7a56ea45 100644 (file)
--- a/info.c
+++ b/info.c
@@ -28,6 +28,7 @@
 #include "tuple.h"
 #include "pgtypes.h"
 #include "dlg_specific.h"
+
 #include "environ.h"
 #include "connection.h"
 #include "statement.h"
@@ -37,6 +38,7 @@
 #include "pgtypes.h"
 #include "pgapifunc.h"
 #include "multibyte.h"
+#include "catfunc.h"
 
 
 /* Trigger related stuff for SQLForeign Keys */
 #define TRIGGER_DELETE 0x01
 #define TRIGGER_UPDATE 0x02
 
-#define    NULL_IF_NULL(a) ((a) ? (const char*)(a) : "(NULL)")
+#define    NULL_IF_NULL(a) ((a) ? ((const char *) a) : "(NULL)")
 
 /* extern GLOBAL_VALUES globals; */
 
 CSTR   pubstr = "public";
+CSTR   likeop = "like";
+CSTR   eqop = "=";
 
 
 RETCODE        SQL_API
 PGAPI_GetInfo(
              HDBC hdbc,
-             UWORD fInfoType,
+             SQLUSMALLINT fInfoType,
              PTR rgbInfoValue,
-             SWORD cbInfoValueMax,
-             SWORD FAR * pcbInfoValue)
+             SQLSMALLINT cbInfoValueMax,
+             SQLSMALLINT FAR * pcbInfoValue)
 {
    CSTR func = "PGAPI_GetInfo";
    ConnectionClass *conn = (ConnectionClass *) hdbc;
@@ -68,6 +72,7 @@ PGAPI_GetInfo(
    int         len = 0,
                value = 0;
    RETCODE     result;
+   char        odbcver[16];
 
    mylog("%s: entering...fInfoType=%d\n", func, fInfoType);
 
@@ -104,6 +109,7 @@ PGAPI_GetInfo(
            value = SQL_AT_ADD_COLUMN;
            if (PG_VERSION_GE(conn, 7.3))
                value |= SQL_AT_DROP_COLUMN;
+#if (ODBCVER >= 0x0300)
            value |= SQL_AT_ADD_COLUMN_SINGLE;
            if (PG_VERSION_GE(conn, 7.1))
                value |= SQL_AT_ADD_CONSTRAINT
@@ -116,12 +122,13 @@ PGAPI_GetInfo(
                    | SQL_AT_DROP_TABLE_CONSTRAINT_CASCADE
                    | SQL_AT_DROP_COLUMN_RESTRICT
                    | SQL_AT_DROP_COLUMN_CASCADE;
+#endif /* ODBCVER */
            break;
 
        case SQL_BOOKMARK_PERSISTENCE:  /* ODBC 2.0 */
            /* very simple bookmark support */
            len = 4;
-           value = ci->drivers.use_declarefetch ? 0 : (SQL_BP_SCROLL | SQL_BP_DELETE | SQL_BP_UPDATE | SQL_BP_TRANSACTION);
+           value = ci->drivers.use_declarefetch && PG_VERSION_LT(conn, 7.4) ? 0 : (SQL_BP_SCROLL | SQL_BP_DELETE | SQL_BP_UPDATE | SQL_BP_TRANSACTION);
            break;
 
        case SQL_COLUMN_ALIAS:  /* ODBC 2.0 */
@@ -134,26 +141,31 @@ PGAPI_GetInfo(
            break;
 
        case SQL_CONVERT_BIGINT:
-       case SQL_CONVERT_BINARY:
-       case SQL_CONVERT_BIT:
-       case SQL_CONVERT_CHAR:
-       case SQL_CONVERT_DATE:
+       case SQL_CONVERT_INTEGER:
+       case SQL_CONVERT_SMALLINT:
+       case SQL_CONVERT_TINYINT:
        case SQL_CONVERT_DECIMAL:
        case SQL_CONVERT_DOUBLE:
        case SQL_CONVERT_FLOAT:
-       case SQL_CONVERT_INTEGER:
-       case SQL_CONVERT_LONGVARBINARY:
-       case SQL_CONVERT_LONGVARCHAR:
        case SQL_CONVERT_NUMERIC:
        case SQL_CONVERT_REAL:
-       case SQL_CONVERT_SMALLINT:
+       case SQL_CONVERT_BIT:
+       case SQL_CONVERT_DATE:
        case SQL_CONVERT_TIME:
        case SQL_CONVERT_TIMESTAMP:
-       case SQL_CONVERT_TINYINT:
-       case SQL_CONVERT_VARBINARY:
+       case SQL_CONVERT_BINARY:
+       case SQL_CONVERT_LONGVARBINARY:
+       case SQL_CONVERT_VARBINARY:     /* ODBC 1.0 */
+       case SQL_CONVERT_CHAR:
+       case SQL_CONVERT_LONGVARCHAR:
        case SQL_CONVERT_VARCHAR:       /* ODBC 1.0 */
-           len = 4;
-           value = fInfoType;
+#ifdef UNICODE_SUPPORT
+       case SQL_CONVERT_WCHAR:
+       case SQL_CONVERT_WLONGVARCHAR:
+       case SQL_CONVERT_WVARCHAR:
+#endif /* UNICODE_SUPPORT */
+           len = sizeof(SQLUINTEGER);
+           value = 0;  /* CONVERT is unavailable */
            break;
 
        case SQL_CONVERT_FUNCTIONS:     /* ODBC 1.0 */
@@ -174,7 +186,7 @@ PGAPI_GetInfo(
        case SQL_CURSOR_COMMIT_BEHAVIOR:        /* ODBC 1.0 */
            len = 2;
            value = SQL_CB_CLOSE;
-           if (!ci->drivers.use_declarefetch)
+           if (!ci->drivers.use_declarefetch || PG_VERSION_GE(conn, 7.4))
                value = SQL_CB_PRESERVE;
            break;
 
@@ -202,11 +214,12 @@ PGAPI_GetInfo(
             *
             * p = CC_get_database(conn);
             */
-           p = "";
+           p = NULL_CATALOG_NAME;
            break;
 
        case SQL_DBMS_NAME:     /* ODBC 1.0 */
-           p = DBMS_NAME;
+           /* p = DBMS_NAME; */
+           p = "PostgreSQL";
            break;
 
        case SQL_DBMS_VER:      /* ODBC 1.0 */
@@ -216,8 +229,10 @@ PGAPI_GetInfo(
             * the driver
             */
            /* version number to the dbms version string */
+           /*
            snprintf(tmp, sizeof(tmp) - 1, "%s %s", POSTGRESDRIVERVERSION, conn->pg_version);
-                        tmp[sizeof(tmp) - 1] = '\0';
+                        tmp[sizeof(tmp) - 1] = '\0'; */
+           strncpy_null(tmp, conn->pg_version, sizeof(tmp));
            p = tmp;
            break;
 
@@ -234,7 +249,9 @@ PGAPI_GetInfo(
            break;
 
        case SQL_DRIVER_ODBC_VER:
-           p = DRIVER_ODBC_VER;
+           sprintf(odbcver, "%02x.%02x", ODBCVER / 256, ODBCVER % 256);
+           /* p = DRIVER_ODBC_VER; */
+           p = odbcver;
            break;
 
        case SQL_DRIVER_VER:    /* ODBC 1.0 */
@@ -247,14 +264,14 @@ PGAPI_GetInfo(
 
        case SQL_FETCH_DIRECTION:       /* ODBC 1.0 */
            len = 4;
-           value = ci->drivers.use_declarefetch ? (SQL_FD_FETCH_NEXT) :
-            (SQL_FD_FETCH_NEXT | 
-            SQL_FD_FETCH_FIRST |
-            SQL_FD_FETCH_LAST |
-            SQL_FD_FETCH_PRIOR |
-            SQL_FD_FETCH_ABSOLUTE |
-            SQL_FD_FETCH_RELATIVE |
-            SQL_FD_FETCH_BOOKMARK);
+           value = (SQL_FD_FETCH_NEXT |
+               SQL_FD_FETCH_NEXT | 
+               SQL_FD_FETCH_FIRST |
+               SQL_FD_FETCH_LAST |
+               SQL_FD_FETCH_PRIOR |
+               SQL_FD_FETCH_ABSOLUTE |
+               SQL_FD_FETCH_RELATIVE |
+               SQL_FD_FETCH_BOOKMARK);
            break;
 
        case SQL_FILE_USAGE:    /* ODBC 2.0 */
@@ -317,8 +334,11 @@ PGAPI_GetInfo(
 
        case SQL_MAX_COLUMN_NAME_LEN:   /* ODBC 1.0 */
            len = 2;
+           if (PG_VERSION_GT(conn, 7.4))
+               value = CC_get_max_idlen(conn);
 #ifdef MAX_COLUMN_LEN
-           value = MAX_COLUMN_LEN;
+           else
+               value = MAX_COLUMN_LEN;
 #endif /* MAX_COLUMN_LEN */
            if (0 == value)
            {
@@ -367,8 +387,10 @@ PGAPI_GetInfo(
        case SQL_MAX_OWNER_NAME_LEN:    /* ODBC 1.0 */
            len = 2;
            value = 0;
+           if (PG_VERSION_GT(conn, 7.4))
+               value = CC_get_max_idlen(conn);
 #ifdef MAX_SCHEMA_LEN
-           if (conn->schema_support)
+           else if (conn->schema_support)
                value = MAX_SCHEMA_LEN;
 #endif /* MAX_SCHEMA_LEN */
            if (0 == value)
@@ -420,8 +442,11 @@ PGAPI_GetInfo(
 
        case SQL_MAX_TABLE_NAME_LEN:    /* ODBC 1.0 */
            len = 2;
+           if (PG_VERSION_GT(conn, 7.4))
+               value = CC_get_max_idlen(conn);
 #ifdef MAX_TABLE_LEN
-           value = MAX_TABLE_LEN;
+           else
+               value = MAX_TABLE_LEN;
 #endif /* MAX_TABLE_LEN */
            if (0 == value)
            {
@@ -547,10 +572,8 @@ PGAPI_GetInfo(
        case SQL_POS_OPERATIONS:        /* ODBC 2.0 */
            len = 4;
            value = (SQL_POS_POSITION | SQL_POS_REFRESH);
-#ifdef DRIVER_CURSOR_IMPLEMENT
-           if (ci->updatable_cursors)
+           if (0 != ci->updatable_cursors)
                value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
            break;
 
        case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */
@@ -570,7 +593,7 @@ PGAPI_GetInfo(
 
        case SQL_QUALIFIER_LOCATION:    /* ODBC 2.0 */
            len = 2;
-           value = 0;
+           value = SQL_QL_START;
            break;
 
        case SQL_QUALIFIER_NAME_SEPARATOR:      /* ODBC 1.0 */
@@ -598,28 +621,22 @@ PGAPI_GetInfo(
             * Driver doesn't support keyset-driven or mixed cursors, so
             * not much point in saying row updates are supported
             */
-           p = (ci->updatable_cursors) ? "Y" : "N";
+           p = (0 != ci->updatable_cursors) ? "Y" : "N";
            break;
 
        case SQL_SCROLL_CONCURRENCY:    /* ODBC 1.0 */
            len = 4;
            value = SQL_SCCO_READ_ONLY;
-#ifdef DRIVER_CURSOR_IMPLEMENT
-           if (ci->updatable_cursors)
+           if (0 != ci->updatable_cursors)
                value |= SQL_SCCO_OPT_ROWVER;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
            if (ci->drivers.lie)
                value |= (SQL_SCCO_LOCK | SQL_SCCO_OPT_VALUES);
            break;
 
        case SQL_SCROLL_OPTIONS:        /* ODBC 1.0 */
            len = 4;
-           value = SQL_SO_FORWARD_ONLY;
-#ifdef DECLAREFETCH_FORWARDONLY
-           if (!ci->drivers.use_declarefetch)
-#endif /* DECLAREFETCH_FORWARDONLY */
-               value |= SQL_SO_STATIC;
-           if (ci->updatable_cursors)
+           value = SQL_SO_FORWARD_ONLY | SQL_SO_STATIC;
+           if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
                value |= SQL_SO_KEYSET_DRIVEN;
            if (ci->drivers.lie)
                value |= (SQL_SO_DYNAMIC | SQL_SO_MIXED);
@@ -643,10 +660,8 @@ PGAPI_GetInfo(
        case SQL_STATIC_SENSITIVITY:    /* ODBC 2.0 */
            len = 4;
            value = 0;
-#ifdef DRIVER_CURSOR_IMPLEMENT
-           if (ci->updatable_cursors)
+           if (0 != ci->updatable_cursors)
                value |= (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
            break;
 
        case SQL_STRING_FUNCTIONS:      /* ODBC 1.0 */
@@ -726,12 +741,14 @@ PGAPI_GetInfo(
 
        default:
            /* unrecognized key */
-           CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unrecognized key passed to PGAPI_GetInfo.");
+           CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unrecognized key passed to PGAPI_GetInfo.", NULL);
            return SQL_ERROR;
    }
 
    result = SQL_SUCCESS;
 
+   mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax);
+
    /*
     * NOTE, that if rgbInfoValue is NULL, then no warnings or errors
     * should result and just pcbInfoValue is returned, which indicates
@@ -741,31 +758,29 @@ PGAPI_GetInfo(
    {
        /* char/binary data */
        len = strlen(p);
-#ifdef  UNICODE_SUPPORT                
-                /* Note that at this point we don't know if we've been called just
-                 * to get the length of the output. If it's unicode, then we better
-                 * adjust to bytes now, so we don't return a buffer size that's too
-                 * small.
-                 */
-                if (conn->unicode)
-                    len = len * WCLEN;
-#endif
 
        if (rgbInfoValue)
        {
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
            if (conn->unicode)
-               len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / 2);
+           {
+               len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / WCLEN);
+               len *= WCLEN;
+           }
            else
-#endif
-               strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
+#endif /* UNICODE_SUPPORT */
+           strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
 
            if (len >= cbInfoValueMax)
            {
                result = SQL_SUCCESS_WITH_INFO;
-               CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the InfoValue.");
+               CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the InfoValue.", func);
            }
        }
+#ifdef UNICODE_SUPPORT
+       else if (conn->unicode)
+           len *= WCLEN;
+#endif /* UNICODE_SUPPORT */
    }
    else
    {
@@ -779,12 +794,10 @@ PGAPI_GetInfo(
        }
    }
 
-
    if (pcbInfoValue)
-       *pcbInfoValue = len;        
-   
-   mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax);
-   
+       *pcbInfoValue = len;
+cleanup:
+
    return result;
 }
 
@@ -792,60 +805,74 @@ PGAPI_GetInfo(
 RETCODE        SQL_API
 PGAPI_GetTypeInfo(
                  HSTMT hstmt,
-                 SWORD fSqlType)
+                 SQLSMALLINT fSqlType)
 {
    CSTR func = "PGAPI_GetTypeInfo";
    StatementClass *stmt = (StatementClass *) hstmt;
    QResultClass    *res;
-   TupleNode  *row;
+   TupleField  *tuple;
    int         i, result_cols;
 
    /* Int4 type; */
    Int4        pgType;
    Int2        sqlType;
-   RETCODE     result;
+   RETCODE     result = SQL_SUCCESS;
 
    mylog("%s: entering...fSqlType = %d\n", func, fSqlType);
 
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
        return result;
 
-   stmt->manual_result = TRUE;
    if (res = QR_Constructor(), !res)
    {
-       SC_log_error(func, "Error creating result.", stmt);
+       SC_set_error(stmt, STMT_INTERNAL_ERROR, "Error creating result.", func);
        return SQL_ERROR;
    }
    SC_set_Result(stmt, res);
 
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
+#if (ODBCVER >= 0x0300)
    result_cols = 19;
+#else
+   result_cols = 15;
+#endif /* ODBCVER */
    extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
+   stmt->catalog_result = TRUE;
    QR_set_num_fields(res, result_cols);
-   QR_set_field_info(res, 0, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 1, "DATA_TYPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 2, "PRECISION", PG_TYPE_INT4, 4);
-   QR_set_field_info(res, 3, "LITERAL_PREFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 4, "LITERAL_SUFFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 5, "CREATE_PARAMS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 6, "NULLABLE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 8, "SEARCHABLE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 10, "MONEY", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 15, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 16, "SQL_DATATIME_SUB", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 17, "NUM_PREC_RADIX", PG_TYPE_INT4, 4);
-   QR_set_field_info(res, 18, "INTERVAL_PRECISION", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 0, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 1, "DATA_TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 2, "PRECISION", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, 3, "LITERAL_PREFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 4, "LITERAL_SUFFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 5, "CREATE_PARAMS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 6, "NULLABLE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 8, "SEARCHABLE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 10, "MONEY", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
+#if (ODBCVER >=0x0300)
+   QR_set_field_info_v(res, 15, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 16, "SQL_DATATIME_SUB", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 17, "NUM_PREC_RADIX", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, 18, "INTERVAL_PRECISION", PG_TYPE_INT2, 2);
+#endif /* ODBCVER */
 
    for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i])
    {
        pgType = sqltype_to_pgtype(stmt, sqlType);
 
+if (sqlType == SQL_LONGVARBINARY)
+{
+ConnInfo   *ci = &(SC_get_conn(stmt)->connInfo);
+inolog("%d sqltype=%d -> pgtype=%d\n", ci->bytea_as_longvarbinary, sqlType, pgType);
+}
+
        if (fSqlType == SQL_ALL_TYPES || fSqlType == sqlType)
        {
            int pgtcount = 1, cnt;
@@ -854,75 +881,80 @@ PGAPI_GetTypeInfo(
                pgtcount = 2;
            for (cnt = 0; cnt < pgtcount; cnt ++)
            {
+               tuple = QR_AddNew(res);
 
-           SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField)),
-               stmt, "Couldn't alloc row", SQL_ERROR)
-
-           /* These values can't be NULL */
-           if (1 == cnt)
-           {
-               set_tuplefield_string(&row->tuple[0], "serial");
-               set_tuplefield_int2(&row->tuple[6], SQL_NO_NULLS);
+               /* These values can't be NULL */
+               if (1 == cnt)
+               {
+                   set_tuplefield_string(&tuple[0], "serial");
+                   set_tuplefield_int2(&tuple[6], SQL_NO_NULLS);
 inolog("serial in\n");
-           }
-           else
-           {
-               set_tuplefield_string(&row->tuple[0], pgtype_to_name(stmt, pgType));
-               set_tuplefield_int2(&row->tuple[6], pgtype_nullable(stmt, pgType));
-           }
-           set_tuplefield_int2(&row->tuple[1], (Int2) sqlType);
-           set_tuplefield_int2(&row->tuple[7], pgtype_case_sensitive(stmt, pgType));
-           set_tuplefield_int2(&row->tuple[8], pgtype_searchable(stmt, pgType));
-           set_tuplefield_int2(&row->tuple[10], pgtype_money(stmt, pgType));
+               }
+               else
+               {
+                   set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType));
+                   set_tuplefield_int2(&tuple[6], pgtype_nullable(stmt, pgType));
+               }
+               set_tuplefield_int2(&tuple[1], (Int2) sqlType);
+               set_tuplefield_int2(&tuple[7], pgtype_case_sensitive(stmt, pgType));
+               set_tuplefield_int2(&tuple[8], pgtype_searchable(stmt, pgType));
+               set_tuplefield_int2(&tuple[10], pgtype_money(stmt, pgType));
 
            /*
             * Localized data-source dependent data type name (always
             * NULL)
             */
-           set_tuplefield_null(&row->tuple[12]);
-
-           /* These values can be NULL */
-           set_nullfield_int4(&row->tuple[2], pgtype_column_size(stmt, pgType, PG_STATIC, PG_STATIC));
-           set_nullfield_string(&row->tuple[3], pgtype_literal_prefix(stmt, pgType));
-           set_nullfield_string(&row->tuple[4], pgtype_literal_suffix(stmt, pgType));
-           set_nullfield_string(&row->tuple[5], pgtype_create_params(stmt, pgType));
-           if (1 == cnt)
-           {
-               set_nullfield_int2(&row->tuple[9], TRUE);
-               set_nullfield_int2(&row->tuple[11], TRUE);
-           }
-           else
-           {
-               set_nullfield_int2(&row->tuple[9], pgtype_unsigned(stmt, pgType));
-               set_nullfield_int2(&row->tuple[11], pgtype_auto_increment(stmt, pgType));
-           }
-           set_nullfield_int2(&row->tuple[13], pgtype_min_decimal_digits(stmt, pgType));
-           set_nullfield_int2(&row->tuple[14], pgtype_max_decimal_digits(stmt, pgType));
-           set_nullfield_int2(&row->tuple[15], pgtype_to_sqldesctype(stmt, pgType, PG_STATIC));
-           set_nullfield_int2(&row->tuple[16], pgtype_to_datetime_sub(stmt, pgType));
-           set_nullfield_int4(&row->tuple[17], pgtype_radix(stmt, pgType));
-           set_nullfield_int4(&row->tuple[18], 0);
-
-           QR_add_tuple(res, row);
-
+               set_tuplefield_null(&tuple[12]);
+
+               /* These values can be NULL */
+               set_nullfield_int4(&tuple[2], pgtype_column_size(stmt, pgType, PG_STATIC, PG_STATIC));
+               set_nullfield_string(&tuple[3], pgtype_literal_prefix(stmt, pgType));
+               set_nullfield_string(&tuple[4], pgtype_literal_suffix(stmt, pgType));
+               set_nullfield_string(&tuple[5], pgtype_create_params(stmt, pgType));
+               if (1 == cnt)
+               {
+                   set_nullfield_int2(&tuple[9], TRUE);
+                   set_nullfield_int2(&tuple[11], TRUE);
+               }
+               else
+               {
+                   set_nullfield_int2(&tuple[9], pgtype_unsigned(stmt, pgType));
+                   set_nullfield_int2(&tuple[11], pgtype_auto_increment(stmt, pgType));
+               }
+               set_nullfield_int2(&tuple[13], pgtype_min_decimal_digits(stmt, pgType));
+               set_nullfield_int2(&tuple[14], pgtype_max_decimal_digits(stmt, pgType));
+#if (ODBCVER >=0x0300)
+               set_nullfield_int2(&tuple[15], pgtype_to_sqldesctype(stmt, pgType, PG_STATIC));
+               set_nullfield_int2(&tuple[16], pgtype_to_datetime_sub(stmt, pgType));
+               set_nullfield_int4(&tuple[17], pgtype_radix(stmt, pgType));
+               set_nullfield_int4(&tuple[18], 0);
+#endif /* ODBCVER */
            }
        }
    }
 
+cleanup:
+#undef return
+   /*
+    * also, things need to think that this statement is finished so the
+    * results can be retrieved.
+    */
    stmt->status = STMT_FINISHED;
    stmt->currTuple = -1;
-   stmt->rowset_start = -1;
+   SC_set_rowset_start(stmt, -1, FALSE);
    SC_set_current_col(stmt, -1);
 
-   return SQL_SUCCESS;
+   if (stmt->internal)
+       result = DiscardStatementSvp(stmt, result, FALSE);
+   return result;
 }
 
 
 RETCODE        SQL_API
 PGAPI_GetFunctions(
                   HDBC hdbc,
-                  UWORD fFunction,
-                  UWORD FAR * pfExists)
+                  SQLUSMALLINT fFunction,
+                  SQLUSMALLINT FAR * pfExists)
 {
    CSTR func = "PGAPI_GetFunctions";
    ConnectionClass *conn = (ConnectionClass *) hdbc;
@@ -932,76 +964,108 @@ PGAPI_GetFunctions(
 
    if (fFunction == SQL_API_ALL_FUNCTIONS)
    {
-       memset(pfExists, 0, sizeof(UWORD) * 100);
-
-       /* ODBC core functions */
-       pfExists[SQL_API_SQLALLOCCONNECT] = TRUE;
-       pfExists[SQL_API_SQLALLOCENV] = TRUE;
-       pfExists[SQL_API_SQLALLOCSTMT] = TRUE;
-       pfExists[SQL_API_SQLBINDCOL] = TRUE;
-       pfExists[SQL_API_SQLCANCEL] = TRUE;
-       pfExists[SQL_API_SQLCOLATTRIBUTES] = TRUE;
-       pfExists[SQL_API_SQLCONNECT] = TRUE;
-       pfExists[SQL_API_SQLDESCRIBECOL] = TRUE;        /* partial */
-       pfExists[SQL_API_SQLDISCONNECT] = TRUE;
-       pfExists[SQL_API_SQLERROR] = TRUE;
-       pfExists[SQL_API_SQLEXECDIRECT] = TRUE;
-       pfExists[SQL_API_SQLEXECUTE] = TRUE;
-       pfExists[SQL_API_SQLFETCH] = TRUE;
-       pfExists[SQL_API_SQLFREECONNECT] = TRUE;
-       pfExists[SQL_API_SQLFREEENV] = TRUE;
-       pfExists[SQL_API_SQLFREESTMT] = TRUE;
-       pfExists[SQL_API_SQLGETCURSORNAME] = TRUE;
-       pfExists[SQL_API_SQLNUMRESULTCOLS] = TRUE;
-       pfExists[SQL_API_SQLPREPARE] = TRUE;            /* complete? */
-       pfExists[SQL_API_SQLROWCOUNT] = TRUE;
-       pfExists[SQL_API_SQLSETCURSORNAME] = TRUE;
-       pfExists[SQL_API_SQLSETPARAM] = FALSE;          /* odbc 1.0 */
-       pfExists[SQL_API_SQLTRANSACT] = TRUE;
-
-       /* ODBC level 1 functions */
-       pfExists[SQL_API_SQLBINDPARAMETER] = TRUE;
-       pfExists[SQL_API_SQLCOLUMNS] = TRUE;
-       pfExists[SQL_API_SQLDRIVERCONNECT] = TRUE;
-       pfExists[SQL_API_SQLGETCONNECTOPTION] = TRUE;       /* partial */
-       pfExists[SQL_API_SQLGETDATA] = TRUE;
-       pfExists[SQL_API_SQLGETFUNCTIONS] = TRUE;
-       pfExists[SQL_API_SQLGETINFO] = TRUE;
-       pfExists[SQL_API_SQLGETSTMTOPTION] = TRUE;      /* partial */
-       pfExists[SQL_API_SQLGETTYPEINFO] = TRUE;
-       pfExists[SQL_API_SQLPARAMDATA] = TRUE;
-       pfExists[SQL_API_SQLPUTDATA] = TRUE;
-       pfExists[SQL_API_SQLSETCONNECTOPTION] = TRUE;       /* partial */
-       pfExists[SQL_API_SQLSETSTMTOPTION] = TRUE;
-       pfExists[SQL_API_SQLSPECIALCOLUMNS] = TRUE;
-       pfExists[SQL_API_SQLSTATISTICS] = TRUE;
-       pfExists[SQL_API_SQLTABLES] = TRUE;
-
-       /* ODBC level 2 functions */
-       pfExists[SQL_API_SQLBROWSECONNECT] = FALSE;
-       pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
-       pfExists[SQL_API_SQLDATASOURCES] = FALSE;       /* only implemented by DM */
-       pfExists[SQL_API_SQLDESCRIBEPARAM] = FALSE;     /* not properly implemented */
-       pfExists[SQL_API_SQLDRIVERS] = FALSE;           /* only implemented by DM */
-       pfExists[SQL_API_SQLEXTENDEDFETCH] = TRUE;
-       pfExists[SQL_API_SQLFOREIGNKEYS] = TRUE;
-       pfExists[SQL_API_SQLMORERESULTS] = TRUE;
-       pfExists[SQL_API_SQLNATIVESQL] = TRUE;
-       pfExists[SQL_API_SQLNUMPARAMS] = TRUE;
-       pfExists[SQL_API_SQLPARAMOPTIONS] = TRUE;
-       pfExists[SQL_API_SQLPRIMARYKEYS] = TRUE;
-       if (PG_VERSION_LT(conn, 6.5))
-           pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
-       else
-           pfExists[SQL_API_SQLPROCEDURECOLUMNS] = TRUE;
-       if (PG_VERSION_LT(conn, 6.5))
-           pfExists[SQL_API_SQLPROCEDURES] = FALSE;
+#if (ODBCVER < 0x0300)
+       if (ci->drivers.lie)
+       {
+           int         i;
+
+           memset(pfExists, 0, sizeof(UWORD) * 100);
+
+           pfExists[SQL_API_SQLALLOCENV] = TRUE;
+           pfExists[SQL_API_SQLFREEENV] = TRUE;
+           for (i = SQL_API_SQLALLOCCONNECT; i <= SQL_NUM_FUNCTIONS; i++)
+               pfExists[i] = TRUE;
+           for (i = SQL_EXT_API_START; i <= SQL_EXT_API_LAST; i++)
+               pfExists[i] = TRUE;
+       }
        else
-           pfExists[SQL_API_SQLPROCEDURES] = TRUE;
-       pfExists[SQL_API_SQLSETPOS] = TRUE;
-       pfExists[SQL_API_SQLSETSCROLLOPTIONS] = FALSE;      /* odbc 1.0 */
-       pfExists[SQL_API_SQLTABLEPRIVILEGES] = TRUE;
-       pfExists[SQL_API_SQLBULKOPERATIONS] = TRUE;
+#endif
+       {
+           memset(pfExists, 0, sizeof(UWORD) * 100);
+
+           /* ODBC core functions */
+           pfExists[SQL_API_SQLALLOCCONNECT] = TRUE;
+           pfExists[SQL_API_SQLALLOCENV] = TRUE;
+           pfExists[SQL_API_SQLALLOCSTMT] = TRUE;
+           pfExists[SQL_API_SQLBINDCOL] = TRUE;
+           pfExists[SQL_API_SQLCANCEL] = TRUE;
+           pfExists[SQL_API_SQLCOLATTRIBUTES] = TRUE;
+           pfExists[SQL_API_SQLCONNECT] = TRUE;
+           pfExists[SQL_API_SQLDESCRIBECOL] = TRUE;    /* partial */
+           pfExists[SQL_API_SQLDISCONNECT] = TRUE;
+           pfExists[SQL_API_SQLERROR] = TRUE;
+           pfExists[SQL_API_SQLEXECDIRECT] = TRUE;
+           pfExists[SQL_API_SQLEXECUTE] = TRUE;
+           pfExists[SQL_API_SQLFETCH] = TRUE;
+           pfExists[SQL_API_SQLFREECONNECT] = TRUE;
+           pfExists[SQL_API_SQLFREEENV] = TRUE;
+           pfExists[SQL_API_SQLFREESTMT] = TRUE;
+           pfExists[SQL_API_SQLGETCURSORNAME] = TRUE;
+           pfExists[SQL_API_SQLNUMRESULTCOLS] = TRUE;
+           pfExists[SQL_API_SQLPREPARE] = TRUE;        /* complete? */
+           pfExists[SQL_API_SQLROWCOUNT] = TRUE;
+           pfExists[SQL_API_SQLSETCURSORNAME] = TRUE;
+           pfExists[SQL_API_SQLSETPARAM] = FALSE;      /* odbc 1.0 */
+           pfExists[SQL_API_SQLTRANSACT] = TRUE;
+
+           /* ODBC level 1 functions */
+           pfExists[SQL_API_SQLBINDPARAMETER] = TRUE;
+           pfExists[SQL_API_SQLCOLUMNS] = TRUE;
+           pfExists[SQL_API_SQLDRIVERCONNECT] = TRUE;
+           pfExists[SQL_API_SQLGETCONNECTOPTION] = TRUE;       /* partial */
+           pfExists[SQL_API_SQLGETDATA] = TRUE;
+           pfExists[SQL_API_SQLGETFUNCTIONS] = TRUE;
+           pfExists[SQL_API_SQLGETINFO] = TRUE;
+           pfExists[SQL_API_SQLGETSTMTOPTION] = TRUE;  /* partial */
+           pfExists[SQL_API_SQLGETTYPEINFO] = TRUE;
+           pfExists[SQL_API_SQLPARAMDATA] = TRUE;
+           pfExists[SQL_API_SQLPUTDATA] = TRUE;
+           pfExists[SQL_API_SQLSETCONNECTOPTION] = TRUE;       /* partial */
+           pfExists[SQL_API_SQLSETSTMTOPTION] = TRUE;
+           pfExists[SQL_API_SQLSPECIALCOLUMNS] = TRUE;
+           pfExists[SQL_API_SQLSTATISTICS] = TRUE;
+           pfExists[SQL_API_SQLTABLES] = TRUE;
+
+           /* ODBC level 2 functions */
+           pfExists[SQL_API_SQLBROWSECONNECT] = FALSE;
+           if (PG_VERSION_GE(conn, 7.4))
+               pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
+           else
+               pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
+           pfExists[SQL_API_SQLDATASOURCES] = FALSE;   /* only implemented by
+                                                        * DM */
+           if (PROTOCOL_74(ci))
+               pfExists[SQL_API_SQLDESCRIBEPARAM] = TRUE;
+           else
+               pfExists[SQL_API_SQLDESCRIBEPARAM] = FALSE; /* not properly
+                                                        * implemented */
+           pfExists[SQL_API_SQLDRIVERS] = FALSE;       /* only implemented by
+                                                        * DM */
+           pfExists[SQL_API_SQLEXTENDEDFETCH] = TRUE;
+           pfExists[SQL_API_SQLFOREIGNKEYS] = TRUE;
+           pfExists[SQL_API_SQLMORERESULTS] = TRUE;
+           pfExists[SQL_API_SQLNATIVESQL] = TRUE;
+           pfExists[SQL_API_SQLNUMPARAMS] = TRUE;
+           pfExists[SQL_API_SQLPARAMOPTIONS] = TRUE;
+           pfExists[SQL_API_SQLPRIMARYKEYS] = TRUE;
+           if (PG_VERSION_LT(conn, 6.5))
+               pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
+           else
+               pfExists[SQL_API_SQLPROCEDURECOLUMNS] = TRUE;
+           if (PG_VERSION_LT(conn, 6.5))
+               pfExists[SQL_API_SQLPROCEDURES] = FALSE;
+           else
+               pfExists[SQL_API_SQLPROCEDURES] = TRUE;
+           pfExists[SQL_API_SQLSETPOS] = TRUE;
+           pfExists[SQL_API_SQLSETSCROLLOPTIONS] = TRUE;       /* odbc 1.0 */
+           pfExists[SQL_API_SQLTABLEPRIVILEGES] = TRUE;
+#if (ODBCVER >= 0x0300)
+           if (0 == ci->updatable_cursors)
+               pfExists[SQL_API_SQLBULKOPERATIONS] = FALSE;
+           else
+               pfExists[SQL_API_SQLBULKOPERATIONS] = TRUE;
+#endif /* ODBCVER */
+       }
    }
    else
    {
@@ -1011,13 +1075,28 @@ PGAPI_GetFunctions(
        {
            switch (fFunction)
            {
+#if (ODBCVER < 0x0300)
+               case SQL_API_SQLALLOCCONNECT:
+                   *pfExists = TRUE;
+                   break;
+               case SQL_API_SQLALLOCENV:
+                   *pfExists = TRUE;
+                   break;
+               case SQL_API_SQLALLOCSTMT:
+                   *pfExists = TRUE;
+                   break;
+#endif /* ODBCVER */
                case SQL_API_SQLBINDCOL:
                    *pfExists = TRUE;
                    break;
                case SQL_API_SQLCANCEL:
                    *pfExists = TRUE;
                    break;
+#if (ODBCVER >= 0x0300)
                case SQL_API_SQLCOLATTRIBUTE:
+#else
+               case SQL_API_SQLCOLATTRIBUTES:
+#endif /* ODBCVER */
                    *pfExists = TRUE;
                    break;
                case SQL_API_SQLCONNECT:
@@ -1029,6 +1108,11 @@ PGAPI_GetFunctions(
                case SQL_API_SQLDISCONNECT:
                    *pfExists = TRUE;
                    break;
+#if (ODBCVER < 0x0300)
+               case SQL_API_SQLERROR:
+                   *pfExists = TRUE;
+                   break;
+#endif /* ODBCVER */
                case SQL_API_SQLEXECDIRECT:
                    *pfExists = TRUE;
                    break;
@@ -1038,6 +1122,14 @@ PGAPI_GetFunctions(
                case SQL_API_SQLFETCH:
                    *pfExists = TRUE;
                    break;
+#if (ODBCVER < 0x0300)
+               case SQL_API_SQLFREECONNECT:
+                   *pfExists = TRUE;
+                   break;
+               case SQL_API_SQLFREEENV:
+                   *pfExists = TRUE;
+                   break;
+#endif /* ODBCVER */
                case SQL_API_SQLFREESTMT:
                    *pfExists = TRUE;
                    break;
@@ -1056,7 +1148,16 @@ PGAPI_GetFunctions(
                case SQL_API_SQLSETCURSORNAME:
                    *pfExists = TRUE;
                    break;
-               /* ODBC level 1 functions */
+#if (ODBCVER < 0x0300)
+               case SQL_API_SQLSETPARAM:
+                   *pfExists = FALSE;
+                   break;      /* odbc 1.0 */
+               case SQL_API_SQLTRANSACT:
+                   *pfExists = TRUE;
+                   break;
+#endif /* ODBCVER */
+
+                   /* ODBC level 1 functions */
                case SQL_API_SQLBINDPARAMETER:
                    *pfExists = TRUE;
                    break;
@@ -1066,6 +1167,11 @@ PGAPI_GetFunctions(
                case SQL_API_SQLDRIVERCONNECT:
                    *pfExists = TRUE;
                    break;
+#if (ODBCVER < 0x0300)
+               case SQL_API_SQLGETCONNECTOPTION:
+                   *pfExists = TRUE;
+                   break;      /* partial */
+#endif /* ODBCVER */
                case SQL_API_SQLGETDATA:
                    *pfExists = TRUE;
                    break;
@@ -1075,6 +1181,11 @@ PGAPI_GetFunctions(
                case SQL_API_SQLGETINFO:
                    *pfExists = TRUE;
                    break;
+#if (ODBCVER < 0x0300)
+               case SQL_API_SQLGETSTMTOPTION:
+                   *pfExists = TRUE;
+                   break;      /* partial */
+#endif /* ODBCVER */
                case SQL_API_SQLGETTYPEINFO:
                    *pfExists = TRUE;
                    break;
@@ -1084,6 +1195,14 @@ PGAPI_GetFunctions(
                case SQL_API_SQLPUTDATA:
                    *pfExists = TRUE;
                    break;
+#if (ODBCVER < 0x0300)
+               case SQL_API_SQLSETCONNECTOPTION:
+                   *pfExists = TRUE;
+                   break;      /* partial */
+               case SQL_API_SQLSETSTMTOPTION:
+                   *pfExists = TRUE;
+                   break;
+#endif /* ODBCVER */
                case SQL_API_SQLSPECIALCOLUMNS:
                    *pfExists = TRUE;
                    break;
@@ -1094,7 +1213,7 @@ PGAPI_GetFunctions(
                    *pfExists = TRUE;
                    break;
 
-               /* ODBC level 2 functions */
+                   /* ODBC level 2 functions */
                case SQL_API_SQLBROWSECONNECT:
                    *pfExists = FALSE;
                    break;
@@ -1105,7 +1224,10 @@ PGAPI_GetFunctions(
                    *pfExists = FALSE;
                    break;      /* only implemented by DM */
                case SQL_API_SQLDESCRIBEPARAM:
-                   *pfExists = FALSE;
+                   if (PROTOCOL_74(ci))
+                       *pfExists = TRUE;
+                   else
+                       *pfExists = FALSE;
                    break;      /* not properly implemented */
                case SQL_API_SQLDRIVERS:
                    *pfExists = FALSE;
@@ -1125,6 +1247,11 @@ PGAPI_GetFunctions(
                case SQL_API_SQLNUMPARAMS:
                    *pfExists = TRUE;
                    break;
+#if (ODBCVER < 0x0300)
+               case SQL_API_SQLPARAMOPTIONS:
+                   *pfExists = TRUE;
+                   break;
+#endif /* ODBCVER */
                case SQL_API_SQLPRIMARYKEYS:
                    *pfExists = TRUE;
                    break;
@@ -1143,9 +1270,15 @@ PGAPI_GetFunctions(
                case SQL_API_SQLSETPOS:
                    *pfExists = TRUE;
                    break;
+#if (ODBCVER < 0x0300)
+               case SQL_API_SQLSETSCROLLOPTIONS:
+                   *pfExists = TRUE;
+                   break;      /* odbc 1.0 */
+#endif /* ODBCVER */
                case SQL_API_SQLTABLEPRIVILEGES:
                    *pfExists = TRUE;
                    break;
+#if (ODBCVER >= 0x0300)
                case SQL_API_SQLBULKOPERATIONS: /* 24 */
                case SQL_API_SQLALLOCHANDLE:    /* 1001 */
                case SQL_API_SQLBINDPARAM:  /* 1002 */
@@ -1170,6 +1303,7 @@ PGAPI_GetFunctions(
                case SQL_API_SQLCOPYDESC:   /* 1004 */
                    *pfExists = FALSE;
                    break;
+#endif /* ODBCVER */
                default:
                    *pfExists = FALSE;
                    break;
@@ -1187,21 +1321,21 @@ PGAPI_GetFunctions(
 RETCODE        SQL_API
 PGAPI_Tables(
             HSTMT hstmt,
-            UCHAR FAR * szTableQualifier,
-            SWORD cbTableQualifier,
-            UCHAR FAR * szTableOwner,
-            SWORD cbTableOwner,
-            UCHAR FAR * szTableName,
-            SWORD cbTableName,
-            UCHAR FAR * szTableType,
-            SWORD cbTableType)
+            const SQLCHAR FAR * szTableQualifier, /* PV */
+            SQLSMALLINT cbTableQualifier,
+            const SQLCHAR FAR * szTableOwner, /* PV */
+            SQLSMALLINT cbTableOwner,
+            const SQLCHAR FAR * szTableName, /* PV */
+            SQLSMALLINT cbTableName,
+            const SQLCHAR FAR * szTableType,
+            SQLSMALLINT cbTableType)
 {
    CSTR func = "PGAPI_Tables";
    StatementClass *stmt = (StatementClass *) hstmt;
    StatementClass *tbl_stmt;
    QResultClass    *res;
-   TupleNode  *row;
-   HSTMT       htbl_stmt;
+   TupleField  *tuple;
+   HSTMT       htbl_stmt = NULL;
    RETCODE     ret = SQL_ERROR, result;
    char       *tableType;
    char        tables_query[INFO_INQUIRY_LEN];
@@ -1219,37 +1353,35 @@ PGAPI_Tables(
                table_types[MAX_INFO_STRING];
    char        show_system_tables,
                show_regular_tables,
-               show_views,
-               remarks[254]; /*Added for holding Table Description, if any.*/
+               show_views;
    char        regular_table,
                view,
                systable;
    int         i;
-   SWORD           internal_asis_type = SQL_C_CHAR, cbSchemaName;
-   const char *likeeq = "like", *szSchemaName;
+   SQLSMALLINT     internal_asis_type = SQL_C_CHAR, cbSchemaName;
+   CSTR    likeeq = "like";
+   const char  *szSchemaName;
 
-   mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
+   mylog("%s: entering...stmt=%x scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
 
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
        return result;
 
-   stmt->manual_result = TRUE;
-   stmt->errormsg_created = TRUE;
-
    conn = SC_get_conn(stmt);
    ci = &(conn->connInfo);
 
    result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Tables result.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Tables result.", func);
        return SQL_ERROR;
    }
    tbl_stmt = (StatementClass *) htbl_stmt;
    szSchemaName = szTableOwner;
    cbSchemaName = cbTableOwner;
 
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
 retry_public_schema:
    /*
     * Create the query to find out the tables
@@ -1257,19 +1389,9 @@ retry_public_schema:
    if (conn->schema_support)
    {
        /* view is represented by its relkind since 7.1 */
-
-       /* Previously it was:
-        * strcpy(tables_query, "select relname, nspname, relkind"
-        * from pg_catalog.pg_class c, pg_catalog.pg_namespace n");
-        * strcat(tables_query, " where relkind in ('r', 'v')");
-        * Modified query to retrieve the description of the table:
-        */ 
-
-       strcpy(tables_query,"SELECT DISTINCT tt.relname, tt.nspname, tt.relkind, COALESCE(d.description,'') from");
-        strcat(tables_query," (SELECT c.oid as oid, c.tableoid as tableoid, n.nspname as nspname, c.relname, c.relkind");
-       strcat(tables_query," FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
-       strcat(tables_query," WHERE c.relkind IN ('r', 'v') ");
-
+       strcpy(tables_query, "select relname, nspname, relkind"
+       " from pg_catalog.pg_class c, pg_catalog.pg_namespace n");
+       strcat(tables_query, " where relkind in ('r', 'v')");
    }
    else if (PG_VERSION_GE(conn, 7.1))
    {
@@ -1277,7 +1399,6 @@ retry_public_schema:
        strcpy(tables_query, "select relname, usename, relkind"
        " from pg_class c, pg_user u");
        strcat(tables_query, " where relkind in ('r', 'v')");
-
    }
    else
    {
@@ -1286,12 +1407,14 @@ retry_public_schema:
    }
 
    if (conn->schema_support)
+   {
        schema_strcat1(tables_query, " and nspname %s '%.*s'", likeeq, szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
+       /* strcat(tables_query, " and pg_catalog.pg_table_is_visible(c.oid)"); */
+   }
    else
        my_strcat1(tables_query, " and usename %s '%.*s'", likeeq, szSchemaName, cbSchemaName);
    my_strcat1(tables_query, " and relname %s '%.*s'", likeeq, szTableName, cbTableName);
 
-
    /* Parse the extra systable prefix  */
    strcpy(prefixes, ci->drivers.extra_systable_prefixes);
    i = 0;
@@ -1300,7 +1423,7 @@ retry_public_schema:
 #else
    prefix[i] = strtok(prefixes, ";");
 #endif /* HAVE_STRTOK_R */
-   while (i < 31 && prefix[i])
+   while (i < sizeof(prefix) && prefix[i])
 #ifdef HAVE_STRTOK_R
        prefix[++i] = strtok_r(NULL, ";", &last);
 #else
@@ -1324,7 +1447,7 @@ retry_public_schema:
 #else
        table_type[i] = strtok(table_types, ",");
 #endif /* HAVE_STRTOK_R */
-       while (i < 31 && table_type[i])
+       while (i < sizeof(table_type) && table_type[i])
 #ifdef HAVE_STRTOK_R
            table_type[++i] = strtok_r(NULL, ",", &last);
 #else
@@ -1363,17 +1486,20 @@ retry_public_schema:
     */
    if (!atoi(ci->show_system_tables) && !show_system_tables)
    {
-       strcat(tables_query, " and relname !~ '^" POSTGRES_SYS_PREFIX);
-
-       /* Also filter out user-defined system table types */
-       i = 0;
-       while (prefix[i])
+       if (conn->schema_support)
+           strcat(tables_query, " and nspname not in ('pg_catalog', 'information_schema')");
+       else
        {
-           strcat(tables_query, "|^");
-           strcat(tables_query, prefix[i]);
-           i++;
+           strcat(tables_query, " and relname !~ '^" POSTGRES_SYS_PREFIX);
+
+           /* Also filter out user-defined system table types */
+           for (i = 0; prefix[i]; i++)
+           {
+               strcat(tables_query, "|^");
+               strcat(tables_query, prefix[i]);
+           }
+           strcat(tables_query, "'");
        }
-       strcat(tables_query, "'");
    }
 
    /* match users */
@@ -1382,24 +1508,14 @@ retry_public_schema:
        strcat(tables_query, " and relname !~ '^xinv[0-9]+'");
 
    if (conn->schema_support)
-   {
-       /* Previously it was:
-        * strcat(tables_query, " and n.oid = relnamespace order by nspname, relname");
-        * Modified query to retrieve the description of the table:
-        */ 
-
-       strcat(tables_query," ) AS tt LEFT JOIN pg_catalog.pg_description d ");
-       strcat(tables_query," ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)");
-       strcat(tables_query," order by nspname, relname");
-   }
-
+       strcat(tables_query, " and n.oid = relnamespace order by nspname, relname");
    else
        strcat(tables_query, " and usesysid = relowner order by relname");
 
    result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_full_error_copy(stmt, htbl_stmt);
+       SC_full_error_copy(stmt, htbl_stmt, FALSE);
        goto cleanup;
    }
 
@@ -1417,7 +1533,7 @@ retry_public_schema:
         */
        if (szSchemaName &&
            (cbSchemaName == SQL_NTS ||
-            cbSchemaName == (SWORD) strlen(user)) &&
+            cbSchemaName == (SQLSMALLINT) strlen(user)) &&
            strnicmp(szSchemaName, user, strlen(user)) == 0 &&
            stricmp(CC_get_current_schema(conn), pubstr) == 0)
        {
@@ -1426,17 +1542,15 @@ retry_public_schema:
            goto retry_public_schema;
        }
    }
-
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
    if (conn->unicode)
        internal_asis_type = INTERNAL_ASIS_TYPE;
-#endif
-
+#endif /* UNICODE_SUPPORT */
    result = PGAPI_BindCol(htbl_stmt, 1, internal_asis_type,
                           table_name, MAX_INFO_STRING, NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, tbl_stmt);
+       SC_error_copy(stmt, tbl_stmt, TRUE);
        goto cleanup;
    }
 
@@ -1444,31 +1558,20 @@ retry_public_schema:
                           table_owner, MAX_INFO_STRING, NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, tbl_stmt);
+       SC_error_copy(stmt, tbl_stmt, TRUE);
        goto cleanup;
    }
    result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
                           relkind_or_hasrules, MAX_INFO_STRING, NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, tbl_stmt);
+       SC_error_copy(stmt, tbl_stmt, TRUE);
        goto cleanup;
    }
 
-   /* Binds the description column to variable 'remarks' */
-
-   result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
-                              remarks, 254, NULL);
-   if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
-   {
-           SC_error_copy(stmt, tbl_stmt);
-           goto cleanup;
-   }
-
-
    if (res = QR_Constructor(), !res)
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Tables result.");
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Tables result.", func);
        goto cleanup;
    }
    SC_set_Result(stmt, res);
@@ -1481,13 +1584,14 @@ retry_public_schema:
     */
    extend_column_bindings(SC_get_ARDF(stmt), 5);
 
+   stmt->catalog_result = TRUE;
    /* set the field names */
    QR_set_num_fields(res, 5);
-   QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 3, "TABLE_TYPE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 4, "REMARKS", PG_TYPE_VARCHAR, 254);
+   QR_set_field_info_v(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 3, "TABLE_TYPE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 4, "REMARKS", PG_TYPE_VARCHAR, 254);
 
    /* add the tuples */
    result = PGAPI_Fetch(htbl_stmt);
@@ -1541,10 +1645,10 @@ retry_public_schema:
            (view && show_views) ||
            (regular_table && show_regular_tables))
        {
-           SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (5 - 1) * sizeof(TupleField)), stmt, "Couldn't alloc row", SQL_ERROR) 
+           tuple = QR_AddNew(res);
 
-           /*set_tuplefield_string(&row->tuple[0], "");*/
-           set_tuplefield_null(&row->tuple[0]);
+           /* set_tuplefield_null(&tuple[0]); */
+           set_tuplefield_string(&tuple[0], "");
 
            /*
             * I have to hide the table owner from Access, otherwise it
@@ -1552,75 +1656,115 @@ retry_public_schema:
             * is valid according to the ODBC SQL grammar, but Postgres
             * won't support it.)
             *
-            * set_tuplefield_string(&row->tuple[1], table_owner);
+            * set_tuplefield_string(&tuple[1], table_owner);
             */
 
            mylog("%s: table_name = '%s'\n", func, table_name);
 
            if (conn->schema_support)
-               set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
+               set_tuplefield_string(&tuple[1], GET_SCHEMA_NAME(table_owner));
            else
-               set_tuplefield_null(&row->tuple[1]);
-           set_tuplefield_string(&row->tuple[2], table_name);
-           set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
-           set_tuplefield_string(&row->tuple[4], remarks);
-           /*** set_tuplefield_string(&row->tuple[4], "TABLE"); ***/
-
-           QR_add_tuple(res, row);
+               set_tuplefield_null(&tuple[1]);
+           set_tuplefield_string(&tuple[2], table_name);
+           set_tuplefield_string(&tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
+           set_tuplefield_string(&tuple[4], "");
+           /*** set_tuplefield_string(&tuple[4], "TABLE"); ***/
        }
        result = PGAPI_Fetch(htbl_stmt);
    }
    if (result != SQL_NO_DATA_FOUND)
    {
-       SC_full_error_copy(stmt, htbl_stmt);
+       SC_full_error_copy(stmt, htbl_stmt, FALSE);
        goto cleanup;
    }
    ret = SQL_SUCCESS;
 
 cleanup:
+#undef return
    /*
     * also, things need to think that this statement is finished so the
     * results can be retrieved.
     */
    stmt->status = STMT_FINISHED;
-   if (SQL_ERROR == ret)
-       SC_log_error(func, "", stmt);
 
    /* set up the current tuple pointer for SQLFetch */
    stmt->currTuple = -1;
-   stmt->rowset_start = -1;
+   SC_set_rowset_start(stmt, -1, FALSE);
    SC_set_current_col(stmt, -1);
 
    if (htbl_stmt)
        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
-   mylog("%s: EXIT, stmt=%u, ret=%d\n", func, stmt, ret);
+   if (stmt->internal)
+       ret = DiscardStatementSvp(stmt, ret, FALSE);
+   mylog("%s: EXIT, stmt=%x, ret=%d\n", func, stmt, ret);
    return ret;
 }
 
+static char    *
+simpleCatalogEscape(const char *src, int srclen, char escape_ch, int *result_len, int ccsc)
+{
+   int i, outlen;
+   const char *in;
+   char    *dest = NULL;
+   BOOL    escape_in = FALSE;
+   encoded_str encstr;
+
+   if (result_len)
+       *result_len = 0;
+   if (!src || srclen == SQL_NULL_DATA)
+       return dest;
+   else if (srclen == SQL_NTS)
+       srclen = strlen(src);
+   if (srclen <= 0)
+       return dest;
+mylog("simple in=%s(%d)\n", src, srclen);
+   encoded_str_constr(&encstr, ccsc, src);
+   dest = malloc(2 * srclen + 1);
+   for (i = 0, in = src, outlen = 0; i < srclen; i++, in++)
+   {
+                encoded_nextchar(&encstr);
+                if (ENCODE_STATUS(encstr) != 0)
+                {
+                        dest[outlen++] = *in;
+                        continue;
+                }
+       if (LITERAL_QUOTE == *in ||
+           escape_ch == *in)
+           dest[outlen++] = *in;
+       dest[outlen++] = *in;
+   }
+   dest[outlen] = '\0';
+   if (result_len)
+       *result_len = outlen;
+mylog("simple output=%s(%d)\n", dest, outlen);
+   return dest;
+}
 
 /*
  * PostgreSQL needs 2 '\\' to escape '_' and '%'. 
  */
-static int
-reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len, int ccsc)
+static char    *
+adjustLikePattern(const char *src, int srclen, char escape_ch, int *result_len, int ccsc)
 {
    int i, outlen;
    const char *in;
+   char    *dest = NULL;
    BOOL    escape_in = FALSE;
    encoded_str encstr;
 
-   if (srclen == SQL_NULL_DATA)
-   {
-       dest[0] = '\0';
-       return STRCPY_NULL;
-   }
+   if (result_len)
+       *result_len = 0;
+   if (!src || srclen == SQL_NULL_DATA)
+       return dest;
    else if (srclen == SQL_NTS)
        srclen = strlen(src);
    if (srclen <= 0)
-       return STRCPY_FAIL;
+       return dest;
+mylog("adjust in=%s(%d)\n", src, srclen);
    encoded_str_constr(&encstr, ccsc, src);
-   for (i = 0, in = src, outlen = 0; i < srclen && outlen < dst_len; i++, in++)
+   dest = malloc(2 * srclen + 1);
+   for (i = 0, in = src, outlen = 0; i < srclen; i++, in++)
    {
                 encoded_nextchar(&encstr);
                 if (ENCODE_STATUS(encstr) != 0)
@@ -1634,46 +1778,56 @@ reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len,
            {
                case '%':
                case '_':
-                   dest[outlen++] = '\\'; /* needs 1 more */
+                   if (escape_ch == ESCAPE_IN_LITERAL)
+                       dest[outlen++] = ESCAPE_IN_LITERAL; /* and insert 1 more LEXER escape */
+                   dest[outlen++] = escape_ch;
                    break;
                default:
-                   dest[outlen++] = '\\';
-                   if (outlen < dst_len)
-                       dest[outlen++] = '\\';
-                   if (outlen < dst_len)
-                       dest[outlen++] = '\\';
+                   if (escape_ch == ESCAPE_IN_LITERAL)
+                       dest[outlen++] = ESCAPE_IN_LITERAL;
+                   dest[outlen++] = escape_ch;
+                   if (escape_ch == ESCAPE_IN_LITERAL)
+                       dest[outlen++] = ESCAPE_IN_LITERAL;
+                   dest[outlen++] = escape_ch;
                    break;
            }
        }
-       if (*in == '\\')
+       if (*in == escape_ch)
            escape_in = TRUE;
        else
+       {
            escape_in = FALSE;
-       if (outlen < dst_len)
+           if (LITERAL_QUOTE == *in)
+               dest[outlen++] = *in;
            dest[outlen++] = *in;
+       }
    }
-   if (outlen < dst_len)
-       dest[outlen] = '\0';
-   return outlen;
+   dest[outlen] = '\0';
+   if (result_len)
+       *result_len = outlen;
+mylog("adjust output=%s(%d)\n", dest, outlen);
+   return dest;
 }
 
 RETCODE        SQL_API
 PGAPI_Columns(
              HSTMT hstmt,
-             UCHAR FAR * szTableQualifier,
-             SWORD cbTableQualifier,
-             UCHAR FAR * szTableOwner,
-             SWORD cbTableOwner,
-             UCHAR FAR * szTableName,
-             SWORD cbTableName,
-             UCHAR FAR * szColumnName,
-             SWORD cbColumnName,
-             UWORD flag)
+             const SQLCHAR FAR * szTableQualifier, /* OA */
+             SQLSMALLINT cbTableQualifier,
+             const SQLCHAR FAR * szTableOwner, /* PV */
+             SQLSMALLINT cbTableOwner,
+             const SQLCHAR FAR * szTableName, /* PV */
+             SQLSMALLINT cbTableName,
+             const SQLCHAR FAR * szColumnName, /* PV */
+             SQLSMALLINT cbColumnName,
+             UWORD flag,
+             UInt4 reloid,
+             Int2  attnum)
 {
    CSTR func = "PGAPI_Columns";
    StatementClass *stmt = (StatementClass *) hstmt;
    QResultClass    *res;
-   TupleNode  *row;
+   TupleField  *tuple;
    HSTMT       hcol_stmt = NULL;
    StatementClass *col_stmt;
    char        columns_query[INFO_INQUIRY_LEN];
@@ -1695,106 +1849,127 @@ PGAPI_Columns(
    char        useStaticPrecision, useStaticScale;
    char        not_null[MAX_INFO_STRING],
                relhasrules[MAX_INFO_STRING], relkind[8];
-   BOOL        relisaview;
+   char    *escSchemaName = NULL, *escTableName = NULL, *escColumnName = NULL;
+   BOOL    search_pattern, search_by_ids, relisaview;
    ConnInfo   *ci;
    ConnectionClass *conn;
-   SWORD       internal_asis_type = SQL_C_CHAR, cbSchemaName;
-   const char *likeeq = "like", *szSchemaName;
+   SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
+   const char  *like_or_eq;
+   const char  *szSchemaName;
 
-   mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
+   mylog("%s: entering...stmt=%x scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
 
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
        return result;
 
-   stmt->manual_result = TRUE;
-   stmt->errormsg_created = TRUE;
-
    conn = SC_get_conn(stmt);
    ci = &(conn->connInfo);
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
    if (conn->unicode)
        internal_asis_type = INTERNAL_ASIS_TYPE;
-#endif
+#endif /* UNICODE_SUPPORT */
    szSchemaName = szTableOwner;
    cbSchemaName = cbTableOwner;
 
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
+   search_by_ids = ((flag & PODBC_SEARCH_BY_IDS) != 0);
+   if (search_by_ids)
+   {
+       szSchemaName = NULL;
+       cbSchemaName = SQL_NULL_DATA;
+   }
+   else
+   {
+       szSchemaName = szTableOwner;
+       cbSchemaName = cbTableOwner;
+       reloid = 0;
+       attnum = 0;
+       /*
+        *  TableName or ColumnName is ordinarily an pattern value,
+        */
+       search_pattern = ((flag & PODBC_NOT_SEARCH_PATTERN) == 0); 
+       if (search_pattern) 
+       {
+           like_or_eq = likeop;
+           escSchemaName = adjustLikePattern(szSchemaName, cbSchemaName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
+           escTableName = adjustLikePattern(szTableName, cbTableName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
+           escColumnName = adjustLikePattern(szColumnName, cbColumnName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
+       }
+       else
+       {
+           like_or_eq = eqop;
+           escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+           escTableName = simpleCatalogEscape(szTableName, cbTableName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+           escColumnName = simpleCatalogEscape(szColumnName, cbColumnName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+       }
+   }
 retry_public_schema:
    /*
     * Create the query to find out the columns (Note: pre 6.3 did not
     * have the atttypmod field)
     */
    if (conn->schema_support)
-       sprintf(columns_query, "select u.nspname, c.relname, a.attname, a.atttypid"
-      ", t.typname, a.attnum, a.attlen, %s, a.attnotnull, c.relhasrules, c.relkind"
-           " from pg_catalog.pg_namespace u, pg_catalog.pg_class c,"
-           " pg_catalog.pg_attribute a, pg_catalog.pg_type t"
-           " where u.oid = c.relnamespace"
-           " and (not a.attisdropped)"
-           " and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
-           "a.atttypmod");
-   else
-       sprintf(columns_query, "select u.usename, c.relname, a.attname, a.atttypid"
-      ", t.typname, a.attnum, a.attlen, %s, a.attnotnull, c.relhasrules, c.relkind"
-           " from pg_user u, pg_class c, pg_attribute a, pg_type t"
-           " where u.usesysid = c.relowner"
-     " and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
-           PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod");
-
-   if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) 
    {
-       my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
-       if (conn->schema_support)
-           schema_strcat(columns_query, " and u.nspname = '%.*s'", szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
+       strncpy(columns_query,
+           "select n.nspname, c.relname, a.attname, a.atttypid"
+           ", t.typname, a.attnum, a.attlen, a.atttypmod, a.attnotnull"
+           ", c.relhasrules, c.relkind, d.adsrc from (((pg_catalog.pg_class c"
+           " inner join pg_catalog.pg_namespace n on n.oid = c.relnamespace",
+           sizeof(columns_query));
+       if (search_by_ids)
+           snprintf(columns_query, sizeof(columns_query), "%s and c.oid = %u", columns_query, reloid);
        else
-           my_strcat(columns_query, " and u.usename = '%.*s'", szSchemaName, cbSchemaName);
-       my_strcat(columns_query, " and a.attname = '%.*s'", szColumnName, cbColumnName);
+       {
+           if (escTableName)
+               snprintf(columns_query, sizeof(columns_query), "%s and c.relname %s '%s'", columns_query, like_or_eq, escTableName);
+           schema_strcat1(columns_query, " and n.nspname %s '%.*s'", like_or_eq, escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
+       }
+       strcat(columns_query, ") inner join pg_catalog.pg_attribute a"
+           " on (not a.attisdropped) and a.attnum > 0");
+       if (search_by_ids)
+           snprintf(columns_query, sizeof(columns_query), "%s and a.attnum = %d", columns_query, attnum);
+       else if (escColumnName)
+           snprintf(columns_query, sizeof(columns_query), "%s and a.attname %s '%s'", columns_query, like_or_eq, escColumnName);
+       strcat(columns_query,
+           " and a.attrelid = c.oid) inner join pg_catalog.pg_type t"
+           " on t.oid = a.atttypid) left outer join pg_attrdef d"
+           " on a.atthasdef and d.adrelid = a.attrelid and d.adnum = a.attnum");
+       strcat(columns_query, " order by n.nspname, c.relname, attnum");
    }
    else
    {
-       char    esc_table_name[TABLE_NAME_STORAGE_LEN * 2];
-       int escTbnamelen;
-
-       escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc);
-       my_strcat1(columns_query, " and c.relname %s '%.*s'", likeeq, esc_table_name, escTbnamelen);
-       if (conn->schema_support)
-           schema_strcat1(columns_query, " and u.nspname %s '%.*s'", likeeq, szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
-       else
-           my_strcat1(columns_query, " and u.usename %s '%.*s'", likeeq, szSchemaName, cbSchemaName);
-       my_strcat1(columns_query, " and a.attname %s '%.*s'", likeeq, szColumnName, cbColumnName);
-   }
-
-   if ((!atoi(ci->show_system_tables)) &&
-       (((cbTableName != SQL_NTS) && (cbTableName < 4)) || (strncmp(szTableName,"pg_",3))))
-   {
-       if (conn->schema_support)
-           strcat(columns_query, "  and nspname !~ '^" POSTGRES_SYS_PREFIX "'");
-       else
-           strcat(columns_query, "  and relname !~ '^" POSTGRES_SYS_PREFIX "'");
-   }
-   /*
-    * give the output in the order the columns were defined when the
-    * table was created
-    */
-   if (conn->schema_support)
-       strcat(columns_query, " order by u.nspname, c.relname, attnum");
-   else
+       snprintf(columns_query, sizeof(columns_query),
+           "select u.usename, c.relname, a.attname, a.atttypid"
+           ", t.typname, a.attnum, a.attlen, %s, a.attnotnull"
+           ", c.relhasrules, c.relkind, NULL from pg_user u"
+           ", pg_class c, pg_attribute a, pg_type t where"
+           "  u.usesysid = c.relowner and c.oid= a.attrelid"
+           "  and a.atttypid = t.oid and (a.attnum > 0)",
+           PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod");
+       if (escTableName)
+           snprintf(columns_query, sizeof(columns_query), "%s and c.relname %s '%s'", columns_query, like_or_eq, escTableName);
+       my_strcat1(columns_query, " and u.usename %s '%.*s'", like_or_eq, szSchemaName, cbSchemaName);
+       if (escColumnName)
+           snprintf(columns_query, sizeof(columns_query), "%s and a.attname %s '%s'", columns_query, like_or_eq, escColumnName);
        strcat(columns_query, " order by c.relname, attnum");
+   }
 
    result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Columns result.");
-       SC_log_error(func, "", stmt);
-       return SQL_ERROR;
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Columns result.", func);
+       result = SQL_ERROR;
+       goto cleanup;
    }
    col_stmt = (StatementClass *) hcol_stmt;
 
-   mylog("%s: hcol_stmt = %u, col_stmt = %u\n", func, hcol_stmt, col_stmt);
+   mylog("%s: hcol_stmt = %x, col_stmt = %x\n", func, hcol_stmt, col_stmt);
 
    result = PGAPI_ExecDirect(hcol_stmt, columns_query, SQL_NTS, 0);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_full_error_copy(stmt, col_stmt);
+       SC_full_error_copy(stmt, col_stmt, FALSE);
        goto cleanup;
    }
 
@@ -1811,16 +1986,20 @@ retry_public_schema:
         * the current schema is 'public',
         * retry the 'public' schema.
         */
-       if (szSchemaName &&
+       if (!search_by_ids &&
+           szSchemaName &&
            (cbSchemaName == SQL_NTS ||
-            cbSchemaName == (SWORD) strlen(user)) &&
+            cbSchemaName == (SQLSMALLINT) strlen(user)) &&
            strnicmp(szSchemaName, user, strlen(user)) == 0 &&
            stricmp(CC_get_current_schema(conn), pubstr) == 0)
        {
            PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
            hcol_stmt = NULL;
+           if (escSchemaName)
+               free(escSchemaName);
            szSchemaName = pubstr;
            cbSchemaName = SQL_NTS;
+           escSchemaName = strdup(szSchemaName);
            goto retry_public_schema;
        }
    }
@@ -1829,7 +2008,7 @@ retry_public_schema:
                           table_owner, MAX_INFO_STRING, NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
+       SC_error_copy(stmt, col_stmt, TRUE);
        goto cleanup;
    }
 
@@ -1837,7 +2016,7 @@ retry_public_schema:
                           table_name, MAX_INFO_STRING, NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
+       SC_error_copy(stmt, col_stmt, TRUE);
        goto cleanup;
    }
 
@@ -1845,7 +2024,7 @@ retry_public_schema:
                           field_name, MAX_INFO_STRING, NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
+       SC_error_copy(stmt, col_stmt, TRUE);
        goto cleanup;
    }
 
@@ -1853,7 +2032,7 @@ retry_public_schema:
                           &field_type, 4, NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
+       SC_error_copy(stmt, col_stmt, TRUE);
        goto cleanup;
    }
 
@@ -1861,7 +2040,7 @@ retry_public_schema:
                           field_type_name, MAX_INFO_STRING, NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
+       SC_error_copy(stmt, col_stmt, TRUE);
        goto cleanup;
    }
 
@@ -1869,7 +2048,7 @@ retry_public_schema:
                           &field_number, MAX_INFO_STRING, NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
+       SC_error_copy(stmt, col_stmt, TRUE);
        goto cleanup;
    }
 
@@ -1877,7 +2056,7 @@ retry_public_schema:
                           &field_length, MAX_INFO_STRING, NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
+       SC_error_copy(stmt, col_stmt, TRUE);
        goto cleanup;
    }
 
@@ -1885,7 +2064,7 @@ retry_public_schema:
                           &mod_length, MAX_INFO_STRING, NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
+       SC_error_copy(stmt, col_stmt, TRUE);
        goto cleanup;
    }
 
@@ -1893,7 +2072,7 @@ retry_public_schema:
                           not_null, MAX_INFO_STRING, NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
+       SC_error_copy(stmt, col_stmt, TRUE);
        goto cleanup;
    }
 
@@ -1901,7 +2080,7 @@ retry_public_schema:
                           relhasrules, MAX_INFO_STRING, NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
+       SC_error_copy(stmt, col_stmt, TRUE);
        goto cleanup;
    }
 
@@ -1909,50 +2088,64 @@ retry_public_schema:
                           relkind, sizeof(relkind), NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
+       SC_error_copy(stmt, col_stmt, TRUE);
        goto cleanup;
    }
 
    if (res = QR_Constructor(), !res)
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Columns result.");
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Columns result.", func);
        goto cleanup;
    }
    SC_set_Result(stmt, res);
 
-   /* the binding structure for a statement is not set up until
+   /* the binding structure for a statement is not set up until */
+
+   /*
     * a statement is actually executed, so we'll have to do this
     * ourselves.
     */
+#if (ODBCVER >= 0x0300)
    reserved_cols = 18;
-
-   result_cols = reserved_cols + 2;
+#else
+   reserved_cols = 12;
+#endif /* ODBCVER */
+   result_cols = COLUMNS_LAST + 1;
    extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
+   stmt->catalog_result = TRUE;
    /* set the field names */
    QR_set_num_fields(res, result_cols);
-   QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 4, "DATA_TYPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 5, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 6, "PRECISION", PG_TYPE_INT4, 4); /* COLUMN_SIZE */
-   QR_set_field_info(res, 7, "LENGTH", PG_TYPE_INT4, 4); /* BUFFER_LENGTH */
-   QR_set_field_info(res, 8, "SCALE", PG_TYPE_INT2, 2); /* DECIMAL_DIGITS ***/
-   QR_set_field_info(res, 9, "RADIX", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 10, "NULLABLE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 11, "REMARKS", PG_TYPE_VARCHAR, 254);
-
+   QR_set_field_info_v(res, COLUMNS_CATALOG_NAME, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, COLUMNS_SCHEMA_NAME, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, COLUMNS_TABLE_NAME, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, COLUMNS_COLUMN_NAME, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, COLUMNS_DATA_TYPE, "DATA_TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, COLUMNS_TYPE_NAME, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, COLUMNS_PRECISION, "PRECISION", PG_TYPE_INT4, 4); /* COLUMN_SIZE */
+   QR_set_field_info_v(res, COLUMNS_LENGTH, "LENGTH", PG_TYPE_INT4, 4); /* BUFFER_LENGTH */
+   QR_set_field_info_v(res, COLUMNS_SCALE, "SCALE", PG_TYPE_INT2, 2); /* DECIMAL_DIGITS ***/
+   QR_set_field_info_v(res, COLUMNS_RADIX, "RADIX", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, COLUMNS_NULLABLE, "NULLABLE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, COLUMNS_REMARKS, "REMARKS", PG_TYPE_VARCHAR, 254);
+
+#if (ODBCVER >= 0x0300)
+   QR_set_field_info_v(res, COLUMNS_COLUMN_DEF, "COLUMN_DEF", PG_TYPE_VARCHAR, 254);
+   QR_set_field_info_v(res, COLUMNS_SQL_DATA_TYPE, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, COLUMNS_SQL_DATETIME_SUB, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, COLUMNS_CHAR_OCTET_LENGTH, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, COLUMNS_ORDINAL_POSITION, "ORDINAL_POSITION", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, COLUMNS_IS_NULLABLE, "IS_NULLABLE", PG_TYPE_VARCHAR, 254);
+#endif /* ODBCVER */
    /* User defined fields */
-   QR_set_field_info(res, 12, "COLUMN_DEF", PG_TYPE_INT4, 254);
-   QR_set_field_info(res, 13, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 14, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 15, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
-   QR_set_field_info(res, 16, "ORDINAL_POSITION", PG_TYPE_INT4, 4);
-   QR_set_field_info(res, 17, "IS_NULLABLE", PG_TYPE_VARCHAR, 254);
-   QR_set_field_info(res, reserved_cols, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
-   QR_set_field_info(res, reserved_cols + 1, "FIELD_TYPE", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, COLUMNS_DISPLAY_SIZE, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, COLUMNS_FIELD_TYPE, "FIELD_TYPE", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, COLUMNS_AUTO_INCREMENT, "AUTO_INCREMENT", PG_TYPE_INT4, 4);
+   if (reserved_cols != COLUMNS_DISPLAY_SIZE)
+   {
+       SC_set_error(stmt, STMT_INTERNAL_ERROR, "reserved_cols unmatch", func);
+       goto cleanup;
+   }
 
    ordinal = 1;
    result = PGAPI_Fetch(hcol_stmt);
@@ -1975,59 +2168,69 @@ retry_public_schema:
        {
            /* For OID fields */
            the_type = PG_TYPE_OID;
-           SC_MALLOC_return_with_error(row, TupleNode,
-            (sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField)),
-               stmt, "Couldn't alloc row", SQL_ERROR)
-
-           set_tuplefield_string(&row->tuple[0], "");
+           tuple = QR_AddNew(res);
+           set_tuplefield_string(&tuple[COLUMNS_CATALOG_NAME], "");
            /* see note in SQLTables() */
            if (conn->schema_support)
-               set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
+               set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
            else
-               set_tuplefield_string(&row->tuple[1], "");
-           set_tuplefield_string(&row->tuple[2], table_name);
-           set_tuplefield_string(&row->tuple[3], "oid");
+               set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], "");
+           set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
+           set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], "oid");
            sqltype = pgtype_to_concise_type(stmt, the_type, PG_STATIC);
-           set_tuplefield_int2(&row->tuple[4], sqltype);
-           set_tuplefield_string(&row->tuple[5], "OID");
-
-           set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
-           set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
-           set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
-           set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type));
-           set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
-           set_tuplefield_string(&row->tuple[11], "");
-           set_tuplefield_null(&row->tuple[12]);
-           set_tuplefield_int2(&row->tuple[13], sqltype);
-           set_tuplefield_null(&row->tuple[14]);
-           set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC));
-           set_tuplefield_int4(&row->tuple[16], ordinal);
-           set_tuplefield_string(&row->tuple[17], "No");
-           set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
-           set_tuplefield_int4(&row->tuple[reserved_cols + 1], the_type);
-
-           QR_add_tuple(res, row);
+           set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
+           set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], "OID");
+
+           set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
+           set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
+           set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
+           set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(stmt, the_type));
+           set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], SQL_NO_NULLS);
+           set_tuplefield_string(&tuple[COLUMNS_REMARKS], "");
+
+#if (ODBCVER >= 0x0300)
+           set_tuplefield_null(&tuple[COLUMNS_COLUMN_DEF]);
+           set_tuplefield_int2(&tuple[COLUMNS_SQL_DATA_TYPE], sqltype);
+           set_tuplefield_null(&tuple[COLUMNS_SQL_DATETIME_SUB]);
+           set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC));
+           set_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
+           set_tuplefield_string(&tuple[COLUMNS_IS_NULLABLE], "No");
+#endif /* ODBCVER */
+           set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
+           set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], the_type);
+           set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], TRUE);
            ordinal++;
        }
    }
 
    while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO))
    {
-       SC_MALLOC_return_with_error(row, TupleNode,
-       (sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField)),
-           stmt, "Couldn't alloc row", SQL_ERROR)
+       int auto_unique;
+       SQLLEN  len_needed;
+       char    *attdef;
+
+       attdef = NULL;
+       PGAPI_SetPos(hcol_stmt, 1, SQL_POSITION, 0);
+       PGAPI_GetData(hcol_stmt, 12, internal_asis_type, NULL, 0, &len_needed);
+       if (len_needed > 0)
+       {
+mylog("len_needed=%d\n", len_needed);
+           attdef = malloc(len_needed + 1);
+           PGAPI_GetData(hcol_stmt, 12, internal_asis_type, attdef, len_needed + 1, &len_needed);
+mylog(" and the data=%s\n", attdef);
+       } 
+       tuple = QR_AddNew(res);
 
        sqltype = SQL_TYPE_NULL;    /* unspecified */
-       set_tuplefield_string(&row->tuple[0], "");
+       set_tuplefield_string(&tuple[COLUMNS_CATALOG_NAME], "");
        /* see note in SQLTables() */
        if (conn->schema_support)
-           set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
+           set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
        else
-           set_tuplefield_string(&row->tuple[1], "");
-       set_tuplefield_string(&row->tuple[2], table_name);
-       set_tuplefield_string(&row->tuple[3], field_name);
-       set_tuplefield_string(&row->tuple[5], field_type_name);
-
+           set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], "");
+       set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
+       set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], field_name);
+       set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], field_type_name);
 
        /*----------
         * Some Notes about Postgres Data Types:
@@ -2042,8 +2245,8 @@ retry_public_schema:
         *
         *----------
         */
-       qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,name='%s'\n",
-            table_name, field_name, field_type, field_type_name);
+       qlog("%s: table='%s',field_name='%s',type=%d,name='%s'\n",
+            func, table_name, field_name, field_type, field_type_name);
 
        useStaticPrecision = TRUE;
        useStaticScale = TRUE;
@@ -2063,11 +2266,13 @@ retry_public_schema:
 
                mylog("%s: field type is NUMERIC: field_type = %d, mod_length=%d, precision=%d, scale=%d\n", func, field_type, mod_length, column_size, decimal_digits);
 
-               set_tuplefield_int4(&row->tuple[6], column_size);
-               set_tuplefield_int4(&row->tuple[7], column_size + 2);       /* sign+dec.point */
-               set_nullfield_int2(&row->tuple[8], decimal_digits);
-               set_tuplefield_null(&row->tuple[15]);
-               set_tuplefield_int4(&row->tuple[reserved_cols], column_size + 2);   /* sign+dec.point */
+               set_tuplefield_int4(&tuple[COLUMNS_PRECISION], column_size);
+               set_tuplefield_int4(&tuple[COLUMNS_LENGTH], column_size + 2);       /* sign+dec.point */
+               set_nullfield_int2(&tuple[COLUMNS_SCALE], decimal_digits);
+#if (ODBCVER >= 0x0300)
+               set_tuplefield_null(&tuple[COLUMNS_CHAR_OCTET_LENGTH]);
+#endif /* ODBCVER */
+               set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], column_size + 2); /* sign+dec.point */
            }
        }
        else if ((field_type == PG_TYPE_DATETIME) ||
@@ -2077,7 +2282,7 @@ retry_public_schema:
            {
                useStaticScale = FALSE;
 
-               set_nullfield_int2(&row->tuple[8], (Int2) mod_length);
+               set_nullfield_int2(&tuple[COLUMNS_SCALE], (Int2) mod_length);
            }
        }
 
@@ -2092,31 +2297,42 @@ retry_public_schema:
            /* if (mod_length > ci->drivers.max_varchar_size || mod_length <= 0) */
            if (mod_length <= 0)
                mod_length = ci->drivers.max_varchar_size;
+#ifdef __MS_REPORTS_ANSI_CHAR__
            if (mod_length > ci->drivers.max_varchar_size)
                sqltype = SQL_LONGVARCHAR;
            else
                sqltype = (field_type == PG_TYPE_BPCHAR) ? SQL_CHAR : SQL_VARCHAR;
+#else
+           if (mod_length > ci->drivers.max_varchar_size)
+               sqltype = (conn->unicode ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR);
+           else
+               sqltype = (field_type == PG_TYPE_BPCHAR) ? (conn->unicode ? SQL_WCHAR : SQL_CHAR) : (conn->unicode ? SQL_WVARCHAR : SQL_VARCHAR);
+#endif /* __MS_LOVES_REPORTS_CHAR__ */
 
            mylog("%s: field type is VARCHAR,BPCHAR: field_type = %d, mod_length = %d\n", func, field_type, mod_length);
 
-           set_tuplefield_int4(&row->tuple[6], mod_length);
-           set_tuplefield_int4(&row->tuple[7], mod_length);
-           set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, field_type, PG_STATIC, PG_STATIC));
-           set_tuplefield_int4(&row->tuple[reserved_cols], mod_length);
+           set_tuplefield_int4(&tuple[COLUMNS_PRECISION], mod_length);
+           set_tuplefield_int4(&tuple[COLUMNS_LENGTH], mod_length);
+#if (ODBCVER >= 0x0300)
+           set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, field_type, PG_STATIC, PG_STATIC));
+#endif /* ODBCVER */
+           set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], mod_length);
        }
 
        if (useStaticPrecision)
        {
            mylog("%s: field type is OTHER: field_type = %d, pgtype_length = %d\n", func, field_type, pgtype_buffer_length(stmt, field_type, PG_STATIC, PG_STATIC));
 
-           set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, field_type, PG_STATIC, PG_STATIC));
-           set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, field_type, PG_STATIC, PG_STATIC));
-           set_tuplefield_null(&row->tuple[15]);
-           set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC));
+           set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, field_type, PG_STATIC, PG_STATIC));
+           set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, field_type, PG_STATIC, PG_STATIC));
+#if (ODBCVER >= 0x0300)
+           set_tuplefield_null(&tuple[COLUMNS_CHAR_OCTET_LENGTH]);
+#endif /* ODBCVER */
+           set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC));
        }
        if (useStaticScale)
        {
-           set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC));
+           set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, field_type, PG_STATIC));
        }
 
        if (SQL_TYPE_NULL == sqltype)
@@ -2126,27 +2342,40 @@ retry_public_schema:
        }
        else
            concise_type = sqltype;
-       set_tuplefield_int2(&row->tuple[4], sqltype);
-
-       set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, field_type));
-       set_tuplefield_int2(&row->tuple[10], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(stmt, field_type)));
-       set_tuplefield_string(&row->tuple[11], "");
-       set_tuplefield_null(&row->tuple[12]);
-       set_tuplefield_int2(&row->tuple[13], concise_type);
-       set_nullfield_int2(&row->tuple[14], pgtype_to_datetime_sub(stmt, field_type));
-       set_tuplefield_int4(&row->tuple[16], ordinal);
-       set_tuplefield_null(&row->tuple[17]);
-       set_tuplefield_int4(&row->tuple[reserved_cols + 1], field_type);
-
-       QR_add_tuple(res, row);
+       set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
+
+       set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(stmt, field_type));
+       set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(stmt, field_type)));
+       set_tuplefield_string(&tuple[COLUMNS_REMARKS], "");
+#if (ODBCVER >= 0x0300)
+       if (attdef && strlen(attdef) > 254)
+           set_tuplefield_string(&tuple[COLUMNS_COLUMN_DEF], "TRUNCATE");
+       else
+           set_tuplefield_string(&tuple[COLUMNS_COLUMN_DEF], attdef);
+       set_tuplefield_int2(&tuple[COLUMNS_SQL_DATA_TYPE], concise_type);
+       set_nullfield_int2(&tuple[COLUMNS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, field_type));
+       set_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
+       set_tuplefield_null(&tuple[COLUMNS_IS_NULLABLE]);
+#endif /* ODBCVER */
+       set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], field_type);
+       auto_unique = FALSE;
+       switch (field_type)
+       {
+           case PG_TYPE_INT4:
+           case PG_TYPE_INT8:
+               if (attdef && strnicmp(attdef, "nextval(", 8) == 0) 
+                   auto_unique = TRUE;
+       }
+       set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], auto_unique);
        ordinal++;
 
        result = PGAPI_Fetch(hcol_stmt);
-
+       if (attdef)
+           free(attdef);
    }
    if (result != SQL_NO_DATA_FOUND)
    {
-       SC_full_error_copy(stmt, col_stmt);
+       SC_full_error_copy(stmt, col_stmt, FALSE);
        goto cleanup;
    }
 
@@ -2159,40 +2388,41 @@ retry_public_schema:
        /* For Row Versioning fields */
        the_type = PG_TYPE_INT4;
 
-       SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField)),
-           stmt, "Couldn't alloc row", SQL_ERROR)
+       tuple = QR_AddNew(res);
 
-       set_tuplefield_string(&row->tuple[0], "");
+       set_tuplefield_string(&tuple[COLUMNS_CATALOG_NAME], "");
        if (conn->schema_support)
-           set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
+           set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
        else
-           set_tuplefield_string(&row->tuple[1], "");
-       set_tuplefield_string(&row->tuple[2], table_name);
-       set_tuplefield_string(&row->tuple[3], "xmin");
+           set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], "");
+       set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
+       set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], "xmin");
        sqltype = pgtype_to_concise_type(stmt, the_type, PG_STATIC);
-       set_tuplefield_int2(&row->tuple[4], sqltype);
-       set_tuplefield_string(&row->tuple[5], pgtype_to_name(stmt, the_type));
-       set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
-       set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
-       set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
-       set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type));
-       set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
-       set_tuplefield_string(&row->tuple[11], "");
-       set_tuplefield_null(&row->tuple[12]);
-       set_tuplefield_int2(&row->tuple[13], sqltype);
-       set_tuplefield_null(&row->tuple[14]);
-       set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC));
-       set_tuplefield_int4(&row->tuple[16], ordinal);
-       set_tuplefield_string(&row->tuple[17], "No");
-       set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
-       set_tuplefield_int4(&row->tuple[reserved_cols + 1], the_type);
-
-       QR_add_tuple(res, row);
+       set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
+       set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], pgtype_to_name(stmt, the_type));
+       set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
+       set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
+       set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
+       set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(stmt, the_type));
+       set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], SQL_NO_NULLS);
+       set_tuplefield_string(&tuple[COLUMNS_REMARKS], "");
+#if (ODBCVER >= 0x0300)
+       set_tuplefield_null(&tuple[COLUMNS_COLUMN_DEF]);
+       set_tuplefield_int2(&tuple[COLUMNS_SQL_DATA_TYPE], sqltype);
+       set_tuplefield_null(&tuple[COLUMNS_SQL_DATETIME_SUB]);
+       set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC));
+       set_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
+       set_tuplefield_string(&tuple[COLUMNS_IS_NULLABLE], "No");
+#endif /* ODBCVER */
+       set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
+       set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], the_type);
+       set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], FALSE);
        ordinal++;
    }
    result = SQL_SUCCESS;
 
 cleanup:
+#undef return
    /*
     * also, things need to think that this statement is finished so the
     * results can be retrieved.
@@ -2201,61 +2431,74 @@ cleanup:
 
    /* set up the current tuple pointer for SQLFetch */
    stmt->currTuple = -1;
-   stmt->rowset_start = -1;
+   SC_set_rowset_start(stmt, -1, FALSE);
    SC_set_current_col(stmt, -1);
 
-   if (SQL_SUCCESS != result &&
-       SQL_SUCCESS_WITH_INFO != result)
-       SC_log_error(func, "", stmt);
+   if (escSchemaName)
+       free(escSchemaName);
+   if (escTableName)
+       free(escTableName);
+   if (escColumnName)
+       free(escColumnName);
    if (hcol_stmt)
        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
-   mylog("%s: EXIT,  stmt=%u\n", func, stmt);
+   if (stmt->internal)
+       result = DiscardStatementSvp(stmt, result, FALSE);
+   mylog("%s: EXIT,  stmt=%x\n", func, stmt);
    return result;
 }
 
 
 RETCODE        SQL_API
 PGAPI_SpecialColumns(
-                    HSTMT hstmt,
-                    UWORD fColType,
-                    UCHAR FAR * szTableQualifier,
-                    SWORD cbTableQualifier,
-                    UCHAR FAR * szTableOwner,
-                    SWORD cbTableOwner,
-                    UCHAR FAR * szTableName,
-                    SWORD cbTableName,
-                    UWORD fScope,
-                    UWORD fNullable)
+               HSTMT hstmt,
+               SQLUSMALLINT fColType,
+               const SQLCHAR FAR * szTableQualifier,
+               SQLSMALLINT cbTableQualifier,
+               const SQLCHAR FAR * szTableOwner, /* OA */
+               SQLSMALLINT cbTableOwner,
+               const SQLCHAR FAR * szTableName, /* OA(R) */
+               SQLSMALLINT cbTableName,
+               SQLUSMALLINT fScope,
+               SQLUSMALLINT fNullable)
 {
    CSTR func = "PGAPI_SpecialColumns";
-   TupleNode  *row;
+   TupleField  *tuple;
    StatementClass *stmt = (StatementClass *) hstmt;
    ConnectionClass *conn;
    QResultClass    *res;
    ConnInfo   *ci;
-   HSTMT       hcol_stmt;
+   HSTMT       hcol_stmt = NULL;
    StatementClass *col_stmt;
    char        columns_query[INFO_INQUIRY_LEN];
-   RETCODE     result;
+   char        *table_name = NULL, *escTableName = NULL;
+   RETCODE     result = SQL_SUCCESS;
    char        relhasrules[MAX_INFO_STRING], relkind[8], relhasoids[8];
    BOOL        relisaview;
-   SWORD       internal_asis_type = SQL_C_CHAR, cbSchemaName;
+   SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
    const char  *szSchemaName;
 
-   mylog("%s: entering...stmt=%u scnm=%x len=%d colType=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner, fColType);
+   mylog("%s: entering...stmt=%x scnm=%x len=%d colType=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner, fColType);
 
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
        return result;
    conn = SC_get_conn(stmt);
    ci = &(conn->connInfo);
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
    if (conn->unicode)
        internal_asis_type = INTERNAL_ASIS_TYPE;
-#endif
-   stmt->manual_result = TRUE;
+#endif /* UNICODE_SUPPORT */
+
    szSchemaName = szTableOwner;
    cbSchemaName = cbTableOwner;
 
+   if (!szTableName)
+   {
+       SC_set_error(stmt, STMT_INVALID_NULL_ARG, "The table name is required", func);
+       return result;
+   }
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
 retry_public_schema:
    /*
     * Create the query to find out if this is a view or not...
@@ -2272,7 +2515,11 @@ retry_public_schema:
            "u.usesysid = c.relowner");
 
    /* TableName cannot contain a string search pattern */
-   my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
+   table_name = make_string(szTableName, cbTableName, NULL, 0);
+   escTableName = simpleCatalogEscape(table_name, SQL_NTS, ESCAPE_IN_LITERAL, NULL, conn->ccsc); 
+   /* my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); */
+   if (escTableName)
+       snprintf(columns_query, sizeof(columns_query), "%s and c.relname = '%s'", columns_query, escTableName);
    /* SchemaName cannot contain a string search pattern */
    if (conn->schema_support)
        schema_strcat(columns_query, " and u.nspname = '%.*s'", szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
@@ -2283,21 +2530,20 @@ retry_public_schema:
    result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for SQLSpecialColumns result.");
-       SC_log_error(func, "", stmt);
-       return SQL_ERROR;
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for SQLSpecialColumns result.", func);
+       result = SQL_ERROR;
+       goto cleanup;
    }
    col_stmt = (StatementClass *) hcol_stmt;
 
-   mylog("%s: hcol_stmt = %u, col_stmt = %u\n", func, hcol_stmt, col_stmt);
+   mylog("%s: hcol_stmt = %x, col_stmt = %x\n", func, hcol_stmt, col_stmt);
 
    result = PGAPI_ExecDirect(hcol_stmt, columns_query, SQL_NTS, 0);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_full_error_copy(stmt, col_stmt);
-       SC_log_error(func, "", stmt);
-       PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
-       return SQL_ERROR;
+       SC_full_error_copy(stmt, col_stmt, FALSE);
+       result = SQL_ERROR;
+       goto cleanup;
    }
 
    /* If not found */
@@ -2314,7 +2560,7 @@ retry_public_schema:
         */
        if (szSchemaName &&
            (cbSchemaName == SQL_NTS ||
-            cbSchemaName == (SWORD) strlen(user)) &&
+            cbSchemaName == (SQLSMALLINT) strlen(user)) &&
            strnicmp(szSchemaName, user, strlen(user)) == 0 &&
            stricmp(CC_get_current_schema(conn), pubstr) == 0)
        {
@@ -2330,20 +2576,18 @@ retry_public_schema:
                    relhasrules, sizeof(relhasrules), NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
-       SC_log_error(func, "", stmt);
-       PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
-       return SQL_ERROR;
+       SC_error_copy(stmt, col_stmt, TRUE);
+       result = SQL_ERROR;
+       goto cleanup;
    }
 
    result = PGAPI_BindCol(hcol_stmt, 2, internal_asis_type,
                    relkind, sizeof(relkind), NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
-       SC_log_error(func, "", stmt);
-       PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
-       return SQL_ERROR;
+       SC_error_copy(stmt, col_stmt, TRUE);
+       result = SQL_ERROR;
+       goto cleanup;
    }
    relhasoids[0] = '1';
    if (PG_VERSION_GE(conn, 7.2))
@@ -2352,10 +2596,9 @@ retry_public_schema:
                    relhasoids, sizeof(relhasoids), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, col_stmt);
-           SC_log_error(func, "", stmt);
-           PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
-           return SQL_ERROR;
+           SC_error_copy(stmt, col_stmt, TRUE);
+           result = SQL_ERROR;
+           goto cleanup;
        }
    }
 
@@ -2365,45 +2608,45 @@ retry_public_schema:
    else
        relisaview = (relhasrules[0] == '1');
    PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
+   hcol_stmt = NULL;
 
    res = QR_Constructor();
    SC_set_Result(stmt, res);
    extend_column_bindings(SC_get_ARDF(stmt), 8);
 
+   stmt->catalog_result = TRUE;
    QR_set_num_fields(res, 8);
-   QR_set_field_info(res, 0, "SCOPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 1, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 2, "DATA_TYPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 3, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 4, "PRECISION", PG_TYPE_INT4, 4);
-   QR_set_field_info(res, 5, "LENGTH", PG_TYPE_INT4, 4);
-   QR_set_field_info(res, 6, "SCALE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 0, "SCOPE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 1, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 2, "DATA_TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 3, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 4, "PRECISION", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, 5, "LENGTH", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, 6, "SCALE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2);
 
    if (relisaview)
    {
        /* there's no oid for views */
        if (fColType == SQL_BEST_ROWID)
        {
-           return SQL_NO_DATA_FOUND;
+           result = SQL_NO_DATA_FOUND;
+           goto cleanup;
        }
        else if (fColType == SQL_ROWVER)
        {
            Int2        the_type = PG_TYPE_TID;
 
-           SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (8 - 1) * sizeof(TupleField)),
-               stmt, "Couldn't alloc row", SQL_ERROR)
+           tuple = QR_AddNew(res);
 
-           set_tuplefield_null(&row->tuple[0]);
-           set_tuplefield_string(&row->tuple[1], "ctid");
-           set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
-           set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type));
-           set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
-           set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
-           set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
-           set_tuplefield_int2(&row->tuple[7], SQL_PC_NOT_PSEUDO);
-
-           QR_add_tuple(res, row);
+           set_tuplefield_null(&tuple[0]);
+           set_tuplefield_string(&tuple[1], "ctid");
+           set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
+           set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type));
+           set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
+           set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
+           set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
+           set_tuplefield_int2(&tuple[7], SQL_PC_NOT_PSEUDO);
 inolog("Add ctid\n");
        }
    }
@@ -2413,21 +2656,20 @@ inolog("Add ctid\n");
        if (fColType == SQL_BEST_ROWID)
        {
            if (relhasoids[0] != '1')
-               return SQL_NO_DATA_FOUND;
-           SC_MALLOC_return_with_error(row,  TupleNode, (sizeof(TupleNode) + (8 - 1) *sizeof(TupleField)),
-               stmt, "Couldn't alloc row", SQL_ERROR)
-
-           set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION);
-           set_tuplefield_string(&row->tuple[1], "oid");
-           set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, PG_TYPE_OID, PG_STATIC));
-           set_tuplefield_string(&row->tuple[3], "OID");
-           set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
-           set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
-           set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, PG_TYPE_OID, PG_STATIC));
-           set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
-
-           QR_add_tuple(res, row);
-
+           {
+               result = SQL_NO_DATA_FOUND;
+               goto cleanup;
+           }
+           tuple = QR_AddNew(res);
+
+           set_tuplefield_int2(&tuple[0], SQL_SCOPE_SESSION);
+           set_tuplefield_string(&tuple[1], "oid");
+           set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, PG_TYPE_OID, PG_STATIC));
+           set_tuplefield_string(&tuple[3], "OID");
+           set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
+           set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
+           set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, PG_TYPE_OID, PG_STATIC));
+           set_tuplefield_int2(&tuple[7], SQL_PC_PSEUDO);
        }
        else if (fColType == SQL_ROWVER)
        {
@@ -2435,45 +2677,50 @@ inolog("Add ctid\n");
 
            if (atoi(ci->row_versioning))
            {
-               SC_MALLOC_return_with_error(row, TupleNode,
-               (sizeof(TupleNode) + (8 - 1) * sizeof(TupleField)),
-                   stmt, "Couldn't alloc row", SQL_ERROR)
-
-               set_tuplefield_null(&row->tuple[0]);
-               set_tuplefield_string(&row->tuple[1], "xmin");
-               set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
-               set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type));
-               set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
-               set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
-               set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
-               set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
-
-               QR_add_tuple(res, row);
+               tuple = QR_AddNew(res);
+
+               set_tuplefield_null(&tuple[0]);
+               set_tuplefield_string(&tuple[1], "xmin");
+               set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
+               set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type));
+               set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
+               set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
+               set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
+               set_tuplefield_int2(&tuple[7], SQL_PC_PSEUDO);
            }
        }
    }
 
+cleanup:
+#undef return
+   if (table_name)
+       free(table_name);
+   if (escTableName)
+       free(escTableName);
    stmt->status = STMT_FINISHED;
    stmt->currTuple = -1;
-   stmt->rowset_start = -1;
+   SC_set_rowset_start(stmt, -1, FALSE);
    SC_set_current_col(stmt, -1);
-
-   mylog("%s: EXIT,  stmt=%u\n", func, stmt);
-   return SQL_SUCCESS;
+   if (hcol_stmt)
+       PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
+   if (stmt->internal)
+       result = DiscardStatementSvp(stmt, result, FALSE);
+   mylog("%s: EXIT,  stmt=%x\n", func, stmt);
+   return result;
 }
 
 
 RETCODE        SQL_API
 PGAPI_Statistics(
-                HSTMT hstmt,
-                UCHAR FAR * szTableQualifier,
-                SWORD cbTableQualifier,
-                UCHAR FAR * szTableOwner,
-                SWORD cbTableOwner,
-                UCHAR FAR * szTableName,
-                SWORD cbTableName,
-                UWORD fUnique,
-                UWORD fAccuracy)
+           HSTMT hstmt,
+           const SQLCHAR FAR * szTableQualifier, /* OA */
+           SQLSMALLINT cbTableQualifier,
+           const SQLCHAR FAR * szTableOwner, /* OA */
+           SQLSMALLINT cbTableOwner,
+           const SQLCHAR FAR * szTableName, /* OA(R) */
+           SQLSMALLINT cbTableName,
+           SQLUSMALLINT fUnique,
+           SQLUSMALLINT fAccuracy)
 {
    CSTR func = "PGAPI_Statistics";
    StatementClass *stmt = (StatementClass *) hstmt;
@@ -2482,7 +2729,7 @@ PGAPI_Statistics(
    char        index_query[INFO_INQUIRY_LEN];
    HSTMT       hcol_stmt = NULL, hindx_stmt = NULL;
    RETCODE     ret = SQL_ERROR, result;
-   char        *table_name = NULL;
+   char        *table_name = NULL, *escTableName = NULL;
    char        index_name[MAX_INFO_STRING];
    short       fields_vector[INDEX_KEYS_STORAGE_COUNT];
    char        isunique[10],
@@ -2490,39 +2737,41 @@ PGAPI_Statistics(
                ishash[MAX_INFO_STRING];
    SDWORD      index_name_len,
                fields_vector_len;
-   TupleNode  *row;
+   TupleField  *tuple;
    int         i;
    StatementClass *col_stmt,
               *indx_stmt;
    char        column_name[MAX_INFO_STRING],
-           table_qualifier[MAX_INFO_STRING],
-               relhasrules[10];
+           table_schemaname[MAX_INFO_STRING],
+               relhasrules[10], relkind[8];
    char      **column_names = NULL;
    SQLINTEGER  column_name_len;
    int         total_columns = 0;
    ConnInfo   *ci;
    char        buf[256];
-   SWORD       internal_asis_type = SQL_C_CHAR, cbSchemaName;
+   SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
    const char  *szSchemaName;
 
-   mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
+   mylog("%s: entering...stmt=%x scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
 
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
        return result;
 
-   stmt->manual_result = TRUE;
-   stmt->errormsg_created = TRUE;
-
+   if (!szTableName)
+   {
+       SC_set_error(stmt, STMT_INVALID_NULL_ARG, "The table name is required", func);
+       return result;
+   }
    conn = SC_get_conn(stmt);
    ci = &(conn->connInfo);
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
    if (conn->unicode)
        internal_asis_type = INTERNAL_ASIS_TYPE;
-#endif
+#endif /* UNICODE_SUPPORT */
+
    if (res = QR_Constructor(), !res)
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Statistics result.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Statistics result.", func);
        return SQL_ERROR;
    }
    SC_set_Result(stmt, res);
@@ -2535,21 +2784,22 @@ PGAPI_Statistics(
     */
    extend_column_bindings(SC_get_ARDF(stmt), 13);
 
+   stmt->catalog_result = TRUE;
    /* set the field names */
    QR_set_num_fields(res, 13);
-   QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 3, "NON_UNIQUE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 4, "INDEX_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 5, "INDEX_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 6, "TYPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 7, "SEQ_IN_INDEX", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 8, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 9, "COLLATION", PG_TYPE_CHAR, 1);
-   QR_set_field_info(res, 10, "CARDINALITY", PG_TYPE_INT4, 4);
-   QR_set_field_info(res, 11, "PAGES", PG_TYPE_INT4, 4);
-   QR_set_field_info(res, 12, "FILTER_CONDITION", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 3, "NON_UNIQUE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 4, "INDEX_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 5, "INDEX_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 6, "TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 7, "SEQ_IN_INDEX", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 8, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 9, "COLLATION", PG_TYPE_CHAR, 1);
+   QR_set_field_info_v(res, 10, "CARDINALITY", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, 11, "PAGES", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, 12, "FILTER_CONDITION", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
    /*
     * only use the table name... the owner should be redundant, and we
@@ -2558,15 +2808,17 @@ PGAPI_Statistics(
    table_name = make_string(szTableName, cbTableName, NULL, 0);
    if (!table_name)
    {
-       SC_set_error(stmt, STMT_INTERNAL_ERROR, "No table name passed to PGAPI_Statistics.");
+       SC_set_error(stmt, STMT_INTERNAL_ERROR, "No table name passed to PGAPI_Statistics.", func);
        goto cleanup;
    }
    szSchemaName = szTableOwner;
    cbSchemaName = cbTableOwner;
 
-   table_qualifier[0] = '\0';
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
+   table_schemaname[0] = '\0';
    if (conn->schema_support)
-       schema_strcat(table_qualifier, "%.*s", szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
+       schema_strcat(table_schemaname, "%.*s", szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
 
    /*
     * we need to get a list of the field names first, so we can return
@@ -2575,7 +2827,7 @@ PGAPI_Statistics(
    result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in PGAPI_Statistics for columns.");
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in PGAPI_Statistics for columns.", func);
        goto cleanup;
    }
 
@@ -2589,20 +2841,20 @@ PGAPI_Statistics(
    /* 
     * table_name parameter cannot contain a string search pattern. 
     */
-   result = PGAPI_Columns(hcol_stmt, "", 0, table_qualifier, SQL_NTS,
-                          table_name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN | PODBC_SEARCH_PUBLIC_SCHEMA);
+   result = PGAPI_Columns(hcol_stmt, "", 0, table_schemaname, SQL_NTS,
+                          table_name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN | PODBC_SEARCH_PUBLIC_SCHEMA, 0, 0);
    col_stmt->internal = FALSE;
 
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
+       SC_error_copy(stmt, col_stmt, TRUE);
        goto cleanup;
    }
    result = PGAPI_BindCol(hcol_stmt, 4, internal_asis_type,
                         column_name, sizeof(column_name), &column_name_len);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, col_stmt);
+       SC_error_copy(stmt, col_stmt, TRUE);
        goto cleanup;
 
    }
@@ -2611,15 +2863,14 @@ PGAPI_Statistics(
    while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO))
    {
        if (0 == total_columns)
-           PGAPI_GetData(hcol_stmt, 2, internal_asis_type, table_qualifier, sizeof(table_qualifier), NULL);
+           PGAPI_GetData(hcol_stmt, 2, internal_asis_type, table_schemaname, sizeof(table_schemaname), NULL);
        total_columns++;
 
        column_names =
            (char **) realloc(column_names,
                              total_columns * sizeof(char *));
-       SC_MALLOC_return_with_error(column_names[total_columns - 1],
-           char, (strlen(column_name) + 1), stmt, 
-           "Couldn't alloc column_name", SQL_ERROR)
+       column_names[total_columns - 1] =
+           (char *) malloc(strlen(column_name) + 1);
        strcpy(column_names[total_columns - 1], column_name);
 
        mylog("%s: column_name = '%s'\n", func, column_name);
@@ -2629,7 +2880,7 @@ PGAPI_Statistics(
 
    if (result != SQL_NO_DATA_FOUND)
    {
-       SC_full_error_copy(stmt, col_stmt);
+       SC_full_error_copy(stmt, col_stmt, FALSE);
        goto cleanup;
    }
    PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
@@ -2645,14 +2896,16 @@ PGAPI_Statistics(
    result = PGAPI_AllocStmt(stmt->hdbc, &hindx_stmt);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in SQLStatistics for indices.");
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in SQLStatistics for indices.", func);
        goto cleanup;
 
    }
    indx_stmt = (StatementClass *) hindx_stmt;
 
+   /* TableName cannot contain a string search pattern */
+   escTableName = simpleCatalogEscape(table_name, SQL_NTS, ESCAPE_IN_LITERAL, NULL, conn->ccsc); 
    if (conn->schema_support)
-       sprintf(index_query, "select c.relname, i.indkey, i.indisunique"
+       snprintf(index_query, sizeof(index_query), "select c.relname, i.indkey, i.indisunique"
            ", i.indisclustered, a.amname, c.relhasrules, n.nspname"
            " from pg_catalog.pg_index i, pg_catalog.pg_class c,"
            " pg_catalog.pg_class d, pg_catalog.pg_am a,"
@@ -2663,16 +2916,16 @@ PGAPI_Statistics(
            " and d.oid = i.indrelid"
            " and i.indexrelid = c.oid"
            " and c.relam = a.oid order by"
-           ,table_name, table_qualifier);
+           ,escTableName, table_schemaname);
    else
-       sprintf(index_query, "select c.relname, i.indkey, i.indisunique"
+       snprintf(index_query, sizeof(index_query), "select c.relname, i.indkey, i.indisunique"
            ", i.indisclustered, a.amname, c.relhasrules"
            " from pg_index i, pg_class c, pg_class d, pg_am a"
            " where d.relname = '%s'"
            " and d.oid = i.indrelid"
            " and i.indexrelid = c.oid"
            " and c.relam = a.oid order by"
-           ,table_name);
+           ,escTableName);
    if (PG_VERSION_GT(SC_get_conn(stmt), 6.4))
        strcat(index_query, " i.indisprimary desc,");
    if (conn->schema_support)
@@ -2687,7 +2940,7 @@ PGAPI_Statistics(
         * "Couldn't execute index query (w/SQLExecDirect) in
         * SQLStatistics.";
         */
-       SC_full_error_copy(stmt, indx_stmt);
+       SC_full_error_copy(stmt, indx_stmt, FALSE);
        goto cleanup;
    }
 
@@ -2696,7 +2949,7 @@ PGAPI_Statistics(
                           index_name, MAX_INFO_STRING, &index_name_len);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column 
+       SC_error_copy(stmt, indx_stmt, TRUE);   /* "Couldn't bind column 
                        * in SQLStatistics."; */
        goto cleanup;
 
@@ -2706,7 +2959,7 @@ PGAPI_Statistics(
            fields_vector, INDEX_KEYS_STORAGE_COUNT * 2, &fields_vector_len);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column 
+       SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column 
                         * in SQLStatistics."; */
        goto cleanup;
 
@@ -2716,7 +2969,7 @@ PGAPI_Statistics(
                           isunique, sizeof(isunique), NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column 
+       SC_error_copy(stmt, indx_stmt, TRUE);   /* "Couldn't bind column 
                         * in SQLStatistics."; */
        goto cleanup;
    }
@@ -2726,7 +2979,7 @@ PGAPI_Statistics(
                           isclustered, sizeof(isclustered), NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column *
+       SC_error_copy(stmt, indx_stmt, TRUE);   /* "Couldn't bind column *
                         * in SQLStatistics."; */
        goto cleanup;
 
@@ -2737,7 +2990,7 @@ PGAPI_Statistics(
                           ishash, sizeof(ishash), NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column * 
+       SC_error_copy(stmt, indx_stmt, TRUE);   /* "Couldn't bind column * 
                         * in SQLStatistics."; */
        goto cleanup;
 
@@ -2747,7 +3000,7 @@ PGAPI_Statistics(
                    relhasrules, sizeof(relhasrules), NULL);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, indx_stmt);
+       SC_error_copy(stmt, indx_stmt, TRUE);
        goto cleanup;
    }
 
@@ -2756,37 +3009,34 @@ PGAPI_Statistics(
    /* fake index of OID */
    if (relhasrules[0] != '1' && atoi(ci->show_oid_column) && atoi(ci->fake_oid_index))
    {
-       row = (TupleNode *) malloc(sizeof(TupleNode) +
-                                  (13 - 1) *sizeof(TupleField));
+       tuple = QR_AddNew(res);
 
        /* no table qualifier */
-       set_tuplefield_string(&row->tuple[0], "");
+       set_tuplefield_string(&tuple[0], "");
        /* don't set the table owner, else Access tries to use it */
-       set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_qualifier));
-       set_tuplefield_string(&row->tuple[2], table_name);
+       set_tuplefield_string(&tuple[1], GET_SCHEMA_NAME(table_schemaname));
+       set_tuplefield_string(&tuple[2], table_name);
 
        /* non-unique index? */
-       set_tuplefield_int2(&row->tuple[3], (Int2) (ci->drivers.unique_index ? FALSE : TRUE));
+       set_tuplefield_int2(&tuple[3], (Int2) (ci->drivers.unique_index ? FALSE : TRUE));
 
        /* no index qualifier */
-       set_tuplefield_string(&row->tuple[4], "");
+       set_tuplefield_string(&tuple[4], "");
 
        sprintf(buf, "%s_idx_fake_oid", table_name);
-       set_tuplefield_string(&row->tuple[5], buf);
+       set_tuplefield_string(&tuple[5], buf);
 
        /*
         * Clustered/HASH index?
         */
-       set_tuplefield_int2(&row->tuple[6], (Int2) SQL_INDEX_OTHER);
-       set_tuplefield_int2(&row->tuple[7], (Int2) 1);
-
-       set_tuplefield_string(&row->tuple[8], "oid");
-       set_tuplefield_string(&row->tuple[9], "A");
-       set_tuplefield_null(&row->tuple[10]);
-       set_tuplefield_null(&row->tuple[11]);
-       set_tuplefield_null(&row->tuple[12]);
-
-       QR_add_tuple(res, row);
+       set_tuplefield_int2(&tuple[6], (Int2) SQL_INDEX_OTHER);
+       set_tuplefield_int2(&tuple[7], (Int2) 1);
+
+       set_tuplefield_string(&tuple[8], "oid");
+       set_tuplefield_string(&tuple[9], "A");
+       set_tuplefield_null(&tuple[10]);
+       set_tuplefield_null(&tuple[11]);
+       set_tuplefield_null(&tuple[12]);
    }
 
    while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO))
@@ -2799,55 +3049,52 @@ PGAPI_Statistics(
            /* add a row in this table for each field in the index */
            while (i < INDEX_KEYS_STORAGE_COUNT && fields_vector[i] != 0)
            {
-               row = (TupleNode *) malloc(sizeof(TupleNode) +
-                                          (13 - 1) *sizeof(TupleField));
+               tuple = QR_AddNew(res);
 
                /* no table qualifier */
-               set_tuplefield_string(&row->tuple[0], "");
+               set_tuplefield_string(&tuple[0], "");
                /* don't set the table owner, else Access tries to use it */
-               set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_qualifier));
-               set_tuplefield_string(&row->tuple[2], table_name);
+               set_tuplefield_string(&tuple[1], GET_SCHEMA_NAME(table_schemaname));
+               set_tuplefield_string(&tuple[2], table_name);
 
                /* non-unique index? */
                if (ci->drivers.unique_index)
-                   set_tuplefield_int2(&row->tuple[3], (Int2) (atoi(isunique) ? FALSE : TRUE));
+                   set_tuplefield_int2(&tuple[3], (Int2) (atoi(isunique) ? FALSE : TRUE));
                else
-                   set_tuplefield_int2(&row->tuple[3], TRUE);
+                   set_tuplefield_int2(&tuple[3], TRUE);
 
                /* no index qualifier */
-               set_tuplefield_string(&row->tuple[4], "");
-               set_tuplefield_string(&row->tuple[5], index_name);
+               set_tuplefield_string(&tuple[4], "");
+               set_tuplefield_string(&tuple[5], index_name);
 
                /*
                 * Clustered/HASH index?
                 */
-               set_tuplefield_int2(&row->tuple[6], (Int2)
+               set_tuplefield_int2(&tuple[6], (Int2)
                               (atoi(isclustered) ? SQL_INDEX_CLUSTERED :
                                (!strncmp(ishash, "hash", 4)) ? SQL_INDEX_HASHED : SQL_INDEX_OTHER));
-               set_tuplefield_int2(&row->tuple[7], (Int2) (i + 1));
+               set_tuplefield_int2(&tuple[7], (Int2) (i + 1));
 
                if (fields_vector[i] == OID_ATTNUM)
                {
-                   set_tuplefield_string(&row->tuple[8], "oid");
+                   set_tuplefield_string(&tuple[8], "oid");
                    mylog("%s: column name = oid\n", func);
                }
                else if (fields_vector[i] < 0 || fields_vector[i] > total_columns)
                {
-                   set_tuplefield_string(&row->tuple[8], "UNKNOWN");
+                   set_tuplefield_string(&tuple[8], "UNKNOWN");
                    mylog("%s: column name = UNKNOWN\n", func);
                }
                else
                {
-                   set_tuplefield_string(&row->tuple[8], column_names[fields_vector[i] - 1]);
+                   set_tuplefield_string(&tuple[8], column_names[fields_vector[i] - 1]);
                    mylog("%s: column name = '%s'\n", func, column_names[fields_vector[i] - 1]);
                }
 
-               set_tuplefield_string(&row->tuple[9], "A");
-               set_tuplefield_null(&row->tuple[10]);
-               set_tuplefield_null(&row->tuple[11]);
-               set_tuplefield_null(&row->tuple[12]);
-
-               QR_add_tuple(res, row);
+               set_tuplefield_string(&tuple[9], "A");
+               set_tuplefield_null(&tuple[10]);
+               set_tuplefield_null(&tuple[11]);
+               set_tuplefield_null(&tuple[12]);
                i++;
            }
        }
@@ -2857,20 +3104,19 @@ PGAPI_Statistics(
    if (result != SQL_NO_DATA_FOUND)
    {
        /* "SQLFetch failed in SQLStatistics."; */
-       SC_full_error_copy(stmt, indx_stmt);
+       SC_full_error_copy(stmt, indx_stmt, FALSE);
        goto cleanup;
    }
    ret = SQL_SUCCESS;
 
 cleanup:
+#undef return
    /*
     * also, things need to think that this statement is finished so the
     * results can be retrieved.
     */
    stmt->status = STMT_FINISHED;
 
-   if (SQL_ERROR == ret)
-       SC_log_error(func, "", stmt);
    if (hcol_stmt)
        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
    if (hindx_stmt)
@@ -2878,6 +3124,8 @@ cleanup:
    /* These things should be freed on any error ALSO! */
    if (table_name)
        free(table_name);
+   if (escTableName)
+       free(escTableName);
    if (column_names)
    {
        for (i = 0; i < total_columns; i++)
@@ -2887,10 +3135,12 @@ cleanup:
 
    /* set up the current tuple pointer for SQLFetch */
    stmt->currTuple = -1;
-   stmt->rowset_start = -1;
+   SC_set_rowset_start(stmt, -1, FALSE);
    SC_set_current_col(stmt, -1);
 
-   mylog("%s: EXIT, stmt=%u, ret=%d\n", func, stmt, ret);
+   if (stmt->internal)
+       ret = DiscardStatementSvp(stmt, ret, FALSE);
+   mylog("%s: EXIT, stmt=%x, ret=%d\n", func, stmt, ret);
 
    return ret;
 }
@@ -2898,19 +3148,26 @@ cleanup:
 
 RETCODE        SQL_API
 PGAPI_ColumnPrivileges(
-                      HSTMT hstmt,
-                      UCHAR FAR * szTableQualifier,
-                      SWORD cbTableQualifier,
-                      UCHAR FAR * szTableOwner,
-                      SWORD cbTableOwner,
-                      UCHAR FAR * szTableName,
-                      SWORD cbTableName,
-                      UCHAR FAR * szColumnName,
-                      SWORD cbColumnName)
+           HSTMT hstmt,
+           const SQLCHAR FAR * szTableQualifier, /* OA */
+           SQLSMALLINT cbTableQualifier,
+           const SQLCHAR FAR * szTableOwner, /* OA */
+           SQLSMALLINT cbTableOwner,
+           const SQLCHAR FAR * szTableName, /* OA(R) */
+           SQLSMALLINT cbTableName,
+           const SQLCHAR FAR * szColumnName, /* PV */
+           SQLSMALLINT cbColumnName,
+           UWORD flag)
 {
    CSTR func = "PGAPI_ColumnPrivileges";
    StatementClass  *stmt = (StatementClass *) hstmt;
-   RETCODE result;
+   ConnectionClass *conn = SC_get_conn(stmt);
+   RETCODE result = SQL_ERROR;
+   char    *escSchemaName = NULL, *escTableName = NULL, *escColumnName = NULL;
+   const char  *like_or_eq;
+   char    column_query[INFO_INQUIRY_LEN];
+   BOOL    search_pattern;
+   QResultClass    *res;
 
    mylog("%s: entering...\n", func);
 
@@ -2918,9 +3175,61 @@ PGAPI_ColumnPrivileges(
 
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
        return result;
-   SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "not implemented");
-   SC_log_error(func, "Function not implemented", stmt);
-   return SQL_ERROR;
+   if (PG_VERSION_LT(conn, 7.4))
+       SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Function not implementedyet", func);
+   escSchemaName = simpleCatalogEscape(szTableOwner, cbTableOwner, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+   escTableName = simpleCatalogEscape(szTableName, cbTableName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+   search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
+   if (search_pattern) 
+   {
+       like_or_eq = likeop;
+       escColumnName = adjustLikePattern(szColumnName, cbColumnName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
+   }
+   else
+   {
+       like_or_eq = eqop;
+       escColumnName = simpleCatalogEscape(szColumnName, cbColumnName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+   }
+   strcpy(column_query, "select '' as TABLE_CAT, table_schema as TABLE_SCHEM,"
+           " table_name, column_name, grantor, grantee,"
+           " privilege_type as PRIVILEGE, is_grantable from"
+           " information_schema.column_privileges where true");
+   if (escSchemaName)
+       snprintf(column_query, sizeof(column_query),
+           "%s and table_schem = '%s'", column_query, escSchemaName);  
+   if (escTableName)
+       snprintf(column_query, sizeof(column_query),
+           "%s and table_name = '%s'", column_query, escTableName);  
+   if (escColumnName)
+       snprintf(column_query, sizeof(column_query),
+           "%s and column_name %s '%s'", column_query, like_or_eq, escColumnName);
+   if (res = CC_send_query(conn, column_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(res))
+   {
+       SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_ColumnPrivileges query error", func);
+       QR_Destructor(res);
+       return SQL_ERROR;
+   }
+   SC_set_Result(stmt, res);
+
+   /*
+    * also, things need to think that this statement is finished so the
+    * results can be retrieved.
+    */
+   extend_column_bindings(SC_get_ARDF(stmt), 8);
+   /* set up the current tuple pointer for SQLFetch */
+   result = SQL_SUCCESS;
+cleanup:
+   /* set up the current tuple pointer for SQLFetch */
+   stmt->status = STMT_FINISHED;
+   stmt->currTuple = -1;
+   SC_set_rowset_start(stmt, -1, FALSE);
+   if (escSchemaName)
+       free(escSchemaName);
+   if (escTableName)
+       free(escTableName);
+   if (escColumnName)
+       free(escColumnName);
+   return result;
 }
 
 
@@ -2931,92 +3240,92 @@ PGAPI_ColumnPrivileges(
  */
 RETCODE        SQL_API
 PGAPI_PrimaryKeys(
-                 HSTMT hstmt,
-                 UCHAR FAR * szTableQualifier,
-                 SWORD cbTableQualifier,
-                 UCHAR FAR * szTableOwner,
-                 SWORD cbTableOwner,
-                 UCHAR FAR * szTableName,
-                 SWORD cbTableName)
+           HSTMT hstmt,
+           const SQLCHAR FAR * szTableQualifier, /* OA */
+           SQLSMALLINT cbTableQualifier,
+           const SQLCHAR FAR * szTableOwner, /* OA */
+           SQLSMALLINT cbTableOwner,
+           const SQLCHAR FAR * szTableName, /* OA(R) */
+           SQLSMALLINT cbTableName)
 {
    CSTR func = "PGAPI_PrimaryKeys";
    StatementClass *stmt = (StatementClass *) hstmt;
    QResultClass    *res;
    ConnectionClass *conn;
-   TupleNode  *row;
-   RETCODE     ret = SQL_ERROR, result;
+   TupleField  *tuple;
+   RETCODE     ret = SQL_SUCCESS, result;
    int         seq = 0;
    HSTMT       htbl_stmt = NULL;
    StatementClass *tbl_stmt;
    char        tables_query[INFO_INQUIRY_LEN];
    char        attname[MAX_INFO_STRING];
    SDWORD      attname_len;
-   char       *pktab;
-   char        pkscm[TABLE_NAME_STORAGE_LEN + 1];
+   char        *pktab = NULL, pkscm[TABLE_NAME_STORAGE_LEN + 1];
    Int2        result_cols;
    int         qno,
                qstart,
                qend;
-   SWORD       internal_asis_type = SQL_C_CHAR, cbSchemaName;
+   SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
    const char  *szSchemaName;
 
-   mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
+   mylog("%s: entering...stmt=%x scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
 
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
        return result;
-   stmt->manual_result = TRUE;
-   stmt->errormsg_created = TRUE;
 
    if (res = QR_Constructor(), !res)
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_PrimaryKeys result.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_PrimaryKeys result.", func);
        return SQL_ERROR;
    }
    SC_set_Result(stmt, res);
 
-   /* the binding structure for a statement is not set up until */
-
-   /*
+   /* the binding structure for a statement is not set up until 
+    *
     * a statement is actually executed, so we'll have to do this
     * ourselves.
     */
    result_cols = 6;
    extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
+   stmt->catalog_result = TRUE;
    /* set the field names */
    QR_set_num_fields(res, result_cols);
-   QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 4, "KEY_SEQ", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 5, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 3, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 4, "KEY_SEQ", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 5, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
 
    result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for Primary Key result.");
-       SC_log_error(func, "", stmt);
-       return SQL_ERROR;
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for Primary Key result.", func);
+       ret = SQL_ERROR;
+       goto cleanup;
    }
    tbl_stmt = (StatementClass *) htbl_stmt;
 
    conn = SC_get_conn(stmt);
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
    if (conn->unicode)
        internal_asis_type = INTERNAL_ASIS_TYPE;
-#endif
+#endif /* UNICODE_SUPPORT */
+
    pktab = make_string(szTableName, cbTableName, NULL, 0);
-   if (pktab == NULL || pktab[0] == '\0')
+   if (!pktab || pktab[0] == '\0')
    {
-       SC_set_error(stmt, STMT_INTERNAL_ERROR, "No Table specified to PGAPI_PrimaryKeys.");
+       SC_set_error(stmt, STMT_INTERNAL_ERROR, "No Table specified to PGAPI_PrimaryKeys.", func);
+       ret = SQL_ERROR;
        goto cleanup;
    }
    szSchemaName = szTableOwner;
    cbSchemaName = cbTableOwner;
 
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
 retry_public_schema:
    pkscm[0] = '\0';
    if (conn->schema_support)
@@ -3026,7 +3335,8 @@ retry_public_schema:
                           attname, MAX_INFO_STRING, &attname_len);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_error_copy(stmt, tbl_stmt);
+       SC_error_copy(stmt, tbl_stmt, TRUE);
+       ret = SQL_ERROR;
        goto cleanup;
    }
 
@@ -3047,7 +3357,7 @@ retry_public_schema:
                 * 2000-03-21
                 */
                if (conn->schema_support)
-                   sprintf(tables_query, "select ta.attname, ia.attnum"
+                   snprintf(tables_query, sizeof(tables_query), "select ta.attname, ia.attnum"
                        " from pg_catalog.pg_attribute ta,"
                        " pg_catalog.pg_attribute ia, pg_catalog.pg_class c,"
                        " pg_catalog.pg_index i, pg_catalog.pg_namespace n"
@@ -3063,7 +3373,7 @@ retry_public_schema:
                        " AND (NOT ia.attisdropped)"
                        " order by ia.attnum", pktab, pkscm);
                else
-                   sprintf(tables_query, "select ta.attname, ia.attnum"
+                   snprintf(tables_query, sizeof(tables_query), "select ta.attname, ia.attnum"
                        " from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i"
                        " where c.relname = '%s'"
                        " AND c.oid = i.indrelid"
@@ -3079,7 +3389,7 @@ retry_public_schema:
                 * Simplified query to search old fashoned primary key
                 */
                if (conn->schema_support)
-                   sprintf(tables_query, "select ta.attname, ia.attnum"
+                   snprintf(tables_query, sizeof(tables_query), "select ta.attname, ia.attnum"
                        " from pg_catalog.pg_attribute ta,"
                        " pg_catalog.pg_attribute ia, pg_catalog.pg_class c,"
                        " pg_catalog.pg_index i, pg_catalog.pg_namespace n"
@@ -3094,7 +3404,7 @@ retry_public_schema:
                        " AND (NOT ia.attisdropped)"
                        " order by ia.attnum", pktab, pkscm);
                else
-                   sprintf(tables_query, "select ta.attname, ia.attnum"
+                   snprintf(tables_query, sizeof(tables_query), "select ta.attname, ia.attnum"
                        " from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i"
                        " where c.relname = '%s_pkey'"
                        " AND c.oid = i.indexrelid"
@@ -3109,7 +3419,8 @@ retry_public_schema:
        result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_full_error_copy(stmt, tbl_stmt);
+           SC_full_error_copy(stmt, tbl_stmt, FALSE);
+           ret = SQL_ERROR;
            goto cleanup;
        }
 
@@ -3131,7 +3442,7 @@ retry_public_schema:
         */
        if (szSchemaName &&
            (cbSchemaName == SQL_NTS ||
-            cbSchemaName == (SWORD) strlen(user)) &&
+            cbSchemaName == (SQLSMALLINT) strlen(user)) &&
            strnicmp(szSchemaName, user, strlen(user)) == 0 &&
            stricmp(CC_get_current_schema(conn), pubstr) == 0)
        {
@@ -3143,9 +3454,9 @@ retry_public_schema:
 
    while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO))
    {
-       row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
+       tuple = QR_AddNew(res);
 
-       set_tuplefield_null(&row->tuple[0]);
+       set_tuplefield_null(&tuple[0]);
 
        /*
         * I have to hide the table owner from Access, otherwise it
@@ -3153,13 +3464,11 @@ retry_public_schema:
         * valid according to the ODBC SQL grammar, but Postgres won't
         * support it.)
         */
-       set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(pkscm));
-       set_tuplefield_string(&row->tuple[2], pktab);
-       set_tuplefield_string(&row->tuple[3], attname);
-       set_tuplefield_int2(&row->tuple[4], (Int2) (++seq));
-       set_tuplefield_null(&row->tuple[5]);
-
-       QR_add_tuple(res, row);
+       set_tuplefield_string(&tuple[1], GET_SCHEMA_NAME(pkscm));
+       set_tuplefield_string(&tuple[2], pktab);
+       set_tuplefield_string(&tuple[3], attname);
+       set_tuplefield_int2(&tuple[4], (Int2) (++seq));
+       set_tuplefield_null(&tuple[5]);
 
        mylog(">> primaryKeys: pktab = '%s', attname = '%s', seq = %d\n", pktab, attname, seq);
 
@@ -3168,32 +3477,33 @@ retry_public_schema:
 
    if (result != SQL_NO_DATA_FOUND)
    {
-       SC_full_error_copy(stmt, htbl_stmt);
+       SC_full_error_copy(stmt, htbl_stmt, FALSE);
+       ret = SQL_ERROR;
        goto cleanup;
    }
    ret = SQL_SUCCESS;
 
 cleanup:
-   if (pktab)
-       free(pktab);
-
+#undef return
    /*
     * also, things need to think that this statement is finished so the
     * results can be retrieved.
     */
    stmt->status = STMT_FINISHED;
 
-   if (SQL_ERROR == ret)
-       SC_log_error(func, "", stmt);
    if (htbl_stmt)
        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
+   if (pktab)
+       free(pktab);
    /* set up the current tuple pointer for SQLFetch */
    stmt->currTuple = -1;
-   stmt->rowset_start = -1;
+   SC_set_rowset_start(stmt, -1, FALSE);
    SC_set_current_col(stmt, -1);
 
-   mylog("%s: EXIT, stmt=%u, ret=%d\n", func, stmt, ret);
+   if (stmt->internal)
+       ret = DiscardStatementSvp(stmt, ret, FALSE); 
+   mylog("%s: EXIT, stmt=%x, ret=%d\n", func, stmt, ret);
    return ret;
 }
 
@@ -3225,62 +3535,59 @@ getClientTableName(ConnectionClass *conn, const char *serverSchemaName, char *se
    QResultClass *res;
 
    *nameAlloced = FALSE;
-   if (!conn->client_encoding || !isMultibyte(serverTableName))
+   if (!conn->origianl_client_encoding || !isMultibyte(serverTableName))
        return ret;
    if (!conn->server_encoding)
    {
-       if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res)
+       if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL), QR_command_maybe_successsful(res))
        {
            if (QR_get_num_tuples(res) > 0)
                conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
-           QR_Destructor(res);
        }
+       QR_Destructor(res);
    }
    if (!conn->server_encoding)
        return ret;
-   sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
-   bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
+   snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
+   bError = (!QR_command_maybe_successful(res = CC_send_query(conn, query, NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL));
+   QR_Destrctor(res);
    if (!bError && continueExec)
    {
        if (conn->schema_support)
-           sprintf(query, "select OID from pg_catalog.pg_class,"
+           snprintf(query, sizeof(query), "select OID from pg_catalog.pg_class,"
            " pg_catalog.pg_namespace"
            " where relname = '%s' and pg_namespace.oid = relnamespace and"
            " pg_namespace.nspname = '%s'", serverTableName, serverSchemaName);
        else
-           sprintf(query, "select OID from pg_class where relname = '%s'", serverTableName);
-       if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
+           snprintf(query, sizeof(query), "select OID from pg_class where relname = '%s'", serverTableName);
+       if (res = CC_send_query(conn, query, NULL, ROLLBACK_ON_ERROR | GNORE_ABORT_ON_CONN), QR_command_maybe_successful(res))
        {
            if (QR_get_num_tuples(res) > 0)
                strcpy(saveoid, QR_get_value_backend_row(res, 0, 0));
            else
                continueExec = FALSE;
-           QR_Destructor(res);
        }
        else
            bError = TRUE;
+       QR_Destructor(res);
    }
    continueExec = (continueExec && !bError);
-   if (bError && CC_is_in_trans(conn))
-   {
-       CC_abort(conn);
-       bError = FALSE;
-   }
    /* restore the client encoding */
-   sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
-   bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
+   snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->original_client_encoding);
+   bError = (QR_command_maybe_successful(res = CC_send_query(conn, query, NULL, IGNORE_ABORT_ON_CONN, NULL));
+   QR_Destrcutor(res);
    if (bError || !continueExec)
        return ret;
-   sprintf(query, "select relname from pg_class where OID = %s", saveoid);
-   if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
+   snprintf(query, sizeof(query), "select relname from pg_class where OID = %s", saveoid);
+   if (res = CC_send_query(conn, query, NULL, IGNORE_ABORT_ON_CONN, NULL), QR_command_maybe_successful(res))
    {
        if (QR_get_num_tuples(res) > 0)
        {
            ret = strdup(QR_get_value_backend_row(res, 0, 0));
            *nameAlloced = TRUE;
        }
-       QR_Destructor(res);
    }
+   QR_Destructor(res);
    return ret;
 }
 static char *
@@ -3295,35 +3602,36 @@ getClientColumnName(ConnectionClass *conn, const char * serverSchemaName, const
    QResultClass *res;
 
    *nameAlloced = FALSE;
-   if (!conn->client_encoding || !isMultibyte(serverColumnName))
+   if (!conn->original_client_encoding || !isMultibyte(serverColumnName))
        return ret;
    if (!conn->server_encoding)
    {
-       if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res)
+       if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, IGNORE_ABORT_ON_CONN, NULL), QR_command_maybe_successful(res))
        {
            if (QR_get_num_tuples(res) > 0)
                conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
-           QR_Destructor(res);
        }
+       QR_Destructor(res);
    }
    if (!conn->server_encoding)
        return ret;
-   sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
-   bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
+   snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
+   bError = (!QR_command_maybe_successful(res = CC_send_query(conn, query, NULL, IGNORE_ABORT_ON_CONN, NULL));
+   QR_Destructor(res);
    if (!bError && continueExec)
    {
        if (conn->schema_support)
-           sprintf(query, "select attrelid, attnum from pg_catalog.pg_class,"
+           snprintf(query, sizeof(query), "select attrelid, attnum from pg_catalog.pg_class,"
            " pg_catalog.pg_attribute, pg_catalog.pg_namespace "
                "where relname = '%s' and attrelid = pg_class.oid "
                "and (not attisdropped) "
                "and attname = '%s' and pg_namespace.oid = relnamespace and"
                " pg_namespace.nspname = '%s'", serverTableName, serverColumnName, serverSchemaName);
        else
-           sprintf(query, "select attrelid, attnum from pg_class, pg_attribute "
+           snprintf(query, sizeof(query), "select attrelid, attnum from pg_class, pg_attribute "
                "where relname = '%s' and attrelid = pg_class.oid "
                "and attname = '%s'", serverTableName, serverColumnName);
-       if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
+       if (res = CC_send_query(conn, query, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL), QR_command_maybe_successful(res))
        {
            if (QR_get_num_tuples(res) > 0)
            {
@@ -3332,32 +3640,28 @@ getClientColumnName(ConnectionClass *conn, const char * serverSchemaName, const
            }
            else
                continueExec = FALSE;
-           QR_Destructor(res);
        }
        else
            bError = TRUE;
+       QR_Destructor(res);
    }
    continueExec = (continueExec && !bError);
-   if (bError && CC_is_in_trans(conn))
-   {
-       CC_abort(conn);
-       bError = FALSE;
-   }
    /* restore the cleint encoding */
-   sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
-   bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
+   snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->original_client_encoding);
+   bError = (!QR_command_maybe_successful(res = CC_send_query(conn, query, NULL, IGNORE_ABORT_ON_CONN, NULL));
+   QR_Destructor(res);
    if (bError || !continueExec)
        return ret;
-   sprintf(query, "select attname from pg_attribute where attrelid = %s and attnum = %s", saveattrelid, saveattnum);
-   if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
+   snprintf(query, sizeof(query), "select attname from pg_attribute where attrelid = %s and attnum = %s", saveattrelid, saveattnum);
+   if (res = CC_send_query(conn, query, NULL, IGNORE_ABORT_ON_CONN, NULL), QR_command_maybe_successful(res))
    {
        if (QR_get_num_tuples(res) > 0)
        {
            ret = strdup(QR_get_value_backend_row(res, 0, 0));
            *nameAlloced = TRUE;
        }
-       QR_Destructor(res);
    }
+   QR_Destructor(res);
    return ret;
 }
 #endif /* NOT_USED */
@@ -3369,85 +3673,83 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName,
    BOOL        continueExec = TRUE,
                bError = FALSE;
    QResultClass *res;
+   UWORD   flag = IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR;
 
    *nameAlloced = FALSE;
-   if (!conn->client_encoding || !isMultibyte(serverColumnName))
+   if (!conn->original_client_encoding || !isMultibyte(serverColumnName))
        return ret;
    if (!conn->server_encoding)
    {
-       if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res)
+       if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, flag, NULL), QR_command_maybe_successful(res))
        {
-           if (QR_get_num_backend_tuples(res) > 0)
+           if (QR_get_num_cached_tuples(res) > 0)
                conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
-           QR_Destructor(res);
        }
    }
+   QR_Destructor(res);
    if (!conn->server_encoding)
        return ret;
-   sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
-   bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
+   snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
+   bError = (!QR_command_maybe_successful((res = CC_send_query(conn, query, NULL, flag, NULL))));
+   QR_Destructor(res);
    if (!bError && continueExec)
    {
-       sprintf(query, "select attnum from pg_attribute "
+       snprintf(query, sizeof(query), "select attnum from pg_attribute "
            "where attrelid = %u and attname = '%s'",
            relid, serverColumnName);
-       if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
+       if (res = CC_send_query(conn, query, NULL, flag, NULL), QR_command_maybe_successful(res))
        {
-           if (QR_get_num_backend_tuples(res) > 0)
+           if (QR_get_num_cached_tuples(res) > 0)
            {
                strcpy(saveattnum, QR_get_value_backend_row(res, 0, 0));
            }
            else
                continueExec = FALSE;
-           QR_Destructor(res);
        }
        else
            bError = TRUE;
+       QR_Destructor(res);
    }
    continueExec = (continueExec && !bError);
-   if (bError && CC_is_in_trans(conn))
-   {
-       CC_abort(conn);
-       bError = FALSE;
-   }
    /* restore the cleint encoding */
-   sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
-   bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
+   snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->original_client_encoding);
+   bError = (!QR_command_maybe_successful((res = CC_send_query(conn, query, NULL, flag, NULL))));
+   QR_Destructor(res);
    if (bError || !continueExec)
        return ret;
-   sprintf(query, "select attname from pg_attribute where attrelid = %u and attnum = %s", relid, saveattnum);
-   if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
+   snprintf(query, sizeof(query), "select attname from pg_attribute where attrelid = %u and attnum = %s", relid, saveattnum);
+   if (res = CC_send_query(conn, query, NULL, flag, NULL), QR_command_maybe_successful(res))
    {
-       if (QR_get_num_backend_tuples(res) > 0)
+       if (QR_get_num_cached_tuples(res) > 0)
        {
            ret = strdup(QR_get_value_backend_row(res, 0, 0));
            *nameAlloced = TRUE;
        }
-       QR_Destructor(res);
    }
+   QR_Destructor(res);
    return ret;
 }
 
 RETCODE        SQL_API
 PGAPI_ForeignKeys(
-                 HSTMT hstmt,
-                 UCHAR FAR * szPkTableQualifier,
-                 SWORD cbPkTableQualifier,
-                 UCHAR FAR * szPkTableOwner,
-                 SWORD cbPkTableOwner,
-                 UCHAR FAR * szPkTableName,
-                 SWORD cbPkTableName,
-                 UCHAR FAR * szFkTableQualifier,
-                 SWORD cbFkTableQualifier,
-                 UCHAR FAR * szFkTableOwner,
-                 SWORD cbFkTableOwner,
-                 UCHAR FAR * szFkTableName,
-                 SWORD cbFkTableName)
+           HSTMT hstmt,
+           const SQLCHAR FAR * szPkTableQualifier, /* OA */
+           SQLSMALLINT cbPkTableQualifier,
+           const SQLCHAR FAR * szPkTableOwner, /* OA */
+           SQLSMALLINT cbPkTableOwner,
+           const SQLCHAR FAR * szPkTableName, /* OA(R) */
+           SQLSMALLINT cbPkTableName,
+           const SQLCHAR FAR * szFkTableQualifier, /* OA */
+           SQLSMALLINT cbFkTableQualifier,
+           const SQLCHAR FAR * szFkTableOwner, /* OA */
+           SQLSMALLINT cbFkTableOwner,
+           const SQLCHAR FAR * szFkTableName, /* OA(R) */
+           SQLSMALLINT cbFkTableName)
 {
    CSTR func = "PGAPI_ForeignKeys";
    StatementClass *stmt = (StatementClass *) hstmt;
    QResultClass    *res;
-   TupleNode  *row;
+   TupleField  *tuple;
    HSTMT       htbl_stmt = NULL, hpkey_stmt = NULL;
    StatementClass *tbl_stmt;
    RETCODE     ret = SQL_ERROR, result, keyresult;
@@ -3457,16 +3759,16 @@ PGAPI_ForeignKeys(
    char        trig_args[1024];
    char        upd_rule[TABLE_NAME_STORAGE_LEN],
                del_rule[TABLE_NAME_STORAGE_LEN];
-   char       *pk_table_needed;
+   char        *pk_table_needed = NULL;
    char        fk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
-   char       *fk_table_needed;
+   char        *fk_table_needed = NULL;
    char        pk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
    char        schema_needed[SCHEMA_NAME_STORAGE_LEN + 1];
    char        schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1];
    char       *pkey_ptr,
-              *pkey_text,
+              *pkey_text = NULL,
               *fkey_ptr,
-              *fkey_text;
+              *fkey_text = NULL;
 
    ConnectionClass *conn;
    BOOL        pkey_alloced,
@@ -3479,23 +3781,22 @@ PGAPI_ForeignKeys(
                upd_rule_type = 0,
                del_rule_type = 0;
    SWORD       internal_asis_type = SQL_C_CHAR;
+
+#if (ODBCVER >= 0x0300)
    SWORD       defer_type;
+#endif
    char        pkey[MAX_INFO_STRING];
    Int2        result_cols;
    UInt4       relid1, relid2;
 
-   mylog("%s: entering...stmt=%u\n", func, stmt);
+   mylog("%s: entering...stmt=%x\n", func, stmt);
 
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
        return result;
 
-   stmt->manual_result = TRUE;
-   stmt->errormsg_created = TRUE;
-
    if (res = QR_Constructor(), !res)
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ForeignKeys result.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ForeignKeys result.", func);
        return SQL_ERROR;
    }
    SC_set_Result(stmt, res);
@@ -3506,26 +3807,34 @@ PGAPI_ForeignKeys(
     * a statement is actually executed, so we'll have to do this
     * ourselves.
     */
+#if (ODBCVER >= 0x0300)
    result_cols = 15;
+#else
+   result_cols = 14;
+#endif /* ODBCVER */
+   result_cols = FKS_LAST + 1;
    extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
+   stmt->catalog_result = TRUE;
    /* set the field names */
    QR_set_num_fields(res, result_cols);
-   QR_set_field_info(res, 0, "PKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 1, "PKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 2, "PKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 3, "PKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 4, "FKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 5, "FKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 6, "FKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 7, "FKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 8, "KEY_SEQ", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 9, "UPDATE_RULE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 10, "DELETE_RULE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 11, "FK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 12, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 13, "TRIGGER_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 14, "DEFERRABILITY", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, FKS_PKTABLE_CAT, "PKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, FKS_PKTABLE_SCHEM, "PKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, FKS_PKTABLE_NAME, "PKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, FKS_PKCOLUMN_NAME, "PKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, FKS_FKTABLE_CAT, "FKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, FKS_FKTABLE_SCHEM, "FKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, FKS_FKTABLE_NAME, "FKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, FKS_FKCOLUMN_NAME, "FKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, FKS_KEY_SEQ, "KEY_SEQ", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, FKS_UPDATE_RULE, "UPDATE_RULE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, FKS_DELETE_RULE, "DELETE_RULE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, FKS_FK_NAME, "FK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, FKS_PK_NAME, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+#if (ODBCVER >= 0x0300)
+   QR_set_field_info_v(res, FKS_DEFERRABILITY, "DEFERRABILITY", PG_TYPE_INT2, 2);
+#endif   /* ODBCVER >= 0x0300 */
+   QR_set_field_info_v(res, FKS_TRIGGER_NAME, "TRIGGER_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
    /*
     * also, things need to think that this statement is finished so the
@@ -3535,20 +3844,21 @@ PGAPI_ForeignKeys(
 
    /* set up the current tuple pointer for SQLFetch */
    stmt->currTuple = -1;
-   stmt->rowset_start = -1;
+   SC_set_rowset_start(stmt, -1, FALSE);
    SC_set_current_col(stmt, -1);
 
 
    result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt);
    if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys result.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys result.", func);
        return SQL_ERROR;
    }
 
-   tbl_stmt = (StatementClass *) htbl_stmt;
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
 
+   tbl_stmt = (StatementClass *) htbl_stmt;
    schema_needed[0] = '\0';
    schema_fetched[0] = '\0';
 
@@ -3556,11 +3866,10 @@ PGAPI_ForeignKeys(
    fk_table_needed = make_string(szFkTableName, cbFkTableName, NULL, 0);
 
    conn = SC_get_conn(stmt);
-
+#ifdef UNICODE_SUPPORT
    if (conn->unicode)
        internal_asis_type = INTERNAL_ASIS_TYPE;
-
-   pkey_text = fkey_text = NULL;
+#endif /* UNICODE_SUPPORT */
    pkey_alloced = fkey_alloced = FALSE;
 
    /*
@@ -3573,7 +3882,7 @@ PGAPI_ForeignKeys(
        if (conn->schema_support)
        {
            schema_strcat(schema_needed, "%.*s", szFkTableOwner, cbFkTableOwner, szFkTableName, cbFkTableName, conn);
-           sprintf(tables_query, "SELECT   pt.tgargs, "
+           snprintf(tables_query, sizeof(tables_query), "SELECT    pt.tgargs, "
                "       pt.tgnargs, "
                "       pt.tgdeferrable, "
                "       pt.tginitdeferred, "
@@ -3614,7 +3923,7 @@ PGAPI_ForeignKeys(
                fk_table_needed, schema_needed);
        }
        else
-           sprintf(tables_query, "SELECT   pt.tgargs, "
+           snprintf(tables_query, sizeof(tables_query), "SELECT    pt.tgargs, "
                "       pt.tgnargs, "
                "       pt.tgdeferrable, "
                "       pt.tginitdeferred, "
@@ -3652,7 +3961,7 @@ PGAPI_ForeignKeys(
 
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_full_error_copy(stmt, tbl_stmt);
+           SC_full_error_copy(stmt, tbl_stmt, FALSE);
            goto cleanup;
        }
 
@@ -3660,7 +3969,7 @@ PGAPI_ForeignKeys(
                               trig_args, sizeof(trig_args), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -3668,7 +3977,7 @@ PGAPI_ForeignKeys(
                               &trig_nargs, 0, NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -3676,7 +3985,7 @@ PGAPI_ForeignKeys(
                         trig_deferrable, sizeof(trig_deferrable), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -3684,7 +3993,7 @@ PGAPI_ForeignKeys(
                     trig_initdeferred, sizeof(trig_initdeferred), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -3692,7 +4001,7 @@ PGAPI_ForeignKeys(
                               upd_rule, sizeof(upd_rule), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -3700,7 +4009,7 @@ PGAPI_ForeignKeys(
                               del_rule, sizeof(del_rule), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -3708,21 +4017,21 @@ PGAPI_ForeignKeys(
                               &relid1, sizeof(relid1), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
        result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
                               &relid2, sizeof(relid2), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
        result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
                    pk_table_fetched, TABLE_NAME_STORAGE_LEN, NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -3732,7 +4041,7 @@ PGAPI_ForeignKeys(
                    schema_fetched, SCHEMA_NAME_STORAGE_LEN, NULL);
            if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
            {
-               SC_error_copy(stmt, tbl_stmt);
+               SC_error_copy(stmt, tbl_stmt, TRUE);
                goto cleanup;
            }
        }
@@ -3746,14 +4055,14 @@ PGAPI_ForeignKeys(
 
        if (result != SQL_SUCCESS)
        {
-           SC_full_error_copy(stmt, tbl_stmt);
+           SC_full_error_copy(stmt, tbl_stmt, FALSE);
            goto cleanup;
        }
 
        keyresult = PGAPI_AllocStmt(stmt->hdbc, &hpkey_stmt);
        if ((keyresult != SQL_SUCCESS) && (keyresult != SQL_SUCCESS_WITH_INFO))
        {
-           SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.");
+           SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.", func);
            goto cleanup;
        }
 
@@ -3761,7 +4070,7 @@ PGAPI_ForeignKeys(
                                  pkey, sizeof(pkey), NULL);
        if (keyresult != SQL_SUCCESS)
        {
-           SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.");
+           SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.", func);
            goto cleanup;
        }
 
@@ -3786,7 +4095,7 @@ PGAPI_ForeignKeys(
            keyresult = PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0, schema_fetched, SQL_NTS, pk_table_fetched, SQL_NTS);
            if (keyresult != SQL_SUCCESS)
            {
-               SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't get primary keys for PGAPI_ForeignKeys result.");
+               SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't get primary keys for PGAPI_ForeignKeys result.", func);
                goto cleanup;
            }
 
@@ -3848,6 +4157,7 @@ PGAPI_ForeignKeys(
            else if (!strcmp(upd_rule, "RI_FKey_setnull_del"))
                del_rule_type = SQL_SET_NULL;
 
+#if (ODBCVER >= 0x0300)
            /* Set deferrability type */
            if (!strcmp(trig_initdeferred, "y"))
                defer_type = SQL_INITIALLY_DEFERRED;
@@ -3855,6 +4165,7 @@ PGAPI_ForeignKeys(
                defer_type = SQL_INITIALLY_IMMEDIATE;
            else
                defer_type = SQL_NOT_DEFERRABLE;
+#endif   /* ODBCVER >= 0x0300 */
 
            /* Get to first primary key */
            pkey_ptr = trig_args;
@@ -3863,33 +4174,34 @@ PGAPI_ForeignKeys(
 
            for (k = 0; k < num_keys; k++)
            {
-               row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
+               tuple = QR_AddNew(res);
 
                pkey_text = getClientColumnName(conn, relid2, pkey_ptr, &pkey_alloced);
                fkey_text = getClientColumnName(conn, relid1, fkey_ptr, &fkey_alloced);
 
                mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func, pk_table_fetched, pkey_text);
-               set_tuplefield_null(&row->tuple[0]);
-               set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(schema_fetched));
-               set_tuplefield_string(&row->tuple[2], pk_table_fetched);
-               set_tuplefield_string(&row->tuple[3], pkey_text);
+               set_tuplefield_null(&tuple[FKS_PKTABLE_CAT]);
+               set_tuplefield_string(&tuple[FKS_PKTABLE_SCHEM], GET_SCHEMA_NAME(schema_fetched));
+               set_tuplefield_string(&tuple[FKS_PKTABLE_NAME], pk_table_fetched);
+               set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME], pkey_text);
 
                mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n", func, fk_table_needed, fkey_text);
-               set_tuplefield_null(&row->tuple[4]);
-               set_tuplefield_string(&row->tuple[5], GET_SCHEMA_NAME(schema_needed));
-               set_tuplefield_string(&row->tuple[6], fk_table_needed);
-               set_tuplefield_string(&row->tuple[7], fkey_text);
+               set_tuplefield_null(&tuple[FKS_FKTABLE_CAT]);
+               set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM], GET_SCHEMA_NAME(schema_needed));
+               set_tuplefield_string(&tuple[FKS_FKTABLE_NAME], fk_table_needed);
+               set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME], fkey_text);
 
                mylog("%s: upd_rule_type = '%i', del_rule_type = '%i'\n, trig_name = '%s'", func, upd_rule_type, del_rule_type, trig_args);
-               set_tuplefield_int2(&row->tuple[8], (Int2) (k + 1));
-               set_tuplefield_int2(&row->tuple[9], (Int2) upd_rule_type);
-               set_tuplefield_int2(&row->tuple[10], (Int2) del_rule_type);
-               set_tuplefield_null(&row->tuple[11]);
-               set_tuplefield_null(&row->tuple[12]);
-               set_tuplefield_string(&row->tuple[13], trig_args);
-               set_tuplefield_int2(&row->tuple[14], defer_type);
-
-               QR_add_tuple(res, row);
+               set_tuplefield_int2(&tuple[FKS_KEY_SEQ], (Int2) (k + 1));
+               set_tuplefield_int2(&tuple[FKS_UPDATE_RULE], (Int2) upd_rule_type);
+               set_tuplefield_int2(&tuple[FKS_DELETE_RULE], (Int2) del_rule_type);
+               set_tuplefield_null(&tuple[FKS_FK_NAME]);
+               set_tuplefield_null(&tuple[FKS_PK_NAME]);
+#if (ODBCVER >= 0x0300)
+               set_tuplefield_int2(&tuple[FKS_DEFERRABILITY], defer_type);
+#endif   /* ODBCVER >= 0x0300 */
+               set_tuplefield_string(&tuple[FKS_TRIGGER_NAME], trig_args);
+
                if (fkey_alloced)
                    free(fkey_text);
                fkey_alloced = FALSE;
@@ -3920,7 +4232,7 @@ PGAPI_ForeignKeys(
        if (conn->schema_support)
        {
            schema_strcat(schema_needed, "%.*s", szPkTableOwner, cbPkTableOwner, szPkTableName, cbPkTableName, conn);
-           sprintf(tables_query, "SELECT   pt.tgargs, "
+           snprintf(tables_query, sizeof(tables_query), "SELECT    pt.tgargs, "
                "       pt.tgnargs, "
                "       pt.tgdeferrable, "
                "       pt.tginitdeferred, "
@@ -3960,7 +4272,7 @@ PGAPI_ForeignKeys(
                pk_table_needed, schema_needed);
        }
        else
-           sprintf(tables_query, "SELECT   pt.tgargs, "
+           snprintf(tables_query, sizeof(tables_query), "SELECT    pt.tgargs, "
                "       pt.tgnargs, "
                "       pt.tgdeferrable, "
                "       pt.tginitdeferred, "
@@ -3996,7 +4308,7 @@ PGAPI_ForeignKeys(
        result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -4004,7 +4316,7 @@ PGAPI_ForeignKeys(
                               trig_args, sizeof(trig_args), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -4012,7 +4324,7 @@ PGAPI_ForeignKeys(
                               &trig_nargs, 0, NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -4020,7 +4332,7 @@ PGAPI_ForeignKeys(
                         trig_deferrable, sizeof(trig_deferrable), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -4028,7 +4340,7 @@ PGAPI_ForeignKeys(
                     trig_initdeferred, sizeof(trig_initdeferred), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -4036,7 +4348,7 @@ PGAPI_ForeignKeys(
                               upd_rule, sizeof(upd_rule), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -4044,7 +4356,7 @@ PGAPI_ForeignKeys(
                               del_rule, sizeof(del_rule), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -4052,21 +4364,21 @@ PGAPI_ForeignKeys(
                        &relid1, sizeof(relid1), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
        result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
                        &relid2, sizeof(relid2), NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
        result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
                    fk_table_fetched, TABLE_NAME_STORAGE_LEN, NULL);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_error_copy(stmt, tbl_stmt);
+           SC_error_copy(stmt, tbl_stmt, TRUE);
            goto cleanup;
        }
 
@@ -4076,7 +4388,7 @@ PGAPI_ForeignKeys(
                    schema_fetched, SCHEMA_NAME_STORAGE_LEN, NULL);
            if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
            {
-               SC_error_copy(stmt, tbl_stmt);
+               SC_error_copy(stmt, tbl_stmt, TRUE);
                goto cleanup;
            }
        }
@@ -4090,7 +4402,7 @@ PGAPI_ForeignKeys(
 
        if (result != SQL_SUCCESS)
        {
-           SC_full_error_copy(stmt, tbl_stmt);
+           SC_full_error_copy(stmt, tbl_stmt, FALSE);
            goto cleanup;
        }
 
@@ -4122,6 +4434,7 @@ PGAPI_ForeignKeys(
            else if (!strcmp(upd_rule, "RI_FKey_setnull_del"))
                del_rule_type = SQL_SET_NULL;
 
+#if (ODBCVER >= 0x0300)
            /* Set deferrability type */
            if (!strcmp(trig_initdeferred, "y"))
                defer_type = SQL_INITIALLY_DEFERRED;
@@ -4129,6 +4442,7 @@ PGAPI_ForeignKeys(
                defer_type = SQL_INITIALLY_IMMEDIATE;
            else
                defer_type = SQL_NOT_DEFERRABLE;
+#endif   /* ODBCVER >= 0x0300 */
 
            mylog("Foreign Key Case#1: trig_nargs = %d, num_keys = %d\n", trig_nargs, num_keys);
 
@@ -4149,35 +4463,36 @@ PGAPI_ForeignKeys(
 
                mylog("pkey_ptr = '%s', fk_table = '%s', fkey_ptr = '%s'\n", pkey_text, fk_table_fetched, fkey_text);
 
-               row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
+               tuple = QR_AddNew(res);
 
                mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n", pk_table_needed, pkey_text);
-               set_tuplefield_null(&row->tuple[0]);
-               set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(schema_needed));
-               set_tuplefield_string(&row->tuple[2], pk_table_needed);
-               set_tuplefield_string(&row->tuple[3], pkey_text);
+               set_tuplefield_null(&tuple[FKS_PKTABLE_CAT]);
+               set_tuplefield_string(&tuple[FKS_PKTABLE_SCHEM], GET_SCHEMA_NAME(schema_needed));
+               set_tuplefield_string(&tuple[FKS_PKTABLE_NAME], pk_table_needed);
+               set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME], pkey_text);
 
                mylog("fk_table = '%s', fkey_ptr = '%s'\n", fk_table_fetched, fkey_text);
-               set_tuplefield_null(&row->tuple[4]);
-               set_tuplefield_string(&row->tuple[5], GET_SCHEMA_NAME(schema_fetched));
-               set_tuplefield_string(&row->tuple[6], fk_table_fetched);
-               set_tuplefield_string(&row->tuple[7], fkey_text);
+               set_tuplefield_null(&tuple[FKS_FKTABLE_CAT]);
+               set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM], GET_SCHEMA_NAME(schema_fetched));
+               set_tuplefield_string(&tuple[FKS_FKTABLE_NAME], fk_table_fetched);
+               set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME], fkey_text);
 
-               set_tuplefield_int2(&row->tuple[8], (Int2) (k + 1));
+               set_tuplefield_int2(&tuple[FKS_KEY_SEQ], (Int2) (k + 1));
 
                mylog("upd_rule = %d, del_rule= %d", upd_rule_type, del_rule_type);
-               set_nullfield_int2(&row->tuple[9], (Int2) upd_rule_type);
-               set_nullfield_int2(&row->tuple[10], (Int2) del_rule_type);
+               set_nullfield_int2(&tuple[FKS_UPDATE_RULE], (Int2) upd_rule_type);
+               set_nullfield_int2(&tuple[FKS_DELETE_RULE], (Int2) del_rule_type);
 
-               set_tuplefield_null(&row->tuple[11]);
-               set_tuplefield_null(&row->tuple[12]);
+               set_tuplefield_null(&tuple[FKS_FK_NAME]);
+               set_tuplefield_null(&tuple[FKS_PK_NAME]);
 
-               set_tuplefield_string(&row->tuple[13], trig_args);
+               set_tuplefield_string(&tuple[FKS_TRIGGER_NAME], trig_args);
 
+#if (ODBCVER >= 0x0300)
                mylog(" defer_type = %d\n", defer_type);
-               set_tuplefield_int2(&row->tuple[14], defer_type);
+               set_tuplefield_int2(&tuple[FKS_DEFERRABILITY], defer_type);
+#endif   /* ODBCVER >= 0x0300 */
 
-               QR_add_tuple(res, row);
                if (pkey_alloced)
                    free(pkey_text);
                pkey_alloced = FALSE;
@@ -4197,30 +4512,27 @@ PGAPI_ForeignKeys(
    }
    else
    {
-       SC_set_error(stmt, STMT_INTERNAL_ERROR, "No tables specified to PGAPI_ForeignKeys.");
+       SC_set_error(stmt, STMT_INTERNAL_ERROR, "No tables specified to PGAPI_ForeignKeys.", func);
        goto cleanup;
    }
    ret = SQL_SUCCESS;
 
 cleanup:
-   if (fk_table_needed)
-       free(fk_table_needed);
-   if (pk_table_needed)
-       free(pk_table_needed);
-
-
+#undef return
    /*
     * also, things need to think that this statement is finished so the
     * results can be retrieved.
     */
    stmt->status = STMT_FINISHED;
 
-   if (SQL_ERROR == ret)
-       SC_log_error(func, "", stmt);
    if (pkey_alloced)
        free(pkey_text);
    if (fkey_alloced)
        free(fkey_text);
+   if (pk_table_needed)
+       free(pk_table_needed);
+   if (fk_table_needed)
+       free(fk_table_needed);
 
    if (htbl_stmt)
        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
@@ -4229,79 +4541,128 @@ cleanup:
 
    /* set up the current tuple pointer for SQLFetch */
    stmt->currTuple = -1;
-   stmt->rowset_start = -1;
+   SC_set_rowset_start(stmt, -1, FALSE);
    SC_set_current_col(stmt, -1);
 
-   mylog("%s(): EXIT, stmt=%u, ret=%d\n", func, stmt, ret);
+   if (stmt->internal)
+       ret = DiscardStatementSvp(stmt, ret, FALSE);
+   mylog("%s(): EXIT, stmt=%x, ret=%d\n", func, stmt, ret);
    return ret;
 }
 
 
+#define    PRORET_COUNT
 RETCODE        SQL_API
 PGAPI_ProcedureColumns(
-                      HSTMT hstmt,
-                      UCHAR FAR * szProcQualifier,
-                      SWORD cbProcQualifier,
-                      UCHAR FAR * szProcOwner,
-                      SWORD cbProcOwner,
-                      UCHAR FAR * szProcName,
-                      SWORD cbProcName,
-                      UCHAR FAR * szColumnName,
-                      SWORD cbColumnName)
+               HSTMT hstmt,
+               const SQLCHAR FAR * szProcQualifier, /* OA */
+               SQLSMALLINT cbProcQualifier,
+               const SQLCHAR FAR * szProcOwner, /* PV */
+               SQLSMALLINT cbProcOwner,
+               const SQLCHAR FAR * szProcName, /* PV */
+               SQLSMALLINT cbProcName,
+               const SQLCHAR FAR * szColumnName, /* PV */
+               SQLSMALLINT cbColumnName,
+               UWORD flag)
 {
    CSTR func = "PGAPI_ProcedureColumns";
    StatementClass  *stmt = (StatementClass *) hstmt;
    ConnectionClass *conn = SC_get_conn(stmt);
    char        proc_query[INFO_INQUIRY_LEN];
    Int2        result_cols;
-   TupleNode   *row;
-   char        *schema_name, *procname, *params;
+   TupleField  *tuple;
+   char        *schema_name, *procname;
+   char        *escProcName = NULL;
+   char        *params, *proargnames, *proargmodes, *delim;
+   char        *atttypid, *attname, *column_name;
    QResultClass *res, *tres;
    Int4        tcount, paramcount, i, j, pgtype;
    RETCODE     result;
-   const char *likeeq = "like";
+   BOOL        search_pattern, retout = TRUE;
+   const char  *like_or_eq;
+   int     ret_col = -1, ext_pos = -1, poid_pos = -1, attid_pos = -1, attname_pos = -1;
+   UInt4       poid = 0, newpoid;
 
    mylog("%s: entering...\n", func);
 
    if (PG_VERSION_LT(conn, 6.5))
    {
-       SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old");
-       SC_log_error(func, "Function not implemented", stmt);
+       SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old", func);
        return SQL_ERROR;
    }
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
        return result;
+   search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
+   if (search_pattern) 
+   {
+       like_or_eq = likeop;
+       escProcName = adjustLikePattern(szProcName, cbProcName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
+   }
+   else
+   {
+       like_or_eq = eqop;
+       escProcName = simpleCatalogEscape(szProcName, cbProcName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+   }
    if (conn->schema_support)
    {
        strcpy(proc_query, "select proname, proretset, prorettype, "
-               "pronargs, proargtypes, nspname from "
-               "pg_catalog.pg_namespace, pg_catalog.pg_proc where "
-               "pg_proc.pronamespace = pg_namespace.oid "
-               "and (not proretset)");
-       schema_strcat1(proc_query, " and nspname %s '%.*s'", likeeq, szProcOwner, cbProcOwner, szProcName, cbProcName, conn);
-       my_strcat1(proc_query, " and proname %s '%.*s'", likeeq, szProcName, cbProcName);
-       strcat(proc_query, " order by nspname, proname, proretset");
+               "pronargs, proargtypes, nspname, p.oid");
+       ret_col = ext_pos = 7;
+       poid_pos = 6;
+#ifdef PRORET_COUNT
+       strcat(proc_query, ", atttypid, attname");
+       attid_pos = ext_pos;
+       attname_pos = ext_pos + 1;
+       ret_col += 2;
+       ext_pos = ret_col;
+#endif /* PRORET_COUNT */
+       if (PG_VERSION_GE(conn, 8.0))
+       {
+           strcat(proc_query, ", proargnames");
+           ret_col++;
+       }
+       if (PG_VERSION_GE(conn, 8.1))
+       {
+           strcat(proc_query, ", proargmodes, proallargtypes");
+           ret_col++;
+       }
+#ifdef PRORET_COUNT
+       strcat(proc_query, " from ((pg_catalog.pg_namespace n inner join"
+                  " pg_catalog.pg_proc p on p.pronamespace = n.oid)"
+           " inner join pg_type t on t.oid = p.prorettype)"
+           " left outer join pg_attribute a on a.attrelid = t.typrelid "
+           " and attnum > 0 and not attisdropped where");
+#else
+       strcat(proc_query, " from pg_catalog.pg_namespace n,"
+                  " pg_catalog.pg_proc p where");
+                  " p.pronamespace = n.oid  and"
+                  " (not proretset) and");
+#endif /* PRORET_COUNT */
+       strcat(proc_query, " has_function_privilege(p.oid, 'EXECUTE')");
+       my_strcat1(proc_query, " and nspname %s '%.*s'", like_or_eq, szProcOwner, cbProcOwner);
+       snprintf(proc_query, sizeof(proc_query), "%s and proname %s '%s'", proc_query, like_or_eq, escProcName);
+       strcat(proc_query, " order by nspname, proname, p.oid, attnum");
    }
    else
    {
        strcpy(proc_query, "select proname, proretset, prorettype, "
                "pronargs, proargtypes from pg_proc where "
                "(not proretset)");
-       my_strcat1(proc_query, " and proname %s '%.*s'", likeeq, szProcName, cbProcName);
+       ret_col = 5;
+       /* my_strcat1(proc_query, " and proname %s '%.*s'", like_or_eq, szProcName, cbProcName); */
+       snprintf(proc_query, sizeof(proc_query), " and proname %s '%s'", proc_query, like_or_eq, escProcName);
        strcat(proc_query, " order by proname, proretset");
    }
-   if (tres = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !tres)
+   if (tres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(tres))
    {
-       SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_ProcedureColumns query error");
+       SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_ProcedureColumns query error", func);
+       QR_Destructor(tres);
        return SQL_ERROR;
    }
 
-   stmt->manual_result = TRUE;
-   stmt->errormsg_created = TRUE;
    if (res = QR_Constructor(), !res)
    {
-       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ProcedureColumns result.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ProcedureColumns result.", func);
        return SQL_ERROR;
    }
    SC_set_Result(stmt, res);
@@ -4311,36 +4672,46 @@ PGAPI_ProcedureColumns(
     * a statement is actually executed, so we'll have to do this
     * ourselves.
     */
+#if (ODBCVER >= 0x0300)
    result_cols = 19;
+#else
+   result_cols = 13;
+#endif /* ODBCVER */
    extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
    /* set the field names */
    QR_set_num_fields(res, result_cols);
-   QR_set_field_info(res, 0, "PROCEDURE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 1, "PROCEDUR_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 2, "PROCEDURE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 4, "COLUMN_TYPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 5, "DATA_TYPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 6, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 7, "COLUMN_SIZE", PG_TYPE_INT4, 4);
-   QR_set_field_info(res, 8, "BUFFER_LENGTH", PG_TYPE_INT4, 4);
-   QR_set_field_info(res, 9, "DECIMAL_DIGITS", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 10, "NUM_PREC_RADIX", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 11, "NULLABLE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 12, "REMARKS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 13, "COLUMN_DEF", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 14, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 15, "SQL_DATATIME_SUB", PG_TYPE_INT2, 2);
-   QR_set_field_info(res, 16, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
-   QR_set_field_info(res, 17, "ORIDINAL_POSITION", PG_TYPE_INT4, 4);
-   QR_set_field_info(res, 18, "IS_NULLABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-
-   if (0 == cbColumnName || !szColumnName || !szColumnName[0])
-       tcount = QR_get_num_total_tuples(tres);
-   else
+   QR_set_field_info_v(res, 0, "PROCEDURE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 1, "PROCEDUR_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 2, "PROCEDURE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 3, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 4, "COLUMN_TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 5, "DATA_TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 6, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 7, "COLUMN_SIZE", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, 8, "BUFFER_LENGTH", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, 9, "DECIMAL_DIGITS", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 10, "NUM_PREC_RADIX", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 11, "NULLABLE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 12, "REMARKS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+#if (ODBCVER >= 0x0300)
+   QR_set_field_info_v(res, 13, "COLUMN_DEF", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 14, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 15, "SQL_DATATIME_SUB", PG_TYPE_INT2, 2);
+   QR_set_field_info_v(res, 16, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, 17, "ORIDINAL_POSITION", PG_TYPE_INT4, 4);
+   QR_set_field_info_v(res, 18, "IS_NULLABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+#endif   /* ODBCVER >= 0x0300 */
+
+   column_name = make_string(szColumnName, cbColumnName, NULL, 0);
+   if (column_name) /* column_name is unavailable now */
+   {
        tcount = 0;
-   for (i = 0; i < tcount; i++)
+       free(column_name);
+   }
+   else
+       tcount = QR_get_num_total_tuples(tres);
+   for (i = 0, poid = 0; i < tcount; i++)
    {
        if (conn->schema_support)
            schema_name = GET_SCHEMA_NAME(QR_get_value_backend_row(tres, i, 5));
@@ -4348,60 +4719,209 @@ PGAPI_ProcedureColumns(
            schema_name = NULL;
        procname = QR_get_value_backend_row(tres, i, 0);
        pgtype = atoi(QR_get_value_backend_row(tres, i, 2));
-       if (pgtype != 0)
+       newpoid = 0;
+       if (poid_pos >= 0)
+           newpoid = atoi(QR_get_value_backend_row(tres, i, poid_pos));
+mylog("newpoid=%d\n", newpoid);
+       atttypid = NULL;
+       if (attid_pos >= 0)
+       {
+           atttypid = QR_get_value_backend_row(tres, i, attid_pos);
+mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
+       }
+       if (poid == 0 || newpoid != poid)
        {
-           row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
-           set_tuplefield_null(&row->tuple[0]);
-           set_nullfield_string(&row->tuple[1], schema_name);
-           set_tuplefield_string(&row->tuple[2], procname);
-           set_tuplefield_string(&row->tuple[3], "");
-           set_tuplefield_int2(&row->tuple[4], SQL_RETURN_VALUE);
-           set_tuplefield_int2(&row->tuple[5], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
-           set_tuplefield_string(&row->tuple[6], pgtype_to_name(stmt, pgtype));
-           set_nullfield_int4(&row->tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
-           set_tuplefield_int4(&row->tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
-           set_nullfield_int2(&row->tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
-           set_nullfield_int2(&row->tuple[10], pgtype_radix(stmt, pgtype));
-           set_tuplefield_int2(&row->tuple[11], SQL_NULLABLE_UNKNOWN);
-           set_tuplefield_null(&row->tuple[12]);
-           set_tuplefield_null(&row->tuple[13]);
-           set_nullfield_int2(&row->tuple[14], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
-           set_nullfield_int2(&row->tuple[15], pgtype_to_datetime_sub(stmt, pgtype));
-           set_nullfield_int4(&row->tuple[16], pgtype_transfer_octet_length(stmt, pgtype, PG_STATIC, PG_STATIC));
-           set_tuplefield_int4(&row->tuple[17], 0);
-           set_tuplefield_string(&row->tuple[18], "");
-           QR_add_tuple(res, row);
+           poid = newpoid;
+           proargmodes = NULL;
+           proargnames = NULL;
+           if (ext_pos >=0)
+           {
+#ifdef NOT_USED /* !! named parameter is unavailable !! */
+               if (PG_VERSION_GE(conn, 8.0))
+                   proargnames = QR_get_value_backend_row(tres, i, ext_pos);
+#endif /* NOT_USED */
+               if (PG_VERSION_GE(conn, 8.1))
+                   proargmodes = QR_get_value_backend_row(tres, i, ext_pos + 1);
+           }
+           /* RETURN_VALUE info */ 
+           if (pgtype != 0 && pgtype != PG_TYPE_VOID && !atttypid && !proargmodes)
+           {
+               tuple = QR_AddNew(res);
+               set_tuplefield_null(&tuple[0]);
+               set_nullfield_string(&tuple[1], schema_name);
+               set_tuplefield_string(&tuple[2], procname);
+               set_tuplefield_string(&tuple[3], "");
+               set_tuplefield_int2(&tuple[4], SQL_RETURN_VALUE);
+               set_tuplefield_int2(&tuple[5], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
+               set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, pgtype));
+               set_nullfield_int4(&tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
+               set_tuplefield_int4(&tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
+               set_nullfield_int2(&tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
+               set_nullfield_int2(&tuple[10], pgtype_radix(stmt, pgtype));
+               set_tuplefield_int2(&tuple[11], SQL_NULLABLE_UNKNOWN);
+               set_tuplefield_null(&tuple[12]);
+#if (ODBCVER >= 0x0300)
+               set_tuplefield_null(&tuple[13]);
+               set_nullfield_int2(&tuple[14], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
+               set_nullfield_int2(&tuple[15], pgtype_to_datetime_sub(stmt, pgtype));
+               set_nullfield_int4(&tuple[16], pgtype_transfer_octet_length(stmt, pgtype, PG_STATIC, PG_STATIC));
+               set_tuplefield_int4(&tuple[17], 0);
+               set_tuplefield_string(&tuple[18], "");
+#endif   /* ODBCVER >= 0x0300 */
+           }
+           if (proargmodes)
+           {
+               const char *p;
+
+               paramcount = 0;
+               for (p = proargmodes; *p; p++)
+               {
+                   if (',' == (*p))
+                       paramcount++;
+               }
+               paramcount++;
+               params = QR_get_value_backend_row(tres, i, 8);
+               if ('{' == *proargmodes)
+                   proargmodes++;
+               if ('{' == *params)
+                   params++;
+           }
+           else
+           {
+               paramcount = atoi(QR_get_value_backend_row(tres, i, 3));
+               params = QR_get_value_backend_row(tres, i, 4);
+           }
+           if (proargnames)
+           {
+               if ('{' == *proargnames)
+                   proargnames++;
+           }
+           /* PARAMETERS info */
+           for (j = 0; j < paramcount; j++)
+           {
+               /* PG type of parameters */
+               pgtype = 0;
+               if (params)
+               {
+                   while (isspace(*params) || ',' == *params)
+                       params++;
+                   if ('\0' == *params || '}' == *params)
+                       params = NULL;
+                   else
+                   {
+                       sscanf(params, "%d", &pgtype);
+                       while (isdigit(*params))
+                           params++;
+                   }
+               }
+               /* input/output type of parameters */
+               if (proargmodes)
+               {
+                   while (isspace(*proargmodes) || ',' == *proargmodes)
+                       proargmodes++;
+                   if ('\0' == *proargmodes || '}' == *proargmodes)
+                       proargmodes = NULL;
+               }
+               /* name of parameters */
+               if (proargnames)
+               {
+                   while (isspace(*proargnames) || ',' == *proargnames)
+                       proargnames++;
+                   if ('\0' == *proargnames || '}' == *proargnames)
+                       proargnames = NULL;
+                   else if ('"' == *proargnames)
+                   {
+                       proargnames++;
+                       for (delim = proargnames; *delim && *delim != '"'; delim++)
+                           ;
+                   }
+                   else
+                   {
+                       for (delim = proargnames; *delim && !isspace(*delim) && ',' != *delim && '}' != *delim; delim++)
+                           ;
+                   }
+                   if (proargnames && '\0' == *delim) /* discard the incomplete name */
+                       proargnames = NULL;
+               }
+
+               tuple = QR_AddNew(res);
+               set_tuplefield_null(&tuple[0]);
+               set_nullfield_string(&tuple[1], schema_name);
+               set_tuplefield_string(&tuple[2], procname);
+               if (proargnames)
+               {
+                   *delim = '\0';
+                   set_tuplefield_string(&tuple[3], proargnames);
+                   proargnames = delim + 1;
+               }
+               else
+                   set_tuplefield_string(&tuple[3], "");
+               if (proargmodes)
+               {
+                   int ptype;
+
+                   switch (*proargmodes)
+                   {
+                       case 'o':
+                           ptype = SQL_PARAM_OUTPUT;
+                       case 'b':
+                           ptype = SQL_PARAM_INPUT_OUTPUT;
+                           break;
+                       default:
+                           ptype = SQL_PARAM_INPUT;
+                           break;
+                   }
+                   set_tuplefield_int2(&tuple[4], ptype);
+                   proargmodes++;
+               }
+               else
+                   set_tuplefield_int2(&tuple[4], SQL_PARAM_INPUT);
+               set_tuplefield_int2(&tuple[5], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
+               set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, pgtype));
+               set_nullfield_int4(&tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
+               set_tuplefield_int4(&tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
+               set_nullfield_int2(&tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
+               set_nullfield_int2(&tuple[10], pgtype_radix(stmt, pgtype));
+               set_tuplefield_int2(&tuple[11], SQL_NULLABLE_UNKNOWN);
+               set_tuplefield_null(&tuple[12]);
+#if (ODBCVER >= 0x0300)
+               set_tuplefield_null(&tuple[13]);
+               set_nullfield_int2(&tuple[14], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
+               set_nullfield_int2(&tuple[15], pgtype_to_datetime_sub(stmt, pgtype));
+               set_nullfield_int4(&tuple[16], pgtype_transfer_octet_length(stmt, pgtype, PG_STATIC, PG_STATIC));
+               set_tuplefield_int4(&tuple[17], j + 1);
+               set_tuplefield_string(&tuple[18], "");
+#endif   /* ODBCVER >= 0x0300 */
+           }
        }
-       paramcount = atoi(QR_get_value_backend_row(tres, i, 3));
-       params = QR_get_value_backend_row(tres, i, 4);
-       for (j = 0; j < paramcount; j++)
+       /* RESULT Columns info */
+       if (atttypid != NULL)
        {
-           while (isspace(*params))
-               params++;
-           sscanf(params, "%d", &pgtype);
-           row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
-           set_tuplefield_null(&row->tuple[0]);
-           set_nullfield_string(&row->tuple[1], schema_name);
-           set_tuplefield_string(&row->tuple[2], procname);
-           set_tuplefield_string(&row->tuple[3], "");
-           set_tuplefield_int2(&row->tuple[4], SQL_PARAM_INPUT);
-           set_tuplefield_int2(&row->tuple[5], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
-           set_tuplefield_string(&row->tuple[6], pgtype_to_name(stmt, pgtype));
-           set_nullfield_int4(&row->tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
-           set_tuplefield_int4(&row->tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
-           set_nullfield_int2(&row->tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
-           set_nullfield_int2(&row->tuple[10], pgtype_radix(stmt, pgtype));
-           set_tuplefield_int2(&row->tuple[11], SQL_NULLABLE_UNKNOWN);
-           set_tuplefield_null(&row->tuple[12]);
-           set_tuplefield_null(&row->tuple[13]);
-           set_nullfield_int2(&row->tuple[14], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
-           set_nullfield_int2(&row->tuple[15], pgtype_to_datetime_sub(stmt, pgtype));
-           set_nullfield_int4(&row->tuple[16], pgtype_transfer_octet_length(stmt, pgtype, PG_STATIC, PG_STATIC));
-           set_tuplefield_int4(&row->tuple[17], j + 1);
-           set_tuplefield_string(&row->tuple[18], "");
-           QR_add_tuple(res, row);
-           while (isdigit(*params))
-               params++;
+           int typid = atoi(atttypid);
+
+           attname = QR_get_value_backend_row(tres, i, attname_pos);
+           tuple = QR_AddNew(res);
+           set_tuplefield_null(&tuple[0]);
+           set_nullfield_string(&tuple[1], schema_name);
+           set_tuplefield_string(&tuple[2], procname);
+           set_tuplefield_string(&tuple[3], attname);
+           set_tuplefield_int2(&tuple[4], SQL_RESULT_COL);
+           set_tuplefield_int2(&tuple[5], pgtype_to_concise_type(stmt, typid, PG_STATIC));
+           set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, typid));
+           set_nullfield_int4(&tuple[7], pgtype_column_size(stmt, typid, PG_STATIC, PG_STATIC));
+           set_tuplefield_int4(&tuple[8], pgtype_buffer_length(stmt, typid, PG_STATIC, PG_STATIC));
+           set_nullfield_int2(&tuple[9], pgtype_decimal_digits(stmt, typid, PG_STATIC));
+           set_nullfield_int2(&tuple[10], pgtype_radix(stmt, typid));
+           set_tuplefield_int2(&tuple[11], SQL_NULLABLE_UNKNOWN);
+           set_tuplefield_null(&tuple[12]);
+#if (ODBCVER >= 0x0300)
+           set_tuplefield_null(&tuple[13]);
+           set_nullfield_int2(&tuple[14], pgtype_to_sqldesctype(stmt, typid, PG_STATIC));
+           set_nullfield_int2(&tuple[15], pgtype_to_datetime_sub(stmt, typid));
+           set_nullfield_int4(&tuple[16], pgtype_transfer_octet_length(stmt, typid, PG_STATIC, PG_STATIC));
+           set_tuplefield_int4(&tuple[17], 0);
+           set_tuplefield_string(&tuple[18], "");
+#endif   /* ODBCVER >= 0x0300 */
        }
    }
    QR_Destructor(tres);
@@ -4409,10 +4929,12 @@ PGAPI_ProcedureColumns(
     * also, things need to think that this statement is finished so the
     * results can be retrieved.
     */
+   if (escProcName)
+       free(escProcName);
    stmt->status = STMT_FINISHED;
    /* set up the current tuple pointer for SQLFetch */
    stmt->currTuple = -1;
-   stmt->rowset_start = -1;
+   SC_set_rowset_start(stmt, -1, FALSE);
    SC_set_current_col(stmt, -1);
 
    return SQL_SUCCESS;
@@ -4422,12 +4944,12 @@ PGAPI_ProcedureColumns(
 RETCODE        SQL_API
 PGAPI_Procedures(
                 HSTMT hstmt,
-                UCHAR FAR * szProcQualifier,
-                SWORD cbProcQualifier,
-                UCHAR FAR * szProcOwner,
-                SWORD cbProcOwner,
-                UCHAR FAR * szProcName,
-                SWORD cbProcName)
+                const SQLCHAR FAR * szProcQualifier, /* OA */
+                SQLSMALLINT cbProcQualifier,
+                const SQLCHAR FAR * szProcOwner, /* PV */
+                SQLSMALLINT cbProcOwner,
+                const SQLCHAR FAR * szProcName, /* PV */
+                SQLSMALLINT cbProcName)
 {
    CSTR func = "PGAPI_Procedures";
    StatementClass *stmt = (StatementClass *) hstmt;
@@ -4435,14 +4957,13 @@ PGAPI_Procedures(
    char        proc_query[INFO_INQUIRY_LEN];
    QResultClass *res;
    RETCODE     result;
-   const char *likeeq = "like";
+   CSTR    likeeq = "like";
 
    mylog("%s: entering... scnm=%x len=%d\n", func, szProcOwner, cbProcOwner);
 
    if (PG_VERSION_LT(conn, 6.5))
    {
-       SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old");
-       SC_log_error(func, "Function not implemented", stmt);
+       SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old", func);
        return SQL_ERROR;
    }
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
@@ -4474,9 +4995,10 @@ PGAPI_Procedures(
        my_strcat1(proc_query, " where proname %s '%.*s'", likeeq, szProcName, cbProcName);
    }
 
-   if (res = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !res)
+   if (res = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(res))
    {
-       SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_Procedures query error");
+       SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_Procedures query error", func);
+       QR_Destructor(res);
        return SQL_ERROR;
    }
    SC_set_Result(stmt, res);
@@ -4489,7 +5011,7 @@ PGAPI_Procedures(
    extend_column_bindings(SC_get_ARDF(stmt), 8);
    /* set up the current tuple pointer for SQLFetch */
    stmt->currTuple = -1;
-   stmt->rowset_start = -1;
+   SC_set_rowset_start(stmt, -1, FALSE);
    SC_set_current_col(stmt, -1);
 
    return SQL_SUCCESS;
@@ -4522,7 +5044,7 @@ usracl_auth(char *usracl, const char *auth)
 static void
 useracl_upd(char (*useracl)[ACLMAX], QResultClass *allures, const char *user, const char *auth)
 {
-   int usercount = QR_get_num_backend_tuples(allures), i, addcnt = 0;
+   int usercount = QR_get_num_cached_tuples(allures), i, addcnt = 0;
 
 mylog("user=%s auth=%s\n", user, auth);
    if (user[0])
@@ -4544,29 +5066,32 @@ mylog("user=%s auth=%s\n", user, auth);
 
 RETCODE        SQL_API
 PGAPI_TablePrivileges(
-                     HSTMT hstmt,
-                     UCHAR FAR * szTableQualifier,
-                     SWORD cbTableQualifier,
-                     UCHAR FAR * szTableOwner,
-                     SWORD cbTableOwner,
-                     UCHAR FAR * szTableName,
-                     SWORD cbTableName,
-                     UWORD flag)
+               HSTMT hstmt,
+               const SQLCHAR FAR * szTableQualifier, /* OA */
+               SQLSMALLINT cbTableQualifier,
+               const SQLCHAR FAR * szTableOwner, /* PV */
+               SQLSMALLINT cbTableOwner,
+               const SQLCHAR FAR * szTableName, /* PV */
+               SQLSMALLINT cbTableName,
+               UWORD flag)
 {
    StatementClass *stmt = (StatementClass *) hstmt;
    CSTR func = "PGAPI_TablePrivileges";
    ConnectionClass *conn = SC_get_conn(stmt);
    Int2        result_cols;
    char        proc_query[INFO_INQUIRY_LEN];
-   QResultClass    *res, *allures = NULL;
-   TupleNode   *row;
+   QResultClass    *res, *wres = NULL, *allures = NULL;
+   TupleField  *tuple;
    int     tablecount, usercount, i, j, k;
    BOOL        grpauth, sys, su;
-   char        (*useracl)[ACLMAX], *acl, *user, *delim, *auth;
+   char        (*useracl)[ACLMAX] = NULL, *acl, *user, *delim, *auth;
    char        *reln, *owner, *priv, *schnm = NULL;
-   RETCODE     result;
-   const char *likeeq = "like", *szSchemaName;
-   SWORD   cbSchemaName;
+   RETCODE     result, ret = SQL_SUCCESS;
+   const char  *like_or_eq;
+   const char  *szSchemaName;
+   SQLSMALLINT cbSchemaName;
+   char        *escSchemaName = NULL, *escTableName = NULL;
+   BOOL        search_pattern;
 
    mylog("%s: entering... scnm=%x len-%d\n", func, NULL_IF_NULL(szTableOwner), cbTableOwner);
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
@@ -4579,18 +5104,18 @@ PGAPI_TablePrivileges(
    result_cols = 7;
    extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
+   stmt->catalog_result = TRUE;
    /* set the field names */
-   stmt->manual_result = TRUE;
    res = QR_Constructor();
    SC_set_Result(stmt, res);
    QR_set_num_fields(res, result_cols);
-   QR_set_field_info(res, 0, "TABLE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 1, "TABLE_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 3, "GRANTOR", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 4, "GRANTEE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 5, "PRIVILEGE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-   QR_set_field_info(res, 6, "IS_GRANTABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 0, "TABLE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 1, "TABLE_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 3, "GRANTOR", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 4, "GRANTEE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 5, "PRIVILEGE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+   QR_set_field_info_v(res, 6, "IS_GRANTABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
    /*
     * also, things need to think that this statement is finished so the
@@ -4599,11 +5124,13 @@ PGAPI_TablePrivileges(
    stmt->status = STMT_FINISHED;
    /* set up the current tuple pointer for SQLFetch */
    stmt->currTuple = -1;
-   stmt->rowset_start = -1;
+   SC_set_rowset_start(stmt, -1, FALSE);
    SC_set_current_col(stmt, -1);
    szSchemaName = szTableOwner;
    cbSchemaName = cbTableOwner;
 
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
 retry_public_schema:
    if (conn->schema_support)
        strncpy_null(proc_query, "select relname, usename, relacl, nspname"
@@ -4612,43 +5139,40 @@ retry_public_schema:
    else
        strncpy_null(proc_query, "select relname, usename, relacl"
        " from pg_class , pg_user where", sizeof(proc_query));
-   if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0)
+   search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
+   if (search_pattern) 
    {
-       if (conn->schema_support)
-       {
-           schema_strcat(proc_query, " nspname = '%.*s' and", szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
-       }
-       my_strcat(proc_query, " relname = '%.*s' and", szTableName, cbTableName);
+       like_or_eq = likeop;
+       escSchemaName = adjustLikePattern(szSchemaName, cbSchemaName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
+       escTableName = adjustLikePattern(szTableName, cbTableName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
    }
    else
    {
-       char    esc_table_name[TABLE_NAME_STORAGE_LEN * 2];
-       int escTbnamelen;
-
-       if (conn->schema_support)
-       {
-           escTbnamelen = reallyEscapeCatalogEscapes(szSchemaName, cbSchemaName, esc_table_name, sizeof(esc_table_name), conn->ccsc);
-           schema_strcat1(proc_query, " nspname %s '%.*s' and", likeeq, esc_table_name, escTbnamelen, szTableName, cbTableName, conn);
-       }
-       escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc);
-       my_strcat1(proc_query, " relname %s '%.*s' and", likeeq, esc_table_name, escTbnamelen);
+       like_or_eq = eqop;
+       escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+       escTableName = simpleCatalogEscape(szTableName, cbTableName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
    }
-   if (!atoi(conn->connInfo.show_system_tables))
+   if (conn->schema_support)
    {
-       if (conn->schema_support)
-           strcat(proc_query, " nspname !~ '^" POSTGRES_SYS_PREFIX "' and");
-       else
-           strcat(proc_query, " relname !~ '^" POSTGRES_SYS_PREFIX "' and");
+       if (escSchemaName)
+           schema_strcat1(proc_query, " nspname %s '%.*s' and", like_or_eq, escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
    }
+   if (escTableName)
+       snprintf(proc_query, sizeof(proc_query), "%s relname %s '%s' and", proc_query, like_or_eq, escTableName);
    if (conn->schema_support)
-       strcat(proc_query, " pg_namespace.oid = relnamespace and");
+   {
+       strcat(proc_query, " pg_namespace.oid = relnamespace and relkind in ('r', 'v') and");
+       if ((!szTableName || !cbTableName) && (!szTableOwner || !cbTableOwner))
+           strcat(proc_query, " nspname not in ('pg_catalog', 'information_schema') and");
+   }
    strcat(proc_query, " pg_user.usesysid = relowner");
-   if (res = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !res)
+   if (wres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(wres))
    {
-       SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error");
-       return SQL_ERROR;
+       SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error", func);
+       ret = SQL_ERROR;
+       goto cleanup;
    }
-   tablecount = QR_get_num_backend_tuples(res);
+   tablecount = QR_get_num_cached_tuples(wres);
    /* If not found */
    if (conn->schema_support &&
        (flag & PODBC_SEARCH_PUBLIC_SCHEMA) != 0 &&
@@ -4663,11 +5187,12 @@ retry_public_schema:
         */
        if (szSchemaName &&
            (cbSchemaName == SQL_NTS ||
-            cbSchemaName == (SWORD) strlen(user)) &&
+            cbSchemaName == (SQLSMALLINT) strlen(user)) &&
            strnicmp(szSchemaName, user, strlen(user)) == 0 &&
            stricmp(CC_get_current_schema(conn), pubstr) == 0)
        {
-           QR_Destructor(res);
+           QR_Destructor(wres);
+           wres = NULL;
            szSchemaName = pubstr;
            cbSchemaName = SQL_NTS;
            goto retry_public_schema;
@@ -4675,18 +5200,18 @@ retry_public_schema:
    }
 
    strncpy_null(proc_query, "select usename, usesysid, usesuper from pg_user", sizeof(proc_query));
-   if (allures = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !allures)
+   if (allures = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(allures))
    {
-       QR_Destructor(res);
-       SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error");
-       return SQL_ERROR;
+       SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error", func);
+       ret = SQL_ERROR;
+       goto cleanup;
    }
-   usercount = QR_get_num_backend_tuples(allures);
+   usercount = QR_get_num_cached_tuples(allures);
    useracl = (char (*)[ACLMAX]) malloc(usercount * sizeof(char [ACLMAX]));
    for (i = 0; i < tablecount; i++)
    { 
        memset(useracl, 0, usercount * sizeof(char[ACLMAX]));
-       acl = (char *) QR_get_value_backend_row(res, i, 2);
+       acl = (char *) QR_get_value_backend_row(wres, i, 2);
        if (acl && acl[0] == '{')
            user = acl + 1;
        else
@@ -4722,7 +5247,7 @@ retry_public_schema:
                char    *grolist, *uid, *delm;
 
                snprintf(proc_query, sizeof(proc_query) - 1, "select grolist from pg_group where groname = '%s'", user);
-               if (gres = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), gres != NULL)
+               if (gres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(gres))
                {
                    grolist = QR_get_value_backend_row(gres, 0, 0);
                    if (grolist && grolist[0] == '{')
@@ -4742,8 +5267,8 @@ mylog("guid=%s\n", uid);
                            uid = delm + 1;
                        }
                    }
-                   QR_Destructor(gres);
                }
+               QR_Destructor(gres);
            }
            else
                useracl_upd(useracl, allures, user, auth);
@@ -4751,10 +5276,10 @@ mylog("guid=%s\n", uid);
                break;
            user = delim + 1;
        }
-       reln = QR_get_value_backend_row(res, i, 0);
-       owner = QR_get_value_backend_row(res, i, 1);
+       reln = QR_get_value_backend_row(wres, i, 0);
+       owner = QR_get_value_backend_row(wres, i, 1);
        if (conn->schema_support)
-           schnm = QR_get_value_backend_row(res, i, 3);
+           schnm = QR_get_value_backend_row(wres, i, 3);
        /* The owner has all privileges */
        useracl_upd(useracl, allures, owner, ALL_PRIVILIGES);
        for (j = 0; j < usercount; j++)
@@ -4775,19 +5300,19 @@ mylog("guid=%s\n", uid);
                    case 't': /* trigger */
                        continue;
                }
-               row = (TupleNode *) malloc(sizeof(TupleNode) + (7 - 1) *sizeof(TupleField));
-               set_tuplefield_string(&row->tuple[0], "");
+               tuple = QR_AddNew(res);
+               set_tuplefield_string(&tuple[0], "");
                if (conn->schema_support)
-                   set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(schnm));
+                   set_tuplefield_string(&tuple[1], GET_SCHEMA_NAME(schnm));
                else
-                   set_tuplefield_string(&row->tuple[1], "");
-               set_tuplefield_string(&row->tuple[2], reln);
+                   set_tuplefield_string(&tuple[1], "");
+               set_tuplefield_string(&tuple[2], reln);
                if (su || sys)
-                   set_tuplefield_string(&row->tuple[3], "_SYSTEM");
+                   set_tuplefield_string(&tuple[3], "_SYSTEM");
                else
-                   set_tuplefield_string(&row->tuple[3], owner);
+                   set_tuplefield_string(&tuple[3], owner);
                mylog("user=%s\n", user);
-               set_tuplefield_string(&row->tuple[4], user);
+               set_tuplefield_string(&tuple[4], user);
                switch (useracl[j][k])
                {
                    case 'a':
@@ -4808,19 +5333,33 @@ mylog("guid=%s\n", uid);
                    default:
                        priv = "";
                }
-               set_tuplefield_string(&row->tuple[5], priv);
+               set_tuplefield_string(&tuple[5], priv);
                /* The owner and the super user are grantable */
                if (sys || su)
-                   set_tuplefield_string(&row->tuple[6], "YES");
+                   set_tuplefield_string(&tuple[6], "YES");
                else
-                   set_tuplefield_string(&row->tuple[6], "NO");
-               QR_add_tuple(SC_get_Result(stmt), row);
+                   set_tuplefield_string(&tuple[6], "NO");
            }
        }
    }
-   free(useracl);
-   QR_Destructor(res);
-   QR_Destructor(allures); 
-   return SQL_SUCCESS;
+cleanup:
+#undef return
+   if (escSchemaName)
+       free(escSchemaName);
+   if (escTableName)
+       free(escTableName);
+   if (useracl)
+       free(useracl);
+   if (wres)
+       QR_Destructor(wres);
+   if (allures)
+       QR_Destructor(allures);
+   if (stmt->internal) 
+       ret = DiscardStatementSvp(stmt, ret, FALSE);
+   return ret;
 }
 
+#ifdef NOT_USED
+select n.nspname, c.relname, a.attname, a.atttypid, t.typname, a.attnotnull from ((pg_class c inner join pg_namespace n on c.oid = %u and c.relnamespace = n.oid) inner join pg_attribute a on a.attrelid = c.oid and a.attnum = %u) inner join pg_type t on t.oid = a.atttypid;
+#endif /* NOT USED */
+
index 7d3eab30e23c5a837b3768b5231bd8941b0e9827..7ef6f8a45ee9db4f23891095156404d9604813a3 100644 (file)
--- a/info30.c
+++ b/info30.c
@@ -7,12 +7,14 @@
  */
 
 #include "psqlodbc.h"
+
+#if (ODBCVER >= 0x0300)
 #include "connection.h"
 #include "pgapifunc.h"
 
 RETCODE        SQL_API
-PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
-               SWORD cbInfoValueMax, SWORD FAR * pcbInfoValue)
+PGAPI_GetInfo30(HDBC hdbc, SQLUSMALLINT fInfoType, PTR rgbInfoValue,
+           SQLSMALLINT cbInfoValueMax, SQLSMALLINT FAR * pcbInfoValue)
 {
    CSTR func = "PGAPI_GetInfo30";
    ConnectionClass *conn = (ConnectionClass *) hdbc;
@@ -40,6 +42,8 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
        case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
            len = 4;
            value = SQL_CA2_READ_ONLY_CONCURRENCY;
+           if (!ci->drivers.use_declarefetch || ci->drivers.lie)
+               value |= SQL_CA2_CRC_EXACT;
            break;
        case SQL_KEYSET_CURSOR_ATTRIBUTES1:
            len = 4;
@@ -47,7 +51,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
                | SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK
                | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION
                | SQL_CA1_POS_REFRESH;
-           if (ci->updatable_cursors || ci->drivers.lie)
+           if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
                value |= (SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
                | SQL_CA1_BULK_ADD
                | SQL_CA1_BULK_UPDATE_BY_BOOKMARK
@@ -65,14 +69,17 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
        case SQL_KEYSET_CURSOR_ATTRIBUTES2:
            len = 4;
            value = SQL_CA2_READ_ONLY_CONCURRENCY;
-           if (ci->updatable_cursors || ci->drivers.lie)
+           if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
                value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
                /*| SQL_CA2_CRC_APPROXIMATE*/
-               | SQL_CA2_CRC_EXACT
-               | SQL_CA2_SENSITIVITY_DELETIONS
+               );
+           if (0 != (ci->updatable_cursors & SENSE_SELF_OPERATIONS))
+               value |= (SQL_CA2_SENSITIVITY_DELETIONS
                | SQL_CA2_SENSITIVITY_UPDATES
                | SQL_CA2_SENSITIVITY_ADDITIONS
                );
+           if (!ci->drivers.use_declarefetch || ci->drivers.lie)
+               value |= SQL_CA2_CRC_EXACT;
            if (ci->drivers.lie)
                value |= (SQL_CA2_LOCK_CONCURRENCY
                | SQL_CA2_OPT_VALUES_CONCURRENCY
@@ -94,10 +101,12 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
                | SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK
                | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION
                | SQL_CA1_POS_REFRESH;
-           if (ci->updatable_cursors)
+           if (0 != (ci->updatable_cursors & ALLOW_STATIC_CURSORS))
                value |= (SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
                | SQL_CA1_BULK_ADD
-               | SQL_CA1_BULK_UPDATE_BY_BOOKMARK
+               );
+           if (0 != (ci->updatable_cursors & ALLOW_BULK_OPERATIONS))
+               value |= (SQL_CA1_BULK_UPDATE_BY_BOOKMARK
                | SQL_CA1_BULK_DELETE_BY_BOOKMARK
                | SQL_CA1_BULK_FETCH_BY_BOOKMARK
                );
@@ -105,12 +114,16 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
        case SQL_STATIC_CURSOR_ATTRIBUTES2:
            len = 4;
            value = SQL_CA2_READ_ONLY_CONCURRENCY;
-           if (ci->updatable_cursors)
+           if (0 != (ci->updatable_cursors & ALLOW_STATIC_CURSORS))
                value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
-               | SQL_CA2_CRC_EXACT
-               | SQL_CA2_SENSITIVITY_ADDITIONS
-               SQL_CA2_SENSITIVITY_DELETIONS
+               );
+           if (0 != (ci->updatable_cursors & SENSE_SELF_OPERATIONS))
+               value |= (SQL_CA2_SENSITIVITY_DELETIONS
                | SQL_CA2_SENSITIVITY_UPDATES
+               | SQL_CA2_SENSITIVITY_ADDITIONS
+               );
+           if (!ci->drivers.use_declarefetch || ci->drivers.lie)
+               value |= (SQL_CA2_CRC_EXACT
                );
            break;
 
@@ -146,7 +159,10 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
            break;
        case SQL_CATALOG_NAME:
            len = 0;
-           p = "N";
+           if (PG_VERSION_LE(conn, 7.2))
+               p = "N";
+           else
+               p = "N"; /* hopefully */
            break;
        case SQL_COLLATION_SEQ:
            len = 0;
@@ -179,11 +195,11 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
            len = 4;
            value = SQL_CT_CREATE_TABLE | SQL_CT_COLUMN_CONSTRAINT
                | SQL_CT_COLUMN_DEFAULT;
-           if (PG_VERSION_GE(conn, 6.5))
-               value |= SQL_CT_GLOBAL_TEMPORARY;
-           if (PG_VERSION_GE(conn, 7.0))
+           if (PG_VERSION_GE(conn, 6.5)) 
+               value |= SQL_CT_GLOBAL_TEMPORARY; 
+           if (PG_VERSION_GE(conn, 7.0)) 
                value |= SQL_CT_TABLE_CONSTRAINT
-                   | SQL_CT_CONSTRAINT_NAME_DEFINITION
+                   | SQL_CT_CONSTRAINT_NAME_DEFINITION 
                    | SQL_CT_CONSTRAINT_INITIALLY_DEFERRED
                    | SQL_CT_CONSTRAINT_INITIALLY_IMMEDIATE
                    | SQL_CT_CONSTRAINT_DEFERRABLE;
@@ -256,10 +272,9 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
            break;
        case SQL_MAX_IDENTIFIER_LEN:
            len = 2;
-            if (PG_VERSION_GT(conn, 7.2)) 
-               value = 64;
-            else
-                value = 32;
+           value = 32;
+           if (PG_VERSION_GT(conn, 7.2))
+               value = 64;
            break;
        case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
            len = 0;
@@ -295,7 +310,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
            break;
        case SQL_SQL92_NUMERIC_VALUE_FUNCTIONS:
            len = 4;
-           value = SQL_SNVF_BIT_LENGTH | SQL_SNVF_CHAR_LENGTH
+           value = SQL_SNVF_BIT_LENGTH | SQL_SNVF_CHAR_LENGTH 
                | SQL_SNVF_CHARACTER_LENGTH | SQL_SNVF_EXTRACT
                | SQL_SNVF_OCTET_LENGTH | SQL_SNVF_POSITION;
            break;
@@ -314,7 +329,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
                    | SQL_SRJO_FULL_OUTER_JOIN | SQL_SRJO_INNER_JOIN
                    | SQL_SRJO_INTERSECT_JOIN | SQL_SRJO_LEFT_OUTER_JOIN
                    | SQL_SRJO_NATURAL_JOIN | SQL_SRJO_RIGHT_OUTER_JOIN
-                   | SQL_SRJO_UNION_JOIN;
+                   | SQL_SRJO_UNION_JOIN; 
            break;
        case SQL_SQL92_REVOKE:
            len = 4;
@@ -335,6 +350,13 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
            len = 4;
            value = SQL_SVE_CASE | SQL_SVE_CAST | SQL_SVE_COALESCE | SQL_SVE_NULLIF;
            break;
+#ifdef SQL_DTC_TRANSACTION_COST
+       case SQL_DTC_TRANSACTION_COST:
+#else
+       case 1750:
+#endif
+           len = 4;
+           break;
        /* The followings aren't implemented yet */
        case SQL_DATETIME_LITERALS:
            len = 4;
@@ -350,40 +372,38 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
            len = 0;
        default:
            /* unrecognized key */
-           CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unrecognized key passed to SQLGetInfo30.");
-           CC_log_error(func, "", conn);
+           CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unrecognized key passed to SQLGetInfo30.", func);
            return SQL_ERROR;
    }
    result = SQL_SUCCESS;
-
+   mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax);
    if (p)
    {
        /* char/binary data */
        len = strlen(p);
-#ifdef  UNICODE_SUPPORT
-                /* Note that at this point we don't know if we've been called just
-                 * to get the length of the output. If it's unicode, then we better
-                 * adjust to bytes now, so we don't return a buffer size that's too
-                 * small.
-                 */
-                if (conn->unicode)
-                    len = len * WCLEN;
-#endif
+
        if (rgbInfoValue)
        {
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
            if (conn->unicode)
-               len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / 2);
+           {
+               len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / WCLEN);
+               len *= WCLEN;
+           }
            else
-#endif
-               strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
+#endif /* UNICODE_SUPPORT */
+           strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
 
            if (len >= cbInfoValueMax)
            {
                result = SQL_SUCCESS_WITH_INFO;
-               CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the InfoValue.");
+               CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for tthe InfoValue.", func);
            }
        }
+#ifdef UNICODE_SUPPORT
+       else if (conn->unicode)
+           len *= WCLEN;
+#endif /* UNICODE_SUPPORT */
    }
    else
    {
@@ -399,9 +419,6 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
 
    if (pcbInfoValue)
        *pcbInfoValue = len;
-
-   mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax);
-
    return result;
 }
-
+#endif /* ODBCVER >= 0x0300 */
diff --git a/inouealc.c b/inouealc.c
new file mode 100644 (file)
index 0000000..ee43b89
--- /dev/null
@@ -0,0 +1,233 @@
+#include   "psqlodbc.h"
+
+#undef malloc
+#undef calloc
+#undef realloc
+#undef strdup
+#undef free
+#undef memcpy
+#undef strcpy
+#undef memset
+#include   "misc.h"
+#include   <malloc.h>
+#include   <string.h>
+
+typedef struct {
+   size_t  len;
+   void    *aladr;
+} ALADR;
+
+static int alsize = 0;
+static int tbsize = 0;
+static ALADR   *altbl = NULL;
+
+CSTR   ALCERR  = "alcerr";
+void * debug_alloc(size_t size)
+{
+   void * alloced;
+   alloced = malloc(size);
+inolog(" alloced=%x(%d)\n", alloced, size);
+   if (alloced)
+   {
+       if (!alsize)
+       {
+           alsize = 100;
+           altbl = (ALADR *) malloc(alsize * sizeof(ALADR));
+       } 
+       else if (tbsize >= alsize)
+       {
+           alsize *= 2;
+           altbl = (ALADR *) realloc(altbl, alsize * sizeof(ALADR));
+       }
+       altbl[tbsize].aladr = alloced;
+       altbl[tbsize].len = size;
+       tbsize++; 
+   }
+   else
+       mylog("%s:alloc %dbyte\n", ALCERR, size);
+   return alloced;
+}
+void * debug_calloc(size_t n, size_t size)
+{
+   void * alloced = calloc(n, size);
+
+   if (alloced)
+   {
+       if (!alsize)
+       {
+           alsize = 100;
+           altbl = (ALADR *) malloc(alsize * sizeof(ALADR));
+       } 
+       else if (tbsize >= alsize)
+       {
+           alsize *= 2;
+           altbl = (ALADR *) realloc(altbl, alsize * sizeof(ALADR));
+       }
+       altbl[tbsize].aladr = alloced;
+       altbl[tbsize].len = n * size;
+       tbsize++; 
+   }
+   else
+       mylog("%s:calloc %dbyte\n", ALCERR, size);
+inolog("calloced = %x\n", alloced);
+   return alloced;
+}
+void * debug_realloc(void * ptr, size_t size)
+{
+   void * alloced = realloc(ptr, size);
+   if (!alloced)
+   {
+       mylog("%s:debug_realloc %x error\n", ALCERR, ptr);
+   }
+   else if (!ptr)
+   {
+       altbl[tbsize].aladr = alloced;
+       altbl[tbsize].len = size;
+       tbsize++;
+   }
+   else /* if (alloced != ptr) */
+   {
+       int i;
+       for (i = 0; i < tbsize; i++)
+       {
+           if (altbl[i].aladr == ptr)
+           {
+               altbl[i].aladr = alloced;
+               altbl[i].len = size;
+               break;
+           }   
+       }
+   }
+       
+   inolog("debug_realloc %x->%x\n", ptr, alloced);
+   return alloced;
+}
+char * debug_strdup(const char * ptr)
+{
+   char * alloced = strdup(ptr);
+   if (!alloced)
+   {
+       mylog("%s:debug_strdup %x error\n", ALCERR, ptr);
+   }
+   else
+   {
+       if (!alsize)
+       {
+           alsize = 100;
+           altbl = (ALADR *) malloc(alsize * sizeof(ALADR));
+       } 
+       else if (tbsize >= alsize)
+       {
+           alsize *= 2;
+           altbl = (ALADR *) realloc(altbl, alsize * sizeof(ALADR));
+       }
+       altbl[tbsize].aladr = alloced;
+       altbl[tbsize].len = strlen(ptr) + 1;
+       tbsize++; 
+   }
+   inolog("debug_strdup %x->%x(%s)\n", ptr, alloced, alloced);
+   return alloced;
+}
+
+void debug_free(void * ptr)
+{
+   int i, j;
+   int freed = 0;
+
+   if (!ptr)
+   {
+       mylog("%s:debug_freeing null ptr\n", ALCERR);
+       return;
+   }
+   for (i = 0; i < tbsize; i++)
+   {
+       if (altbl[i].aladr == ptr)
+       {
+           for (j = i; j < tbsize - 1; j++)
+           {
+               altbl[j].aladr = altbl[j + 1].aladr;
+               altbl[j].len = altbl[j + 1].len;
+           }
+           tbsize--;
+           freed =  1;
+           break;  
+       }
+   }
+   if (! freed)
+       mylog("%s:debug_freeing not found ptr %x\n", ALCERR, ptr);
+   else
+       inolog("debug_freeing ptr=%x\n", ptr);
+   free(ptr);
+}
+
+static BOOL out_check(void *out, size_t len, const char *name)
+{
+   BOOL    ret = TRUE;
+   int i;
+
+   for (i = 0; i < tbsize; i++)
+   {
+       if ((UInt4)out < (UInt4)(altbl[i].aladr))
+           continue;
+       if ((UInt4)out < (UInt4)(altbl[i].aladr) + altbl[i].len)
+       {
+           if ((UInt4)out + len > (UInt4)(altbl[i].aladr) + altbl[i].len)
+           {
+               ret = FALSE;
+               mylog("%s:%s:out_check found memory buffer overrun %x(%d)>=%x(%d)\n", ALCERR, name, out, len, altbl[i].aladr, altbl[i].len);
+           }
+           break;
+       }
+   }
+   return ret;
+}
+char *debug_strcpy(char *out, const char *in)
+{
+   if (!out || !in)
+   {
+       mylog("%s:debug_strcpy null pointer out=%x,in=%x\n", ALCERR, out, in);
+       return NULL;
+   }
+   out_check(out, strlen(in) + 1, "debug_strcpy");
+   return strcpy(out, in);
+}
+
+void *debug_memcpy(void *out, const void *in, size_t len)
+{
+   if (!out || !in)
+   {
+       mylog("%s:debug_memcpy null pointer out=%x,in=%x\n", ALCERR, out, in);
+       return NULL;
+   }
+   out_check(out, len, "debug_memcpy");
+   return memcpy(out, in, len);
+}
+
+void *debug_memset(void *out, int c, size_t len)
+{
+   if (!out)
+   {
+       mylog("%s:debug_memcpy null pointer out=%xx\n", ALCERR, out);
+       return NULL;
+   }
+   out_check(out, len, "debug_memset");
+   return memset(out, c, len);
+}
+
+void debug_memory_check(void)
+{
+   int i;
+
+   if (0 == tbsize)
+   {
+       mylog("no memry leak found and max count allocated so far is %d\n", alsize);
+   }
+   else
+   {
+       mylog("%s:memory leak found check count=%d alloc=%d\n", ALCERR, tbsize, alsize);
+       for (i = 0; i < tbsize; i++)
+       {
+           mylog("%s:leak = %x(%d)\n", ALCERR, altbl[i].aladr, altbl[i].len);
+       }
+   }
+}
index 983e6d604dc480f0f9538a39981c32acb308fe3d..bdf8ab0cb362a9ed14c7486a07232cfa984e793c 100644 (file)
          GNU LIBRARY GENERAL PUBLIC LICENSE
+
               Version 2, June 1991
 
+
+
  Copyright (C) 1991 Free Software Foundation, Inc.
+
                     675 Mass Ave, Cambridge, MA 02139, USA
+
  Everyone is permitted to copy and distribute verbatim copies
+
  of this license document, but changing it is not allowed.
 
+
+
 [This is the first released version of the library GPL.  It is
+
  numbered 2 because it goes with version 2 of the ordinary GPL.]
 
+
+
                Preamble
 
+
+
   The licenses for most software are designed to take away your
+
 freedom to share and change it.  By contrast, the GNU General Public
+
 Licenses are intended to guarantee your freedom to share and change
+
 free software--to make sure the software is free for all its users.
 
+
+
   This license, the Library General Public License, applies to some
+
 specially designated Free Software Foundation software, and to any
+
 other libraries whose authors decide to use it.  You can use it for
+
 your libraries, too.
 
+
+
   When we speak of free software, we are referring to freedom, not
+
 price.  Our General Public Licenses are designed to make sure that you
+
 have the freedom to distribute copies of free software (and charge for
+
 this service if you wish), that you receive source code or can get it
+
 if you want it, that you can change the software or use pieces of it
+
 in new free programs; and that you know you can do these things.
 
+
+
   To protect your rights, we need to make restrictions that forbid
+
 anyone to deny you these rights or to ask you to surrender the rights.
+
 These restrictions translate to certain responsibilities for you if
+
 you distribute copies of the library, or if you modify it.
 
+
+
   For example, if you distribute copies of the library, whether gratis
+
 or for a fee, you must give the recipients all the rights that we gave
+
 you.  You must make sure that they, too, receive or can get the source
+
 code.  If you link a program with the library, you must provide
+
 complete object files to the recipients so that they can relink them
+
 with the library, after making changes to the library and recompiling
+
 it.  And you must show them these terms so they know their rights.
 
+
+
   Our method of protecting your rights has two steps: (1) copyright
+
 the library, and (2) offer you this license which gives you legal
+
 permission to copy, distribute and/or modify the library.
 
+
+
   Also, for each distributor's protection, we want to make certain
+
 that everyone understands that there is no warranty for this free
+
 library.  If the library is modified by someone else and passed on, we
+
 want its recipients to know that what they have is not the original
+
 version, so that any problems introduced by others will not reflect on
+
 the original authors' reputations.
 
+\f
+
   Finally, any free program is threatened constantly by software
+
 patents.  We wish to avoid the danger that companies distributing free
+
 software will individually obtain patent licenses, thus in effect
+
 transforming the program into proprietary software.  To prevent this,
+
 we have made it clear that any patent must be licensed for everyone's
+
 free use or not licensed at all.
 
+
+
   Most GNU software, including some libraries, is covered by the ordinary
+
 GNU General Public License, which was designed for utility programs.  This
+
 license, the GNU Library General Public License, applies to certain
+
 designated libraries.  This license is quite different from the ordinary
+
 one; be sure to read it in full, and don't assume that anything in it is
+
 the same as in the ordinary license.
 
+
+
   The reason we have a separate public license for some libraries is that
+
 they blur the distinction we usually make between modifying or adding to a
+
 program and simply using it.  Linking a program with a library, without
+
 changing the library, is in some sense simply using the library, and is
+
 analogous to running a utility program or application program.  However, in
+
 a textual and legal sense, the linked executable is a combined work, a
+
 derivative of the original library, and the ordinary General Public License
+
 treats it as such.
 
+
+
   Because of this blurred distinction, using the ordinary General
+
 Public License for libraries did not effectively promote software
+
 sharing, because most developers did not use the libraries.  We
+
 concluded that weaker conditions might promote sharing better.
 
+
+
   However, unrestricted linking of non-free programs would deprive the
+
 users of those programs of all benefit from the free status of the
+
 libraries themselves.  This Library General Public License is intended to
+
 permit developers of non-free programs to use free libraries, while
+
 preserving your freedom as a user of such programs to change the free
+
 libraries that are incorporated in them.  (We have not seen how to achieve
+
 this as regards changes in header files, but we have achieved it as regards
+
 changes in the actual functions of the Library.)  The hope is that this
+
 will lead to faster development of free libraries.
 
+
+
   The precise terms and conditions for copying, distribution and
+
 modification follow.  Pay close attention to the difference between a
+
 "work based on the library" and a "work that uses the library".  The
+
 former contains code derived from the library, while the latter only
+
 works together with the library.
 
+
+
   Note that it is possible for a library to be covered by the ordinary
+
 General Public License rather than by this special one.
 
+\f
+
          GNU LIBRARY GENERAL PUBLIC LICENSE
+
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 
+
+
   0. This License Agreement applies to any software library which
+
 contains a notice placed by the copyright holder or other authorized
+
 party saying it may be distributed under the terms of this Library
+
 General Public License (also called "this License").  Each licensee is
+
 addressed as "you".
 
+
+
   A "library" means a collection of software functions and/or data
+
 prepared so as to be conveniently linked with application programs
+
 (which use some of those functions and data) to form executables.
 
+
+
   The "Library", below, refers to any such software library or work
+
 which has been distributed under these terms.  A "work based on the
+
 Library" means either the Library or any derivative work under
+
 copyright law: that is to say, a work containing the Library or a
+
 portion of it, either verbatim or with modifications and/or translated
+
 straightforwardly into another language.  (Hereinafter, translation is
+
 included without limitation in the term "modification".)
 
+
+
   "Source code" for a work means the preferred form of the work for
+
 making modifications to it.  For a library, complete source code means
+
 all the source code for all modules it contains, plus any associated
+
 interface definition files, plus the scripts used to control compilation
+
 and installation of the library.
 
+
+
   Activities other than copying, distribution and modification are not
+
 covered by this License; they are outside its scope.  The act of
+
 running a program using the Library is not restricted, and output from
+
 such a program is covered only if its contents constitute a work based
+
 on the Library (independent of the use of the Library in a tool for
+
 writing it).  Whether that is true depends on what the Library does
+
 and what the program that uses the Library does.
 
+  
+
   1. You may copy and distribute verbatim copies of the Library's
+
 complete source code as you receive it, in any medium, provided that
+
 you conspicuously and appropriately publish on each copy an
+
 appropriate copyright notice and disclaimer of warranty; keep intact
+
 all the notices that refer to this License and to the absence of any
+
 warranty; and distribute a copy of this License along with the
+
 Library.
 
+
+
   You may charge a fee for the physical act of transferring a copy,
+
 and you may at your option offer warranty protection in exchange for a
+
 fee.
 
+\f
+
   2. You may modify your copy or copies of the Library or any portion
+
 of it, thus forming a work based on the Library, and copy and
+
 distribute such modifications or work under the terms of Section 1
+
 above, provided that you also meet all of these conditions:
 
+
+
     a) The modified work must itself be a software library.
 
+
+
     b) You must cause the files modified to carry prominent notices
+
     stating that you changed the files and the date of any change.
 
+
+
     c) You must cause the whole of the work to be licensed at no
+
     charge to all third parties under the terms of this License.
 
+
+
     d) If a facility in the modified Library refers to a function or a
+
     table of data to be supplied by an application program that uses
+
     the facility, other than as an argument passed when the facility
+
     is invoked, then you must make a good faith effort to ensure that,
+
     in the event an application does not supply such function or
+
     table, the facility still operates, and performs whatever part of
+
     its purpose remains meaningful.
 
+
+
     (For example, a function in a library to compute square roots has
+
     a purpose that is entirely well-defined independent of the
+
     application.  Therefore, Subsection 2d requires that any
+
     application-supplied function or table used by this function must
+
     be optional: if the application does not supply it, the square
+
     root function must still compute square roots.)
 
 
+
 These requirements apply to the modified work as a whole.  If
+
 identifiable sections of that work are not derived from the Library,
+
 and can be reasonably considered independent and separate works in
+
 themselves, then this License, and its terms, do not apply to those
+
 sections when you distribute them as separate works.  But when you
+
 distribute the same sections as part of a whole which is a work based
+
 on the Library, the distribution of the whole must be on the terms of
+
 this License, whose permissions for other licensees extend to the
+
 entire whole, and thus to each and every part regardless of who wrote
+
 it.
 
+
+
 Thus, it is not the intent of this section to claim rights or contest
+
 your rights to work written entirely by you; rather, the intent is to
+
 exercise the right to control the distribution of derivative or
+
 collective works based on the Library.
 
+
+
 In addition, mere aggregation of another work not based on the Library
+
 with the Library (or with a work based on the Library) on a volume of
+
 a storage or distribution medium does not bring the other work under
+
 the scope of this License.
 
+
+
   3. You may opt to apply the terms of the ordinary GNU General Public
+
 License instead of this License to a given copy of the Library.  To do
+
 this, you must alter all the notices that refer to this License, so
+
 that they refer to the ordinary GNU General Public License, version 2,
+
 instead of to this License.  (If a newer version than version 2 of the
+
 ordinary GNU General Public License has appeared, then you can specify
+
 that version instead if you wish.)  Do not make any other change in
+
 these notices.
 
+\f
+
   Once this change is made in a given copy, it is irreversible for
+
 that copy, so the ordinary GNU General Public License applies to all
+
 subsequent copies and derivative works made from that copy.
 
+
+
   This option is useful when you wish to copy part of the code of
+
 the Library into a program that is not a library.
 
+
+
   4. You may copy and distribute the Library (or a portion or
+
 derivative of it, under Section 2) in object code or executable form
+
 under the terms of Sections 1 and 2 above provided that you accompany
+
 it with the complete corresponding machine-readable source code, which
+
 must be distributed under the terms of Sections 1 and 2 above on a
+
 medium customarily used for software interchange.
 
+
+
   If distribution of object code is made by offering access to copy
+
 from a designated place, then offering equivalent access to copy the
+
 source code from the same place satisfies the requirement to
+
 distribute the source code, even though third parties are not
+
 compelled to copy the source along with the object code.
 
+
+
   5. A program that contains no derivative of any portion of the
+
 Library, but is designed to work with the Library by being compiled or
+
 linked with it, is called a "work that uses the Library".  Such a
+
 work, in isolation, is not a derivative work of the Library, and
+
 therefore falls outside the scope of this License.
 
+
+
   However, linking a "work that uses the Library" with the Library
+
 creates an executable that is a derivative of the Library (because it
+
 contains portions of the Library), rather than a "work that uses the
+
 library".  The executable is therefore covered by this License.
+
 Section 6 states terms for distribution of such executables.
 
+
+
   When a "work that uses the Library" uses material from a header file
+
 that is part of the Library, the object code for the work may be a
+
 derivative work of the Library even though the source code is not.
+
 Whether this is true is especially significant if the work can be
+
 linked without the Library, or if the work is itself a library.  The
+
 threshold for this to be true is not precisely defined by law.
 
+
+
   If such an object file uses only numerical parameters, data
+
 structure layouts and accessors, and small macros and small inline
+
 functions (ten lines or less in length), then the use of the object
+
 file is unrestricted, regardless of whether it is legally a derivative
+
 work.  (Executables containing this object code plus portions of the
+
 Library will still fall under Section 6.)
 
+
+
   Otherwise, if the work is a derivative of the Library, you may
+
 distribute the object code for the work under the terms of Section 6.
+
 Any executables containing that work also fall under Section 6,
+
 whether or not they are linked directly with the Library itself.
 
+\f
+
   6. As an exception to the Sections above, you may also compile or
+
 link a "work that uses the Library" with the Library to produce a
+
 work containing portions of the Library, and distribute that work
+
 under terms of your choice, provided that the terms permit
+
 modification of the work for the customer's own use and reverse
+
 engineering for debugging such modifications.
 
+
+
   You must give prominent notice with each copy of the work that the
+
 Library is used in it and that the Library and its use are covered by
+
 this License.  You must supply a copy of this License.  If the work
+
 during execution displays copyright notices, you must include the
+
 copyright notice for the Library among them, as well as a reference
+
 directing the user to the copy of this License.  Also, you must do one
+
 of these things:
 
+
+
     a) Accompany the work with the complete corresponding
+
     machine-readable source code for the Library including whatever
+
     changes were used in the work (which must be distributed under
+
     Sections 1 and 2 above); and, if the work is an executable linked
+
     with the Library, with the complete machine-readable "work that
+
     uses the Library", as object code and/or source code, so that the
+
     user can modify the Library and then relink to produce a modified
+
     executable containing the modified Library.  (It is understood
+
     that the user who changes the contents of definitions files in the
+
     Library will not necessarily be able to recompile the application
+
     to use the modified definitions.)
 
+
+
     b) Accompany the work with a written offer, valid for at
+
     least three years, to give the same user the materials
+
     specified in Subsection 6a, above, for a charge no more
+
     than the cost of performing this distribution.
 
+
+
     c) If distribution of the work is made by offering access to copy
+
     from a designated place, offer equivalent access to copy the above
+
     specified materials from the same place.
 
+
+
     d) Verify that the user has already received a copy of these
+
     materials or that you have already sent this user a copy.
 
+
+
   For an executable, the required form of the "work that uses the
+
 Library" must include any data and utility programs needed for
+
 reproducing the executable from it.  However, as a special exception,
+
 the source code distributed need not include anything that is normally
+
 distributed (in either source or binary form) with the major
+
 components (compiler, kernel, and so on) of the operating system on
+
 which the executable runs, unless that component itself accompanies
+
 the executable.
 
+
+
   It may happen that this requirement contradicts the license
+
 restrictions of other proprietary libraries that do not normally
+
 accompany the operating system.  Such a contradiction means you cannot
+
 use both them and the Library together in an executable that you
+
 distribute.
 
+\f
+
   7. You may place library facilities that are a work based on the
+
 Library side-by-side in a single library together with other library
+
 facilities not covered by this License, and distribute such a combined
+
 library, provided that the separate distribution of the work based on
+
 the Library and of the other library facilities is otherwise
+
 permitted, and provided that you do these two things:
 
+
+
     a) Accompany the combined library with a copy of the same work
+
     based on the Library, uncombined with any other library
+
     facilities.  This must be distributed under the terms of the
+
     Sections above.
 
+
+
     b) Give prominent notice with the combined library of the fact
+
     that part of it is a work based on the Library, and explaining
+
     where to find the accompanying uncombined form of the same work.
 
+
+
   8. You may not copy, modify, sublicense, link with, or distribute
+
 the Library except as expressly provided under this License.  Any
+
 attempt otherwise to copy, modify, sublicense, link with, or
+
 distribute the Library is void, and will automatically terminate your
+
 rights under this License.  However, parties who have received copies,
+
 or rights, from you under this License will not have their licenses
+
 terminated so long as such parties remain in full compliance.
 
+
+
   9. You are not required to accept this License, since you have not
+
 signed it.  However, nothing else grants you permission to modify or
+
 distribute the Library or its derivative works.  These actions are
+
 prohibited by law if you do not accept this License.  Therefore, by
+
 modifying or distributing the Library (or any work based on the
+
 Library), you indicate your acceptance of this License to do so, and
+
 all its terms and conditions for copying, distributing or modifying
+
 the Library or works based on it.
 
+
+
   10. Each time you redistribute the Library (or any work based on the
+
 Library), the recipient automatically receives a license from the
+
 original licensor to copy, distribute, link with or modify the Library
+
 subject to these terms and conditions.  You may not impose any further
+
 restrictions on the recipients' exercise of the rights granted herein.
+
 You are not responsible for enforcing compliance by third parties to
+
 this License.
 
+\f
+
   11. If, as a consequence of a court judgment or allegation of patent
+
 infringement or for any other reason (not limited to patent issues),
+
 conditions are imposed on you (whether by court order, agreement or
+
 otherwise) that contradict the conditions of this License, they do not
+
 excuse you from the conditions of this License.  If you cannot
+
 distribute so as to satisfy simultaneously your obligations under this
+
 License and any other pertinent obligations, then as a consequence you
+
 may not distribute the Library at all.  For example, if a patent
+
 license would not permit royalty-free redistribution of the Library by
+
 all those who receive copies directly or indirectly through you, then
+
 the only way you could satisfy both it and this License would be to
+
 refrain entirely from distribution of the Library.
 
+
+
 If any portion of this section is held invalid or unenforceable under any
+
 particular circumstance, the balance of the section is intended to apply,
+
 and the section as a whole is intended to apply in other circumstances.
 
+
+
 It is not the purpose of this section to induce you to infringe any
+
 patents or other property right claims or to contest validity of any
+
 such claims; this section has the sole purpose of protecting the
+
 integrity of the free software distribution system which is
+
 implemented by public license practices.  Many people have made
+
 generous contributions to the wide range of software distributed
+
 through that system in reliance on consistent application of that
+
 system; it is up to the author/donor to decide if he or she is willing
+
 to distribute software through any other system and a licensee cannot
+
 impose that choice.
 
+
+
 This section is intended to make thoroughly clear what is believed to
+
 be a consequence of the rest of this License.
 
+
+
   12. If the distribution and/or use of the Library is restricted in
+
 certain countries either by patents or by copyrighted interfaces, the
+
 original copyright holder who places the Library under this License may add
+
 an explicit geographical distribution limitation excluding those countries,
+
 so that distribution is permitted only in or among countries not thus
+
 excluded.  In such case, this License incorporates the limitation as if
+
 written in the body of this License.
 
+
+
   13. The Free Software Foundation may publish revised and/or new
+
 versions of the Library General Public License from time to time.
+
 Such new versions will be similar in spirit to the present version,
+
 but may differ in detail to address new problems or concerns.
 
+
+
 Each version is given a distinguishing version number.  If the Library
+
 specifies a version number of this License which applies to it and
+
 "any later version", you have the option of following the terms and
+
 conditions either of that version or of any later version published by
+
 the Free Software Foundation.  If the Library does not specify a
+
 license version number, you may choose any version ever published by
+
 the Free Software Foundation.
 
+\f
+
   14. If you wish to incorporate parts of the Library into other free
+
 programs whose distribution conditions are incompatible with these,
+
 write to the author to ask for permission.  For software which is
+
 copyrighted by the Free Software Foundation, write to the Free
+
 Software Foundation; we sometimes make exceptions for this.  Our
+
 decision will be guided by the two goals of preserving the free status
+
 of all derivatives of our free software and of promoting the sharing
+
 and reuse of software generally.
 
+
+
                NO WARRANTY
 
+
+
   15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+
 WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+
 EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+
 OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+
 KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+
 PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+
 LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+
 THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 
+
+
   16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+
 WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+
 AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+
 FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+
 CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+
 LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+
 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+
 FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+
 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+
 DAMAGES.
 
+
+
             END OF TERMS AND CONDITIONS
 
+\f
+
      Appendix: How to Apply These Terms to Your New Libraries
 
+
+
   If you develop a new library, and you want it to be of the greatest
+
 possible use to the public, we recommend making it free software that
+
 everyone can redistribute and change.  You can do so by permitting
+
 redistribution under these terms (or, alternatively, under the terms of the
+
 ordinary General Public License).
 
+
+
   To apply these terms, attach the following notices to the library.  It is
+
 safest to attach them to the start of each source file to most effectively
+
 convey the exclusion of warranty; and each file should have at least the
+
 "copyright" line and a pointer to where the full notice is found.
 
+
+
     <one line to give the library's name and a brief idea of what it does.>
+
     Copyright (C) <year>  <name of author>
 
+
+
     This library is free software; you can redistribute it and/or
+
     modify it under the terms of the GNU Library General Public
+
     License as published by the Free Software Foundation; either
+
     version 2 of the License, or (at your option) any later version.
 
+
+
     This library is distributed in the hope that it will be useful,
+
     but WITHOUT ANY WARRANTY; without even the implied warranty of
+
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+
     Library General Public License for more details.
 
+
+
     You should have received a copy of the GNU Library General Public
+
     License along with this library; if not, write to the Free
+
     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
+
+
 Also add information on how to contact you by electronic and paper mail.
 
+
+
 You should also get your employer (if you work as a programmer) or your
+
 school, if any, to sign a "copyright disclaimer" for the library, if
+
 necessary.  Here is a sample; alter the names:
 
+
+
   Yoyodyne, Inc., hereby disclaims all copyright interest in the
+
   library `Frob' (a library for tweaking knobs) written by James Random Hacker.
 
+
+
   <signature of Ty Coon>, 1 April 1990
+
   Ty Coon, President of Vice
 
+
+
 That's all there is to it!
 
diff --git a/loadlib.c b/loadlib.c
new file mode 100644 (file)
index 0000000..1938f9f
--- /dev/null
+++ b/loadlib.c
@@ -0,0 +1,185 @@
+/*------
+ * Module:         loadlib.c
+ *
+ * Description:        This module contains routines related to
+ *         delay load import libraries.
+ *         
+ * Comments:       See "notice.txt" for copyright and license information.
+ *-------
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#ifndef    WIN32
+#include <errno.h>
+#endif /* WIN32 */
+#include "loadlib.h"
+#include <libpq-fe.h>
+
+#ifdef  WIN32
+#ifdef  _MSC_VER
+#pragma comment(lib, "Delayimp")
+#pragma comment(lib, "libpq")
+#pragma comment(lib, "ssleay32")
+// The followings works under VC++6.0 but doesn't work under VC++7.0.
+// Please add the equivalent linker options using command line etc.
+#if (_MSC_VER == 1200) && defined(DYNAMIC_LOAD) // VC6.0
+#pragma comment(linker, "/Delayload:libpq.dll")
+#pragma comment(linker, "/Delayload:ssleay32.dll")
+#pragma comment(linker, "/Delay:UNLOAD")
+#endif /* _MSC_VER */
+#endif /* _MSC_VER */
+#if defined(DYNAMIC_LOAD)
+#define    WIN_DYN_LOAD
+CSTR   libpq = "libpq";
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+#define    _MSC_DELAY_LOAD_IMPORT
+#endif /* MSC_VER */
+#endif /* DYNAMIC_LOAD */
+#endif /* WIN32 */
+
+#if defined(_MSC_DELAY_LOAD_IMPORT)
+/*
+ * Load psqlodbc path based libpq dll.
+ */
+static HMODULE LIBPQ_load_from_psqlodbc_path()
+{
+   extern  HINSTANCE   s_hModule;
+   HMODULE hmodule = NULL;
+   char    szFileName[MAX_PATH];
+
+   if (GetModuleFileName(s_hModule, szFileName, sizeof(szFileName)) > 0)
+   {
+       char drive[_MAX_DRIVE], dir[_MAX_DIR], sysdir[MAX_PATH];
+
+       _splitpath(szFileName, drive, dir, NULL, NULL);
+       GetSystemDirectory(sysdir, MAX_PATH);
+       snprintf(szFileName, sizeof(szFileName), "%s%s%s.dll", drive, dir, libpq);
+       if (strnicmp(szFileName, sysdir, strlen(sysdir)) != 0)
+       {
+           hmodule = LoadLibraryEx(szFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+           mylog("psqlodbc path based libpq loaded module=%x\n", hmodule);
+       }
+   }
+   return hmodule;
+}
+
+/*
+ * Error hook function for delay load import.
+ * Try to load psqlodbc path based libpq.
+ * Load alternative ssl library SSLEAY32 or LIBSSL32. 
+ */
+#if (_MSC_VER < 1300)
+extern PfnDliHook __pfnDliFailureHook;
+#else
+extern PfnDliHook __pfnDliFailureHook2;
+#endif /* _MSC_VER */
+
+static FARPROC WINAPI
+DliErrorHook(unsigned  dliNotify,
+       PDelayLoadInfo  pdli)
+{
+   HMODULE hmodule = NULL;
+   int i;
+   static const char * const libarray[] = {"libssl32", "ssleay32"};
+
+   mylog("DliErrorHook Notify=%d %x\n", dliNotify, pdli);
+   switch (dliNotify)
+   {
+       case dliFailLoadLib:
+           if (strnicmp(pdli->szDll, libpq, 5) == 0)
+               hmodule = LIBPQ_load_from_psqlodbc_path();
+           else
+           {
+                   mylog("getting alternative ssl library instead of %s\n", pdli->szDll);
+                   for (i = 0; i < sizeof(libarray) / sizeof(const char * const); i++)
+                   {
+                           if (hmodule = GetModuleHandle(libarray[i]), NULL != hmodule)
+                       break;
+               }
+               }
+           break;
+   }
+   return (FARPROC) hmodule;
+}
+
+/*
+ * unload delay loaded libraries.
+ *
+ * Openssl Library nmake defined
+ * ssleay32.dll is vc make, libssl32.dll is mingw make.
+ */
+#ifndef SSL_DLL
+#define SSL_DLL "SSLEAY32.dll"
+#endif /* SSL_DLL */
+
+typedef BOOL (WINAPI *UnloadFunc)(LPCSTR);
+void UnloadDelayLoadedDLLs(BOOL ssllibLoaded)
+{
+   BOOL    success;
+#if (_MSC_VER < 1300) /* VC6 DELAYLOAD IMPORT */
+   UnloadFunc  func = __FUnloadDelayLoadedDLL;
+#else
+   UnloadFunc  func = __FUnloadDelayLoadedDLL2;
+#endif
+   /* The dll names are case sensitive for the unload helper */
+   success = (*func)("LIBPQ.dll");
+   mylog("LIBPQ unload success=%d\n", success);
+   if (ssllibLoaded)
+   {
+       success = (*func)(SSL_DLL);
+       mylog("ssldll unload success=%d\n", success);
+   }
+   return;
+}
+#else
+void UnloadDelayLoadedDLLs(BOOL SSLLoaded)
+{
+   return;
+}
+#endif /* _MSC_DELAY_LOAD_IMPORT */
+
+void *CALL_PQconnectdb(const char *conninfo, BOOL *libpqLoaded)
+{
+   void *pqconn;
+   *libpqLoaded = TRUE;
+#if defined(_MSC_DELAY_LOAD_IMPORT)
+   __try {
+#if (_MSC_VER < 1300)
+       __pfnDliFailureHook = DliErrorHook;
+#else
+       __pfnDliFailureHook2 = DliErrorHook;
+#endif /* _MSC_VER */
+       pqconn = PQconnectdb(conninfo);
+   }
+   __except ((GetExceptionCode() & 0xffff) == ERROR_MOD_NOT_FOUND ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
+       *libpqLoaded = FALSE;
+   }
+#else
+   pqconn = PQconnectdb(conninfo);
+#endif /* _MSC_DELAY_LOAD_IMPORT */
+   return pqconn;
+}
+
+#if defined(WIN_DYN_LOAD)
+BOOL LIBPQ_check()
+{
+   extern  HINSTANCE   s_hModule;
+   HMODULE hmodule = NULL;
+
+   mylog("checking libpq library\n");
+   if (!(hmodule = LoadLibrary(libpq)))
+       /* Second try the driver's directory */
+       hmodule = LIBPQ_load_from_psqlodbc_path();
+   mylog("hmodule=%x\n", hmodule);
+   if (hmodule)
+       FreeLibrary(hmodule);
+   return (NULL != hmodule);
+}
+#else
+BOOL LIBPQ_check()
+{
+   return TRUE;
+}
+#endif /* WIN_DYN_LOAD */
diff --git a/loadlib.h b/loadlib.h
new file mode 100644 (file)
index 0000000..33a7662
--- /dev/null
+++ b/loadlib.h
@@ -0,0 +1,26 @@
+/* File:           loadlib.h
+ *
+ * Description:        See "loadlib.c"
+ *
+ * Comments:       See "notice.txt" for copyright and license information.
+ *
+ */
+
+#ifndef __LOADLIB_H__
+#define __LOADLIB_H__
+
+#include "psqlodbc.h"
+
+#include <stdlib.h>
+#ifdef  __cplusplus
+extern "C" {
+#endif
+BOOL   LIBPQ_check(void);
+void   *CALL_PQconnectdb(const char *conninfo, BOOL *);
+void   UnloadDelayLoadedDLLs(BOOL);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __LOADLIB_H__ */
+
diff --git a/lobj.c b/lobj.c
new file mode 100644 (file)
index 0000000..125edc3
--- /dev/null
+++ b/lobj.c
@@ -0,0 +1,186 @@
+/*--------
+ * Module:         lobj.c
+ *
+ * Description:        This module contains routines related to manipulating
+ *                 large objects.
+ *
+ * Classes:            none
+ *
+ * API functions:  none
+ *
+ * Comments:       See "notice.txt" for copyright and license information.
+ *--------
+ */
+
+#include "lobj.h"
+
+#include "connection.h"
+
+
+Oid
+odbc_lo_creat(ConnectionClass *conn, int mode)
+{
+   LO_ARG      argv[1];
+   int         retval,
+               result_len;
+
+   argv[0].isint = 1;
+   argv[0].len = 4;
+   argv[0].u.integer = mode;
+
+   if (!CC_send_function(conn, LO_CREAT, &retval, &result_len, 1, argv, 1))
+       return 0;               /* invalid oid */
+   else
+       return retval;
+}
+
+
+int
+odbc_lo_open(ConnectionClass *conn, int lobjId, int mode)
+{
+   int         fd;
+   int         result_len;
+   LO_ARG      argv[2];
+
+   argv[0].isint = 1;
+   argv[0].len = 4;
+   argv[0].u.integer = lobjId;
+
+   argv[1].isint = 1;
+   argv[1].len = 4;
+   argv[1].u.integer = mode;
+
+   if (!CC_send_function(conn, LO_OPEN, &fd, &result_len, 1, argv, 2))
+       return -1;
+
+   if (fd >= 0 && odbc_lo_lseek(conn, fd, 0L, SEEK_SET) < 0)
+       return -1;
+
+   return fd;
+}
+
+
+int
+odbc_lo_close(ConnectionClass *conn, int fd)
+{
+   LO_ARG      argv[1];
+   int         retval,
+               result_len;
+
+   argv[0].isint = 1;
+   argv[0].len = 4;
+   argv[0].u.integer = fd;
+
+   if (!CC_send_function(conn, LO_CLOSE, &retval, &result_len, 1, argv, 1))
+       return -1;
+   else
+       return retval;
+}
+
+
+int
+odbc_lo_read(ConnectionClass *conn, int fd, char *buf, int len)
+{
+   LO_ARG      argv[2];
+   int         result_len;
+
+   argv[0].isint = 1;
+   argv[0].len = 4;
+   argv[0].u.integer = fd;
+
+   argv[1].isint = 1;
+   argv[1].len = 4;
+   argv[1].u.integer = len;
+
+   if (!CC_send_function(conn, LO_READ, (int *) buf, &result_len, 0, argv, 2))
+       return -1;
+   else
+       return result_len;
+}
+
+
+int
+odbc_lo_write(ConnectionClass *conn, int fd, char *buf, int len)
+{
+   LO_ARG      argv[2];
+   int         retval,
+               result_len;
+
+   if (len <= 0)
+       return 0;
+
+   argv[0].isint = 1;
+   argv[0].len = 4;
+   argv[0].u.integer = fd;
+
+   argv[1].isint = 0;
+   argv[1].len = len;
+   argv[1].u.ptr = (char *) buf;
+
+   if (!CC_send_function(conn, LO_WRITE, &retval, &result_len, 1, argv, 2))
+       return -1;
+   else
+       return retval;
+}
+
+
+int
+odbc_lo_lseek(ConnectionClass *conn, int fd, int offset, int whence)
+{
+   LO_ARG      argv[3];
+   int         retval,
+               result_len;
+
+   argv[0].isint = 1;
+   argv[0].len = 4;
+   argv[0].u.integer = fd;
+
+   argv[1].isint = 1;
+   argv[1].len = 4;
+   argv[1].u.integer = offset;
+
+   argv[2].isint = 1;
+   argv[2].len = 4;
+   argv[2].u.integer = whence;
+
+   if (!CC_send_function(conn, LO_LSEEK, &retval, &result_len, 1, argv, 3))
+       return -1;
+   else
+       return retval;
+}
+
+
+int
+odbc_lo_tell(ConnectionClass *conn, int fd)
+{
+   LO_ARG      argv[1];
+   int         retval,
+               result_len;
+
+   argv[0].isint = 1;
+   argv[0].len = 4;
+   argv[0].u.integer = fd;
+
+   if (!CC_send_function(conn, LO_TELL, &retval, &result_len, 1, argv, 1))
+       return -1;
+   else
+       return retval;
+}
+
+
+int
+odbc_lo_unlink(ConnectionClass *conn, Oid lobjId)
+{
+   LO_ARG      argv[1];
+   int         retval,
+               result_len;
+
+   argv[0].isint = 1;
+   argv[0].len = 4;
+   argv[0].u.integer = lobjId;
+
+   if (!CC_send_function(conn, LO_UNLINK, &retval, &result_len, 1, argv, 1))
+       return -1;
+   else
+       return retval;
+}
diff --git a/lobj.h b/lobj.h
new file mode 100644 (file)
index 0000000..342a857
--- /dev/null
+++ b/lobj.h
@@ -0,0 +1,47 @@
+/* File:           lobj.h
+ *
+ * Description:        See "lobj.c"
+ *
+ * Comments:       See "notice.txt" for copyright and license information.
+ *
+ */
+
+#ifndef __LOBJ_H__
+#define __LOBJ_H__
+
+
+#include "psqlodbc.h"
+
+struct lo_arg
+{
+   int         isint;
+   int         len;
+   union
+   {
+       int         integer;
+       char       *ptr;
+   }           u;
+};
+
+#define LO_CREAT                   957
+#define LO_OPEN                        952
+#define LO_CLOSE                   953
+#define LO_READ                        954
+#define LO_WRITE                   955
+#define LO_LSEEK                   956
+#define LO_TELL                        958
+#define LO_UNLINK                  964
+
+#define INV_WRITE                  0x00020000
+#define INV_READ                   0x00040000
+
+Oid        odbc_lo_creat(ConnectionClass *conn, int mode);
+int        odbc_lo_open(ConnectionClass *conn, int lobjId, int mode);
+int        odbc_lo_close(ConnectionClass *conn, int fd);
+int        odbc_lo_read(ConnectionClass *conn, int fd, char *buf, int len);
+int        odbc_lo_write(ConnectionClass *conn, int fd, char *buf, int len);
+int        odbc_lo_lseek(ConnectionClass *conn, int fd, int offset, int len);
+int        odbc_lo_tell(ConnectionClass *conn, int fd);
+int        odbc_lo_unlink(ConnectionClass *conn, Oid lobjId);
+
+#endif
diff --git a/md5.c b/md5.c
index 3bbf0097df4baafa3401dcbdb7a427ef5194116a..d56e6136d2ee0aedf21b109b79649d821d590437 100644 (file)
--- a/md5.c
+++ b/md5.c
@@ -14,7 +14,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /home/heikki/psqlodbc-cvs-copy/psqlodbc/md5.c,v 1.10 2002/09/23 08:08:21 hinoue Exp $
+ *   $Header: /home/heikki/psqlodbc-cvs-copy/psqlodbc/md5.c,v 1.11 2006/04/08 16:30:01 dpage Exp $
  */
 
 
diff --git a/misc.c b/misc.c
index 5c8eaf805c64df1cf2a2b01976ae63a1a6100b29..6ddd95256a6df0b9e5474e9b1d7895178d27e278 100644 (file)
--- a/misc.c
+++ b/misc.c
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
-#include <ctype.h>
+#include <time.h>
 
 #ifndef WIN32
 #include <pwd.h>
 #include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 #include <unistd.h>
 #else
 #include <process.h>           /* Byron: is this where Windows keeps def.
                                 * of getpid ? */
 #endif
-
 #include "connection.h"
 #include "multibyte.h"
 
-extern GLOBAL_VALUES globals;
-void       generate_filename(const char *, const char *, char *);
-
-
-void
-generate_filename(const char *dirname, const char *prefix, char *filename)
-{
-   int         pid = 0;
-
-#ifndef WIN32
-   struct passwd *ptr = 0;
-
-   ptr = getpwuid(getuid());
-#endif
-   pid = getpid();
-   if (dirname == 0 || filename == 0)
-       return;
-
-   strcpy(filename, dirname);
-   strcat(filename, DIRSEPARATOR);
-   if (prefix != 0)
-       strcat(filename, prefix);
-#ifndef WIN32
-   strcat(filename, ptr->pw_name);
-#endif
-   sprintf(filename, "%s%u%s", filename, pid, ".log");
-   return;
-}
-
-#if defined(WIN_MULTITHREAD_SUPPORT)
-CRITICAL_SECTION   qlog_cs, mylog_cs;
-#elif defined(POSIX_MULTITHREAD_SUPPORT)
-pthread_mutex_t    qlog_cs, mylog_cs;
-#endif /* WIN_MULTITHREAD_SUPPORT */
-static int mylog_on = 0,
-           qlog_on = 0;
-
-int    get_mylog(void)
-{
-   return mylog_on;
-}
-int    get_qlog(void)
-{
-   return qlog_on;
-}
-
-void
-logs_on_off(int cnopen, int mylog_onoff, int qlog_onoff)
-{
-   static int  mylog_on_count = 0,
-               mylog_off_count = 0,
-               qlog_on_count = 0,
-               qlog_off_count = 0;
-
-   ENTER_MYLOG_CS;
-   ENTER_QLOG_CS;
-   if (mylog_onoff)
-       mylog_on_count += cnopen;
-   else
-       mylog_off_count += cnopen;
-   if (mylog_on_count > 0)
-       mylog_on = 1;
-   else if (mylog_off_count > 0)
-       mylog_on = 0;
-   else
-       mylog_on = globals.debug;
-   if (qlog_onoff)
-       qlog_on_count += cnopen;
-   else
-       qlog_off_count += cnopen;
-   if (qlog_on_count > 0)
-       qlog_on = 1;
-   else if (qlog_off_count > 0)
-       qlog_on = 0;
-   else
-       qlog_on = globals.commlog;
-   LEAVE_QLOG_CS;
-   LEAVE_MYLOG_CS;
-}
-
-#ifdef MY_LOG
-static FILE *LOGFP = NULL;
-void
-mylog(char *fmt,...)
-{
-   va_list     args;
-   char        filebuf[80];
-
-#ifndef WIN32
-   int     filedes=0;
-#endif
-
-   ENTER_MYLOG_CS;
-   if (mylog_on)
-   {
-       va_start(args, fmt);
-
-       if (!LOGFP)
-       {
-           generate_filename(MYLOGDIR, MYLOGFILE, filebuf);
-#ifdef WIN32
-           LOGFP = fopen(filebuf, PG_BINARY_A);
-#else
-           filedes = open(filebuf, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR);
-           LOGFP = fdopen(filedes, PG_BINARY_A);
-#endif
-           if (LOGFP)
-               setbuf(LOGFP, NULL);
-           else
-               mylog_on = 0;
-       }
-
-#ifdef WIN_MULTITHREAD_SUPPORT
-#ifdef WIN32
-       if (LOGFP)
-           fprintf(LOGFP, "[%d]", GetCurrentThreadId());
-#endif /* WIN32 */
-#endif /* WIN_MULTITHREAD_SUPPORT */
-#if defined(POSIX_MULTITHREAD_SUPPORT)
-       if (LOGFP)
-           fprintf(LOGFP, "[%d]", pthread_self());
-#endif /* POSIX_MULTITHREAD_SUPPORT */
-       if (LOGFP)
-           vfprintf(LOGFP, fmt, args);
-
-       va_end(args);
-   }
-   LEAVE_MYLOG_CS;
-}
-#else
-void
-MyLog(char *fmt,...)
-{
-}
-#endif
-
-
-#ifdef Q_LOG
-void
-qlog(char *fmt,...)
-{
-   va_list     args;
-   char        filebuf[80];
-   static FILE *LOGFP = NULL;
-
-#ifndef WIN32
-        int             filedes=0;
-#endif
-
-   ENTER_QLOG_CS;
-   if (qlog_on)
-   {
-       va_start(args, fmt);
-
-       if (!LOGFP)
-       {
-           generate_filename(QLOGDIR, QLOGFILE, filebuf);
-#ifdef WIN32
-           LOGFP = fopen(filebuf, PG_BINARY_A);
-#else
-           filedes = open(filebuf, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR);
-           LOGFP = fdopen(filedes, PG_BINARY_A);
-#endif
-           if (LOGFP)
-               setbuf(LOGFP, NULL);
-           else
-               qlog_on = 0;
-       }
-
-       if (LOGFP)
-           vfprintf(LOGFP, fmt, args);
-
-       va_end(args);
-   }
-   LEAVE_QLOG_CS;
-}
-#endif
-
-
 /*
  * returns STRCPY_FAIL, STRCPY_TRUNCATED, or #bytes copied
  * (not including null term)
@@ -287,21 +105,19 @@ strncpy_null(char *dst, const char *src, int len)
 /*------
  * Create a null terminated string (handling the SQL_NTS thing):
  *     1. If buf is supplied, place the string in there
- *        (at most bufsize-1 bytes) and return buf.
+ *        (assumes enough space) and return buf.
  *     2. If buf is not supplied, malloc space and return this string
- *        (buflen is ignored in this case)
  *------
  */
 char *
 make_string(const char *s, int len, char *buf, size_t bufsize)
 {
-   unsigned int    length;
+   int         length;
    char       *str;
 
    if (s && (len > 0 || (len == SQL_NTS && strlen(s) > 0)))
    {
        length = (len > 0) ? len : strlen(s);
-
        if (buf)
        {
            if (length >= bufsize)
@@ -310,7 +126,9 @@ make_string(const char *s, int len, char *buf, size_t bufsize)
            return buf;
        }
 
+inolog("malloc size=%d\n", length);
        str = malloc(length + 1);
+inolog("str=%x\n", str);
        if (!str)
            return NULL;
 
@@ -353,7 +171,7 @@ make_lstring_ifneeded(ConnectionClass *conn, const char *s, int len, BOOL ifallu
                    str = NULL;
                }
                break;
-           }
+           } 
            if (tolower(*ptr) != *ptr)
            {
                if (!str)
@@ -440,6 +258,10 @@ trim(char *s)
    return s;
 }
 
+/*
+ * my_strcat1 is a extension of my_strcat.
+ * It can have 1 more parameter than my_strcat.
+ */
 char *
 my_strcat1(char *buf, const char *fmt, const char *s1, const char *s, int len)
 {
@@ -469,20 +291,3 @@ schema_strcat1(char *buf, const char *fmt, const char *s1, const char *s, int le
    }
    return my_strcat1(buf, fmt, s1, s, len);
 }
-
-int 
-contains_token(char *data, char *token)
-{
-   int i, tlen, dlen;
-
-   dlen = strlen(data);
-   tlen = strlen(token);
-
-   for (i = 0; i < dlen-tlen+1; i++)
-   {
-       if (!strnicmp((const char *)data+i, token, tlen))
-           return 1;
-   }
-
-   return 0;
-}
diff --git a/misc.h b/misc.h
index 0dc5e02a912152483077d6e37c2b063243d95fce..67cbfff84cb3a2cb28d3f3c79ccde3196c077a72 100644 (file)
--- a/misc.h
+++ b/misc.h
@@ -13,6 +13,9 @@
 
 #include <stdio.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 /* Uncomment MY_LOG define to compile in the mylog() statements.
    Then, debug logging will occur if 'Debug' is set to 1 in the ODBCINST.INI
    portion of the registry.  You may have to manually add this key.
@@ -66,6 +69,7 @@
 #define MYLOGDIR           "c:"
 #endif /* WIN32 */
 extern void mylog(char *fmt,...);
+extern void forcelog(const char *fmt,...);
 
 #else /* MY_LOG */
 #ifndef WIN32
@@ -75,7 +79,7 @@ extern void MyLog(char *fmt,...);
 #define mylog  if (0) MyLog        /* mylog */
 #endif /* WIN32 */
 #endif /* MY_LOG */
-#define    inolog  mylog   /* for really temporary debug */
+#define    inolog  if (get_mylog() > 1) mylog /* for really temporary debug */
 
 #ifdef Q_LOG
 #define QLOGFILE           "psqlodbc_"
@@ -116,16 +120,16 @@ int   get_mylog(void);
 #endif
 
 
-void   remove_newlines(char *string);
-char   *strncpy_null(char *dst, const char *src, int len);
-char   *trim(char *string);
-char   *make_string(const char *s, int len, char *buf, size_t bufsize);
-char   *make_lstring_ifneeded(ConnectionClass *, const char *s, int len, BOOL);
-char   *my_strcat(char *buf, const char *fmt, const char *s, int len);
-char   *schema_strcat(char *buf, const char *fmt, const char *s, int len,
+void       remove_newlines(char *string);
+char      *strncpy_null(char *dst, const char *src, int len);
+char      *trim(char *string);
+char      *make_string(const char *s, int len, char *buf, size_t bufsize);
+char      *make_lstring_ifneeded(ConnectionClass *, const char *s, int len, BOOL);
+char      *my_strcat(char *buf, const char *fmt, const char *s, int len);
+char      *schema_strcat(char *buf, const char *fmt, const char *s, int len,
        const char *, int, ConnectionClass *conn);
-char   *my_strcat1(char *buf, const char *fmt, const char *s1, const char *s, int len);
-char   *schema_strcat1(char *buf, const char *fmt, const char *s1,
+char      *my_strcat1(char *buf, const char *fmt, const char *s1, const char *s, int len);
+char      *schema_strcat1(char *buf, const char *fmt, const char *s1,
                const char *s, int len,
                const char *, int, ConnectionClass *conn);
 /* #define GET_SCHEMA_NAME(nspname)    (stricmp(nspname, "public") ? nspname : "") */
@@ -137,10 +141,12 @@ char  *schema_strcat1(char *buf, const char *fmt, const char *s1,
 #define STRCPY_TRUNCATED   (-1)
 #define STRCPY_NULL            (-2)
 
-int    my_strcpy(char *dst, int dst_len, const char *src, int src_len);
-int    contains_token(char *data, char *token);
+int            my_strcpy(char *dst, int dst_len, const char *src, int src_len);
 
 /* Define a type for defining a constant string expression */
 #define CSTR static const char * const
 
+#ifdef __cplusplus
+}
 #endif
+#endif /* __MISC_H__ */
index 3871db3a3d54ee4bf2004520645c66d675374c0c..fcfc293f97adf6ac8b717377e78c7d0107435a12 100644 (file)
@@ -11,7 +11,6 @@
 #include "multibyte.h"
 #include "connection.h"
 #include "pgapifunc.h"
-#include "qresult.h"
 #include <string.h>
 #include <ctype.h>
 #include <stdio.h>
@@ -27,29 +26,28 @@ pg_CS CS_Table[] =
    { "EUC_CN", EUC_CN },
    { "EUC_KR", EUC_KR },
    { "EUC_TW", EUC_TW },
-   { "JOHAB", JOHAB },
-   { "UNICODE",    PG_UNICODE },
-   { "UTF8",   UTF8 },     /* Corresponding from Version 8.1 */
+   { "JOHAB",  JOHAB },
+   { "UTF8",   UTF8 },
    { "MULE_INTERNAL",MULE_INTERNAL },
    { "LATIN1", LATIN1 },
    { "LATIN2", LATIN2 },
    { "LATIN3", LATIN3 },
    { "LATIN4", LATIN4 },
    { "LATIN5", LATIN5 },
-   { "LATIN6", LATIN6 },
-   { "LATIN7", LATIN7 },
-   { "LATIN8", LATIN8 },
-   { "LATIN9", LATIN9 },
-   { "LATIN10", LATIN10 },
-   { "WIN1256", WIN1256 },
-   { "TCVN", TCVN },
-   { "WIN1258", WIN1258 },     /* Corresponding from Version 8.1 */
-   { "WIN874", WIN874 },
+   { "LATIN6", LATIN6 },
+   { "LATIN7", LATIN7 },
+   { "LATIN8", LATIN8 },
+   { "LATIN9", LATIN9 },
+   { "LATIN10",    LATIN10 },
+   { "WIN1256",    WIN1256 },
+   { "TCVN",   TCVN },
+   { "WIN1258",    WIN1258 },  /* since 8.1 */
+   { "WIN874", WIN874 },
    { "KOI8",   KOI8R },
    { "WIN",    WIN },
-   { "WIN1251",    WIN1251 },  /* Corresponding from Version 8.1 */
-   { "ALT",    ALT  },
-   { "WIN866", WIN866  },  /* Corresponding from Version 8.1 */
+   { "WIN1251",    WIN1251 },
+   { "ALT",    ALT },
+   { "WIN866", WIN866 },   /* since 8.1 */
    { "ISO_8859_5", ISO_8859_5 },
    { "ISO_8859_6", ISO_8859_6 },
    { "ISO_8859_7", ISO_8859_7 },
@@ -58,11 +56,12 @@ pg_CS CS_Table[] =
 
    { "SJIS",   SJIS },
    { "BIG5",   BIG5 },
-   { "GBK", GBK },
-   { "UHC", UHC },
+   { "GBK",    GBK },
+   { "UHC",    UHC },
    { "WIN1250",    WIN1250 },
    { "GB18030",    GB18030 },
-   { "OTHER", OTHER }
+   { "UNICODE",    UNICODE_PODBC },
+   { "OTHER",  OTHER }
 };
 
 #ifdef NOT_USED
@@ -113,6 +112,32 @@ pg_CS_name(int characterset_code)
    return ("OTHER");
 }
 
+static int
+pg_mb_maxlen(characterset_code)
+{
+   switch (characterset_code)
+   {
+       case UTF8:
+       case UNICODE_PODBC:
+           return 6;
+       case EUC_TW:
+           return 4;
+       case EUC_JP:
+       case GB18030:
+           return 3;
+       case SJIS:
+       case BIG5:
+       case GBK:
+       case UHC:
+       case EUC_CN:
+       case EUC_KR:
+       case JOHAB:
+           return 2;
+       default:
+           return 1;
+   }
+}
+
 int
 pg_CS_stat(int stat,unsigned int character,int characterset_code)
 {
@@ -121,6 +146,7 @@ pg_CS_stat(int stat,unsigned int character,int characterset_code)
    switch (characterset_code)
    {
        case UTF8:
+       case UNICODE_PODBC:
            {
                if (stat < 2 &&
                    character >= 0x80)
@@ -198,11 +224,11 @@ pg_CS_stat(int stat,unsigned int character,int characterset_code)
 /* EUC_JP Support */
        case EUC_JP:
            {
-               if (stat < 3 &&
+               if (stat < 3 && 
                    character == 0x8f)  /* JIS X 0212 */
                    stat = 3;
                else
-               if (stat != 2 &&
+               if (stat != 2 && 
                    (character == 0x8e ||
                    character > 0xa0))  /* Half Katakana HighByte & Kanji HighByte */
                    stat = 2;
@@ -284,7 +310,7 @@ pg_mbschr(int csc, const UCHAR *string, unsigned int character)
    int         mb_st = 0;
    const UCHAR *s, *rs = NULL;
 
-   for(s = string; *s ; s++)
+   for(s = string; *s ; s++) 
    {
        mb_st = pg_CS_stat(mb_st, (UCHAR) *s, csc);
        if (mb_st == 0 && (*s == character))
@@ -331,15 +357,15 @@ CC_lookup_cs_new(ConnectionClass *self)
    char        *encstr = NULL;
    QResultClass    *res;
 
-   res = CC_send_query(self, "select pg_client_encoding()", NULL, CLEAR_RESULT_ON_ABORT);
-   if (res)
+   res = CC_send_query(self, "select pg_client_encoding()", NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL);
+   if (QR_command_maybe_successful(res))
    {
        char    *enc = QR_get_value_backend_row(res, 0, 0);
 
        if (enc)
            encstr = strdup(enc);
-       QR_Destructor(res);
    }
+   QR_Destructor(res);
    return encstr;
 }
 static char *
@@ -367,6 +393,51 @@ CC_lookup_cs_old(ConnectionClass *self)
    return encstr;
 }
 
+/*
+ * This function works under Windows or Unicode case only.
+ * Simply returns NULL under other OSs.
+ */
+const char * get_environment_encoding(const ConnectionClass *conn, const char *oldenc)
+{
+   const char *wenc = NULL;
+
+#ifdef UNICODE_SUPPORT
+   if (conn->unicode)
+       return "UTF8";
+#endif /* UNICODE_SUPPORT */
+#ifdef WIN32
+   switch (GetACP())
+   {
+       case 932:
+           wenc = "SJIS";
+           break;
+       case 936:
+           if (!oldenc && PG_VERSION_GT(conn, 7.2))
+               wenc = "GBK";
+           break;
+       case 949:
+           if (!oldenc || (PG_VERSION_GT(conn, 7.2) && stricmp(oldenc, "EUC_KR")))  
+               wenc = "UHC";
+           break;
+       case 950:
+           wenc = "BIG5";
+           break;
+       case 1250:
+           wenc = "WIN1250";
+           break;
+       case 1252:
+           if (oldenc)
+               ;
+           else if (PG_VERSION_GE(conn, 7.2))
+               wenc = "latin9";
+           else
+               wenc = "latin1";
+           break;
+   }
+#endif /* WIN32 */
+   return wenc;
+}
+
 void
 CC_lookup_characterset(ConnectionClass *self)
 {
@@ -374,86 +445,57 @@ CC_lookup_characterset(ConnectionClass *self)
    CSTR func = "CC_lookup_characterset";
 
    mylog("%s: entering...\n", func);
-   if (PG_VERSION_LT(self, 7.2))
+   if (self->current_client_encoding)
+       encstr = strdup(self->current_client_encoding);
+   else if (PG_VERSION_LT(self, 7.2))
        encstr = CC_lookup_cs_old(self);
    else
        encstr = CC_lookup_cs_new(self);
-   if (self->client_encoding)
-       free(self->client_encoding);
-#ifndef UNICODE_SUPPORT     
-#ifdef  WIN32   
-   else     
-   {    
-       const char *wenc = NULL;     
-       switch (GetACP())    
-       {    
-           case 932:    
-               wenc = "SJIS";   
-               break;   
-           case 936:    
-               if (!encstr || PG_VERSION_GT(self, 7.2))     
-                   wenc = "GBK";    
-               break;   
-           case 949:    
-               if (!encstr || (PG_VERSION_GT(self, 7.2) && stricmp(encstr, "EUC_KR")))      
-                   wenc = "UHC";    
-               break;   
-           case 950:    
-               wenc = "BIG5";   
-               break;   
-           case 1250:   
-               wenc = "WIN1250";    
-               break;   
-           case 1251:   
-               if (PG_VERSION_GE(self, 8.1))    
-                   wenc = "WIN1251";    
-               else
-                   wenc = "WIN";    
-               break;   
-           case 1252:   
-               if (PG_VERSION_GE(self, 7.2))    
-                   wenc = "latin9";     
-               else     
-                   wenc = "latin1";     
-               break;   
-       }    
-       if (wenc && (!encstr || stricmp(encstr, wenc)))      
-       {    
-           QResultClass    *res;    
-           char            query[64];   
-           int             errnum = CC_get_errornumber(self);   
-
-           sprintf(query, "set client_encoding to '%s'", wenc);     
-           res = CC_send_query(self, query, NULL, CLEAR_RESULT_ON_ABORT);   
-           CC_set_errornumber(self, errnum);    
-           if (res)     
-           {    
-               self->client_encoding = strdup(wenc);    
-               self->ccsc = pg_CS_code(self->client_encoding);      
-               QR_Destructor(res);      
-               free(encstr);    
-               return;      
-           }    
-       }    
-   }    
-#endif /* WIN32 */      
+   if (self->original_client_encoding)
+       free(self->original_client_encoding);
+#ifndef    UNICODE_SUPPORT
+   else
+   {
+       const char *wenc = get_environment_encoding(self, encstr);
+       if (wenc && (!encstr || stricmp(encstr, wenc)))
+       {
+           QResultClass    *res;
+           char        query[64];
+           int     errnum = CC_get_errornumber(self);
+           BOOL        cmd_success;
+
+           sprintf(query, "set client_encoding to '%s'", wenc);
+           res = CC_send_query(self, query, NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL);
+           cmd_success = QR_command_maybe_successful(res);
+           QR_Destructor(res);
+           CC_set_errornumber(self, errnum);
+           if (cmd_success)
+           {
+               self->original_client_encoding = strdup(wenc);
+               self->ccsc = pg_CS_code(self->original_client_encoding);
+               free(encstr);
+               return;
+           }
+       }
+   }
 #endif /* UNICODE_SUPPORT */
    if (encstr)
    {
-       self->client_encoding = encstr;
+       self->original_client_encoding = encstr;
        self->ccsc = pg_CS_code(encstr);
-       qlog("    [ Client encoding = '%s' (code = %d) ]\n", self->client_encoding, self->ccsc);
+       qlog("    [ Client encoding = '%s' (code = %d) ]\n", self->original_client_encoding, self->ccsc);
        if (stricmp(pg_CS_name(self->ccsc), encstr))
        {
-           qlog(" Client encoding = '%s' and %s\n", self->client_encoding, pg_CS_name(self->ccsc));
-           CC_set_error(self, CONN_VALUE_OUT_OF_RANGE, "client encoding mismatch");
+           qlog(" Client encoding = '%s' and %s\n", self->original_client_encoding, pg_CS_name(self->ccsc));
+           CC_set_error(self, CONN_VALUE_OUT_OF_RANGE, "client encoding mismatch", func); 
        }
    }
    else
    {
        self->ccsc = SQL_ASCII;
-       self->client_encoding = NULL;
+       self->original_client_encoding = NULL;
    }
+   self->mb_maxbyte_per_char = pg_mb_maxlen(self->ccsc);
 }
 
 void encoded_str_constr(encoded_str *encstr, int ccsc, const char *str)
@@ -467,15 +509,15 @@ int encoded_nextchar(encoded_str *encstr)
 {
    int chr;
 
-   chr = encstr->encstr[++encstr->pos];
+   chr = encstr->encstr[++encstr->pos]; 
    encstr->ccst = pg_CS_stat(encstr->ccst, (unsigned int) chr, encstr->ccsc);
-   return chr;
+   return chr; 
 }
 int encoded_byte_check(encoded_str *encstr, int abspos)
 {
    int chr;
 
-   chr = encstr->encstr[encstr->pos = abspos];
+   chr = encstr->encstr[encstr->pos = abspos]; 
    encstr->ccst = pg_CS_stat(encstr->ccst, (unsigned int) chr, encstr->ccsc);
-   return chr;
+   return chr; 
 }
index f4143d266caa4a45510623ad1e5fef7502e0ef58..f13decf445aee89dee5f734a0f5b4b63349a1588 100644 (file)
@@ -16,7 +16,7 @@
 #define EUC_TW             4   /* EUC for Taiwan */
 #define JOHAB              5
 #define UTF8               6   /* Unicode UTF-8 */
-#define MULE_INTERNAL      7   /* Mule internal code */
+#define MULE_INTERNAL          7   /* Mule internal code */
 #define LATIN1             8   /* ISO-8859 Latin 1 */
 #define LATIN2             9   /* ISO-8859 Latin 2 */
 #define LATIN3             10  /* ISO-8859 Latin 3 */
 
 #define SJIS               28  /* Shift JIS */
 #define BIG5               29  /* Big5 */
-#define GBK                    30  /* GBK */
-#define UHC                    31  /* UHC */
+#define GBK                30  /* GBK */
+#define UHC                31  /* UHC */
 #define WIN1250                32  /* windows-1250 */
 #define GB18030                33  /* GB18030 */
-
-#define PG_UNICODE         34  /* UNICODE ( < Ver8.1) */
-                       /* Can't call it UNICODE as that's already used */
-#define TCVN               35  /* TCVN ( < Ver8.1) */
-#define ALT                36  /* ALT ( < Var8.1) */
-#define WIN                37  /* WIN ( < Ver8.1) */
-
+#define UNICODE_PODBC          34  /* same as Unicode UTF-8 */
+#define    TCVN                35  /* TCVN ( < Ver8.1) */
+#define    ALT             36  /* ALT ( < Var8.1) */
+#define    WIN             37  /* WIN ( < Ver8.1) */
 #define OTHER              -1
 
 #define MAX_CHARACTERSET_NAME  24
@@ -68,6 +65,7 @@
 /* New Type */
 
 extern void CC_lookup_characterset(ConnectionClass *self);
+extern const char *get_environment_encoding(const ConnectionClass *conn, const char *oldenc);
 
 extern int pg_CS_stat(int stat,unsigned int charcter,int characterset_code);
 extern int pg_CS_code(const UCHAR *stat_string);
diff --git a/mylog.c b/mylog.c
new file mode 100644 (file)
index 0000000..6a9a1be
--- /dev/null
+++ b/mylog.c
@@ -0,0 +1,233 @@
+/*-------
+ * Module:         mylog.c
+ *
+ * Description:        This module contains miscellaneous routines
+ *                 such as for debugging/logging and string functions.
+ *
+ * Classes:            n/a
+ *
+ * API functions:  none
+ *
+ * Comments:       See "notice.txt" for copyright and license information.
+ *-------
+ */
+
+#include "psqlodbc.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WIN32
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+#else
+#include <process.h>           /* Byron: is this where Windows keeps def.
+                                * of getpid ? */
+#endif
+
+extern GLOBAL_VALUES globals;
+void       generate_filename(const char *, const char *, char *);
+
+
+void
+generate_filename(const char *dirname, const char *prefix, char *filename)
+{
+   int         pid = 0;
+
+#ifndef WIN32
+   struct passwd *ptr = 0;
+
+   ptr = getpwuid(getuid());
+#endif
+   pid = getpid();
+   if (dirname == 0 || filename == 0)
+       return;
+
+   strcpy(filename, dirname);
+   strcat(filename, DIRSEPARATOR);
+   if (prefix != 0)
+       strcat(filename, prefix);
+#ifndef WIN32
+   strcat(filename, ptr->pw_name);
+#endif
+   sprintf(filename, "%s%u%s", filename, pid, ".log");
+   return;
+}
+
+#if defined(WIN_MULTITHREAD_SUPPORT)
+CRITICAL_SECTION   qlog_cs, mylog_cs;
+#elif defined(POSIX_MULTITHREAD_SUPPORT)
+pthread_mutex_t    qlog_cs, mylog_cs;
+#endif /* WIN_MULTITHREAD_SUPPORT */
+static int mylog_on = 0, qlog_on = 0;
+
+int    get_mylog(void)
+{
+   return mylog_on;
+}
+int    get_qlog(void)
+{
+   return qlog_on;
+}
+
+void
+logs_on_off(int cnopen, int mylog_onoff, int qlog_onoff)
+{
+   static int  mylog_on_count = 0,
+               mylog_off_count = 0,
+               qlog_on_count = 0,
+               qlog_off_count = 0;
+
+   ENTER_MYLOG_CS;
+   ENTER_QLOG_CS;
+   if (mylog_onoff)
+       mylog_on_count += cnopen;
+   else
+       mylog_off_count += cnopen;
+   if (mylog_on_count > 0)
+   {
+       if (mylog_onoff > mylog_on)
+           mylog_on = mylog_onoff;
+       else if (mylog_on < 1)
+           mylog_on = 1;
+   }
+   else if (mylog_off_count > 0)
+       mylog_on = 0;
+   else
+       mylog_on = globals.debug;
+   if (qlog_onoff)
+       qlog_on_count += cnopen;
+   else
+       qlog_off_count += cnopen;
+   if (qlog_on_count > 0)
+       qlog_on = 1;
+   else if (qlog_off_count > 0)
+       qlog_on = 0;
+   else
+       qlog_on = globals.commlog;
+   LEAVE_QLOG_CS;
+   LEAVE_MYLOG_CS;
+}
+
+#ifdef MY_LOG
+static FILE *LOGFP = NULL;
+void
+mylog(char *fmt,...)
+{
+   va_list     args;
+   char        filebuf[80];
+
+   ENTER_MYLOG_CS;
+   if (mylog_on)
+   {
+       va_start(args, fmt);
+
+       if (!LOGFP)
+       {
+           generate_filename(MYLOGDIR, MYLOGFILE, filebuf);
+           LOGFP = fopen(filebuf, PG_BINARY_A);
+           if (LOGFP)
+               setbuf(LOGFP, NULL);
+       }
+
+#ifdef WIN_MULTITHREAD_SUPPORT
+#ifdef WIN32
+       if (LOGFP)
+           fprintf(LOGFP, "[%d]", GetCurrentThreadId());
+#endif /* WIN32 */
+#endif /* WIN_MULTITHREAD_SUPPORT */
+#if defined(POSIX_MULTITHREAD_SUPPORT)
+       if (LOGFP)
+           fprintf(LOGFP, "[%d]", pthread_self());
+#endif /* POSIX_MULTITHREAD_SUPPORT */
+       if (LOGFP)
+           vfprintf(LOGFP, fmt, args);
+
+       va_end(args);
+   }
+   LEAVE_MYLOG_CS;
+}
+void
+forcelog(const char *fmt,...)
+{
+   va_list     args;
+   char        filebuf[80];
+
+   ENTER_MYLOG_CS;
+   va_start(args, fmt);
+
+   if (!LOGFP)
+   {
+       generate_filename(MYLOGDIR, MYLOGFILE, filebuf);
+       LOGFP = fopen(filebuf, PG_BINARY_A);
+       if (LOGFP)
+           setbuf(LOGFP, NULL);
+   }
+   if (!LOGFP)
+   {
+       generate_filename("C:\\podbclog", MYLOGFILE, filebuf);
+       LOGFP = fopen(filebuf, PG_BINARY_A);
+       if (LOGFP)
+           setbuf(LOGFP, NULL);
+   }
+   if (LOGFP)
+   {
+#ifdef WIN_MULTITHREAD_SUPPORT
+#ifdef WIN32
+       time_t  ntime;
+       char    ctim[128];
+
+       time(&ntime);
+       strcpy(ctim, ctime(&ntime));
+       ctim[strlen(ctim) - 1] = '\0';
+       fprintf(LOGFP, "[%d.%d(%s)]", GetCurrentProcessId(), GetCurrentThreadId(), ctim);
+#endif /* WIN32 */
+#endif /* WIN_MULTITHREAD_SUPPORT */
+#if defined(POSIX_MULTITHREAD_SUPPORT)
+       fprintf(LOGFP, "[%d]", pthread_self());
+#endif /* POSIX_MULTITHREAD_SUPPORT */
+       vfprintf(LOGFP, fmt, args);
+   }
+   va_end(args);
+   LEAVE_MYLOG_CS;
+}
+#else
+void
+MyLog(char *fmt,...)
+{
+}
+#endif
+
+
+#ifdef Q_LOG
+void
+qlog(char *fmt,...)
+{
+   va_list     args;
+   char        filebuf[80];
+   static FILE *LOGFP = NULL;
+
+   ENTER_QLOG_CS;
+   if (qlog_on)
+   {
+       va_start(args, fmt);
+
+       if (!LOGFP)
+       {
+           generate_filename(QLOGDIR, QLOGFILE, filebuf);
+           LOGFP = fopen(filebuf, PG_BINARY_A);
+           if (LOGFP)
+               setbuf(LOGFP, NULL);
+       }
+
+       if (LOGFP)
+           vfprintf(LOGFP, fmt, args);
+
+       va_end(args);
+   }
+   LEAVE_QLOG_CS;
+}
+#endif
diff --git a/odbc-drop.sql b/odbc-drop.sql
new file mode 100644 (file)
index 0000000..09f56b3
--- /dev/null
@@ -0,0 +1,36 @@
+DROP FUNCTION "char"(integer);
+DROP FUNCTION concat(text, text);
+DROP FUNCTION insert(text, integer, integer, text);
+DROP FUNCTION lcase(text);
+DROP FUNCTION left(text, integer);
+DROP FUNCTION locate(text, text);
+DROP FUNCTION locate(text, text, integer);
+DROP FUNCTION right(text, integer);
+DROP FUNCTION space(integer);
+DROP FUNCTION ucase(text);
+DROP FUNCTION ceiling(numeric);
+DROP FUNCTION log10(double precision);
+DROP FUNCTION log10(numeric);
+DROP FUNCTION power(double precision, double precision);
+DROP FUNCTION power(numeric, numeric);
+DROP FUNCTION rand();
+DROP FUNCTION rand(double precision);
+DROP FUNCTION truncate(numeric, integer);
+DROP FUNCTION curdate();
+DROP FUNCTION curtime();
+DROP FUNCTION odbc_timestamp();
+DROP FUNCTION dayname(timestamp);
+DROP FUNCTION dayofmonth(timestamp);
+DROP FUNCTION dayofweek(timestamp);
+DROP FUNCTION dayofyear(timestamp);
+DROP FUNCTION hour(timestamp);
+DROP FUNCTION minute(timestamp);
+DROP FUNCTION month(timestamp);
+DROP FUNCTION monthname(timestamp);
+DROP FUNCTION quarter(timestamp);
+DROP FUNCTION second(timestamp);
+DROP FUNCTION week(timestamp);
+DROP FUNCTION year(timestamp);
+DROP FUNCTION odbc_user();
+DROP FUNCTION odbc_current_user();
+DROP FUNCTION odbc_session_user();
diff --git a/odbc.sql b/odbc.sql
new file mode 100644 (file)
index 0000000..3af044a
--- /dev/null
+++ b/odbc.sql
@@ -0,0 +1,228 @@
+-- PostgreSQL catalog extensions for ODBC compatibility
+-- $Header: /home/heikki/psqlodbc-cvs-copy/psqlodbc/odbc.sql,v 1.9 2006/04/08 16:30:02 dpage Exp $
+
+-- ODBC functions are described here:
+-- <http://msdn.microsoft.com/library/en-us/odbc/htm/odbcscalar_functions.asp>
+
+-- Note:  If we format this file consistently we can automatically
+-- generate a corresponding "drop script".  Start "CREATE" in the first
+-- column, and keep everything up to and including the argument list on
+-- the same line.  See also the makefile rule.
+
+
+-- String Functions
+-- ++++++++++++++++
+--
+-- Built-in: ASCII, BIT_LENGTH, CHAR_LENGTH, CHARACTER_LENGTH, LTRIM,
+--           OCTET_LENGTH, POSITION, REPEAT, RTRIM, SUBSTRING
+-- Missing: DIFFERENCE, REPLACE, SOUNDEX, LENGTH (ODBC sense)
+-- Keyword problems: CHAR
+
+
+-- CHAR(code)
+CREATE OR REPLACE FUNCTION "char"(integer) RETURNS text AS '
+    SELECT chr($1);
+' LANGUAGE SQL;
+
+
+-- CONCAT(string1, string2)
+CREATE OR REPLACE FUNCTION concat(text, text) RETURNS text AS '
+    SELECT $1 || $2;
+' LANGUAGE SQL;
+
+
+-- INSERT(string1, start, len, string2)
+CREATE OR REPLACE FUNCTION insert(text, integer, integer, text) RETURNS text AS '
+    SELECT substring($1 from 1 for $2 - 1) || $4 || substring($1 from $2 + $3);
+' LANGUAGE SQL;
+
+
+-- LCASE(string)
+CREATE OR REPLACE FUNCTION lcase(text) RETURNS text AS '
+    SELECT lower($1);
+' LANGUAGE SQL;
+
+
+-- LEFT(string, count)
+CREATE OR REPLACE FUNCTION left(text, integer) RETURNS text AS '
+    SELECT substring($1 for $2);
+' LANGUAGE SQL;
+
+
+-- LOCATE(substring, string[, start])
+CREATE OR REPLACE FUNCTION locate(text, text) RETURNS integer AS '
+    SELECT position($1 in $2);
+' LANGUAGE SQL;
+CREATE OR REPLACE FUNCTION locate(text, text, integer) RETURNS integer AS '
+    SELECT position($1 in substring($2 from $3)) + $3 - 1;
+' LANGUAGE SQL;
+
+
+-- RIGHT(string, count)
+CREATE OR REPLACE FUNCTION right(text, integer) RETURNS text AS '
+    SELECT substring($1 from char_length($1) - $2 + 1);
+' LANGUAGE SQL;
+
+
+-- SPACE(count)
+CREATE OR REPLACE FUNCTION space(integer) RETURNS text AS '
+    SELECT repeat('' '', $1);
+' LANGUAGE SQL;
+
+
+-- UCASE(string)
+CREATE OR REPLACE FUNCTION ucase(text) RETURNS text AS '
+    SELECT upper($1);
+' LANGUAGE SQL;
+
+
+-- Numeric Functions
+-- +++++++++++++++++
+--
+-- Built-in: ABS, ACOS, ASIN, ATAN, ATAN2, COS, COT, DEGRESS, EXP,
+--           FLOOR, MOD, PI, RADIANS, ROUND, SIGN, SIN, SQRT, TAN
+-- Missing: LOG (ODBC sense)
+
+
+-- CEILING(num)
+CREATE OR REPLACE FUNCTION ceiling(numeric) RETURNS numeric AS '
+    SELECT ceil($1);
+' LANGUAGE SQL;
+
+
+-- LOG10(num)
+CREATE OR REPLACE FUNCTION log10(double precision) RETURNS double precision AS '
+    SELECT log($1);
+' LANGUAGE SQL;
+CREATE OR REPLACE FUNCTION log10(numeric) RETURNS numeric AS '
+    SELECT log($1);
+' LANGUAGE SQL;
+
+
+-- POWER(num, num)
+CREATE OR REPLACE FUNCTION power(double precision, double precision)
+  RETURNS double precision AS '
+    SELECT pow($1, $2);
+' LANGUAGE SQL;
+CREATE OR REPLACE FUNCTION power(numeric, numeric)
+  RETURNS numeric AS '
+    SELECT pow($1, $2);
+' LANGUAGE SQL;
+
+
+-- RAND([seed])
+CREATE OR REPLACE FUNCTION rand() RETURNS double precision AS '
+    SELECT random();
+' LANGUAGE SQL;
+CREATE OR REPLACE FUNCTION rand(double precision) RETURNS double precision AS '
+    SELECT setseed($1);
+    SELECT random();
+' LANGUAGE SQL;
+
+
+-- TRUNCATE(num, places)
+CREATE OR REPLACE FUNCTION truncate(numeric, integer) RETURNS numeric AS '
+    SELECT trunc($1, $2);
+' LANGUAGE SQL;
+
+
+-- Time, Date, and Interval Functions
+-- ++++++++++++++++++++++++++++++++++
+--
+-- Built-in: CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, EXTRACT, NOW
+-- Missing: none
+
+
+CREATE OR REPLACE FUNCTION curdate() RETURNS date AS '
+    SELECT current_date;
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION curtime() RETURNS time with time zone AS '
+    SELECT current_time;
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION odbc_timestamp() RETURNS timestamp with time zone AS '
+    SELECT current_timestamp;
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION dayname(timestamp) RETURNS text AS '
+    SELECT to_char($1,''Day'');
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION dayofmonth(timestamp) RETURNS integer AS '
+    SELECT CAST(EXTRACT(day FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION dayofweek(timestamp) RETURNS integer AS '
+    SELECT CAST(EXTRACT(dow FROM $1) AS integer) + 1;
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION dayofyear(timestamp) RETURNS integer AS '
+    SELECT CAST(EXTRACT(doy FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION hour(timestamp) RETURNS integer AS '
+    SELECT CAST(EXTRACT(hour FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION minute(timestamp) RETURNS integer AS '
+    SELECT CAST(EXTRACT(minute FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION month(timestamp) RETURNS integer AS '
+    SELECT CAST(EXTRACT(month FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION monthname(timestamp) RETURNS text AS '
+    SELECT to_char($1, ''Month'');
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION quarter(timestamp) RETURNS integer AS '
+    SELECT CAST(EXTRACT(quarter FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION second(timestamp) RETURNS integer AS '
+    SELECT CAST(EXTRACT(second FROM $1) AS integer);
+' LANGUAGE SQL;
+
+/*
+-- The first argument is an integer constant denoting the units
+-- of the second argument. Until we know the actual values, we
+-- cannot implement these. - thomas 2000-04-11
+xCREATE OR REPLACE FUNCTION timestampadd(integer, integer, timestamp)
+  RETURNS timestamp AS '
+    SELECT CAST(($3 + ($2 * $1)) AS timestamp);
+' LANGUAGE SQL;
+
+xCREATE OR REPLACE FUNCTION timestampdiff(integer, integer, timestamp)
+  RETURNS timestamp AS '
+    SELECT CAST(($3 + ($2 * $1)) AS timestamp);
+' LANGUAGE SQL;
+*/
+
+CREATE OR REPLACE FUNCTION week(timestamp) RETURNS integer AS '
+    SELECT CAST(EXTRACT(week FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION year(timestamp) RETURNS integer AS '
+    SELECT CAST(EXTRACT(year FROM $1) AS integer);
+' LANGUAGE SQL;
+
+
+-- System Functions
+-- ++++++++++++++++
+--
+-- Built-in: USER
+-- Missing: DATABASE, IFNULL
+
+CREATE OR REPLACE FUNCTION odbc_user() RETURNS text AS '
+    SELECT CAST(current_user AS TEXT);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION odbc_current_user() RETURNS text AS '
+    SELECT CAST(current_user AS TEXT);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION odbc_session_user() RETURNS text AS '
+    SELECT CAST(session_user AS TEXT);
+' LANGUAGE SQL;
index b64b9c2f19106b8057ec5673a3c031cb932ccbfe..866608aee273fdb06d2710f59703190797befa15 100644 (file)
--- a/odbcapi.c
+++ b/odbcapi.c
@@ -36,6 +36,7 @@
 #include "statement.h"
 #include "qresult.h"
 
+#if (ODBCVER < 0x0300)
 RETCODE        SQL_API
 SQLAllocConnect(HENV EnvironmentHandle,
                HDBC FAR * ConnectionHandle)
@@ -74,12 +75,13 @@ SQLAllocStmt(HDBC ConnectionHandle,
    LEAVE_CONN_CS(conn);
    return ret;
 }
+#endif /* ODBCVER */
 
 RETCODE        SQL_API
 SQLBindCol(HSTMT StatementHandle,
           SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType,
-          PTR TargetValue, SQLINTEGER BufferLength,
-          SQLINTEGER *StrLen_or_Ind)
+          PTR TargetValue, SQLLEN BufferLength,
+          SQLLEN *StrLen_or_Ind)
 {
    RETCODE ret;
    StatementClass *stmt = (StatementClass *) StatementHandle;
@@ -87,8 +89,10 @@ SQLBindCol(HSTMT StatementHandle,
    mylog("[SQLBindCol]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_BindCol(StatementHandle, ColumnNumber,
                   TargetType, TargetValue, BufferLength, StrLen_or_Ind);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -96,9 +100,14 @@ SQLBindCol(HSTMT StatementHandle,
 RETCODE        SQL_API
 SQLCancel(HSTMT StatementHandle)
 {
+   RETCODE ret;
+   StatementClass  *stmt = (StatementClass *) StatementHandle;
+
    mylog("[SQLCancel]");
-   SC_clear_error((StatementClass *) StatementHandle);
-   return PGAPI_Cancel(StatementHandle);
+   /* Not that neither ENTER_STMT_CS nor StartRollbackState is called */
+   /* SC_clear_error((StatementClass *) StatementHandle); maybe this neither */
+   ret = PGAPI_Cancel(StatementHandle);
+   return DiscardStatementSvp(stmt, ret, FALSE);
 }
 
 RETCODE        SQL_API
@@ -113,18 +122,23 @@ SQLColumns(HSTMT StatementHandle,
    StatementClass *stmt = (StatementClass *) StatementHandle;
    SQLCHAR *ctName = CatalogName, *scName = SchemaName,
        *tbName = TableName, *clName = ColumnName;
-   UWORD   flag = PODBC_SEARCH_PUBLIC_SCHEMA;
+   UWORD   flag    = PODBC_SEARCH_PUBLIC_SCHEMA;
 
    mylog("[%s]", func);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+   if (stmt->options.metadata_id)
+       flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
    if (SC_opencheck(stmt, func))
        ret = SQL_ERROR;
    else
        ret = PGAPI_Columns(StatementHandle, ctName, NameLength1,
                scName, NameLength2, tbName, NameLength3,
-               clName, NameLength4, flag);
-   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+               clName, NameLength4, flag, 0, 0);
+   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) 
    {
        BOOL    ifallupper = TRUE, reexec = FALSE;
        char *newCt = NULL, *newSc = NULL, *newTb = NULL, *newCl = NULL;
@@ -132,22 +146,22 @@ SQLColumns(HSTMT StatementHandle,
 
        if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
            ifallupper = FALSE;
-       if ((newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper)))
+       if (newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper))
        {
            ctName = newCt;
            reexec = TRUE;
        }
-       if ((newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper)))
+       if (newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper))
        {
            scName = newSc;
            reexec = TRUE;
-       }
-       if ((newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper)))
+       }   
+       if (newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper))
        {
            tbName = newTb;
            reexec = TRUE;
        }
-       if ((newCl = make_lstring_ifneeded(conn, ColumnName, NameLength4, ifallupper)))
+       if (newCl = make_lstring_ifneeded(conn, ColumnName, NameLength4, ifallupper))
        {
            clName = newCl;
            reexec = TRUE;
@@ -156,7 +170,7 @@ SQLColumns(HSTMT StatementHandle,
        {
            ret = PGAPI_Columns(StatementHandle, ctName, NameLength1,
                scName, NameLength2, tbName, NameLength3,
-               clName, NameLength4, flag);
+               clName, NameLength4, flag, 0, 0);
            if (newCt)
                free(newCt);
            if (newSc)
@@ -167,6 +181,7 @@ SQLColumns(HSTMT StatementHandle,
                free(newCl);
        }
    }
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -193,12 +208,12 @@ SQLConnect(HDBC ConnectionHandle,
 RETCODE        SQL_API
 SQLDriverConnect(HDBC hdbc,
                 HWND hwnd,
-                UCHAR FAR * szConnStrIn,
-                SWORD cbConnStrIn,
-                UCHAR FAR * szConnStrOut,
-                SWORD cbConnStrOutMax,
-                SWORD FAR * pcbConnStrOut,
-                UWORD fDriverCompletion)
+                SQLCHAR FAR * szConnStrIn,
+                SQLSMALLINT cbConnStrIn,
+                SQLCHAR FAR * szConnStrOut,
+                SQLSMALLINT cbConnStrOutMax,
+                SQLSMALLINT FAR * pcbConnStrOut,
+                SQLUSMALLINT fDriverCompletion)
 {
    RETCODE ret;
    ConnectionClass *conn = (ConnectionClass *) hdbc;
@@ -253,7 +268,7 @@ RETCODE     SQL_API
 SQLDescribeCol(HSTMT StatementHandle,
               SQLUSMALLINT ColumnNumber, SQLCHAR *ColumnName,
               SQLSMALLINT BufferLength, SQLSMALLINT *NameLength,
-              SQLSMALLINT *DataType, SQLUINTEGER *ColumnSize,
+              SQLSMALLINT *DataType, SQLULEN *ColumnSize,
               SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable)
 {
    RETCODE ret;
@@ -262,9 +277,11 @@ SQLDescribeCol(HSTMT StatementHandle,
    mylog("[SQLDescribeCol]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_DescribeCol(StatementHandle, ColumnNumber,
                             ColumnName, BufferLength, NameLength,
                          DataType, ColumnSize, DecimalDigits, Nullable);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -283,6 +300,28 @@ SQLDisconnect(HDBC ConnectionHandle)
    return ret;
 }
 
+#if (ODBCVER < 0x0300)
+RETCODE        SQL_API
+SQLError(HENV EnvironmentHandle,
+        HDBC ConnectionHandle, HSTMT StatementHandle,
+        SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+        SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+        SQLSMALLINT *TextLength)
+{
+   RETCODE ret;
+
+   mylog("[SQLError]");
+   if (NULL != EnvironmentHandle)
+       ENTER_ENV_CS((EnvironmentClass *) EnvironmentHandle);
+   ret = PGAPI_Error(EnvironmentHandle, ConnectionHandle, StatementHandle,
+          Sqlstate, NativeError, MessageText, BufferLength,
+       TextLength);
+   if (NULL != EnvironmentHandle)
+       LEAVE_ENV_CS((EnvironmentClass *) EnvironmentHandle);
+   return ret;
+}
+#endif /* ODBCVER */
+
 RETCODE        SQL_API
 SQLExecDirect(HSTMT StatementHandle,
              SQLCHAR *StatementText, SQLINTEGER TextLength)
@@ -290,14 +329,21 @@ SQLExecDirect(HSTMT StatementHandle,
    CSTR func = "SQLExecDirect";
    RETCODE ret;
    StatementClass *stmt = (StatementClass *) StatementHandle;
+   UWORD   flag = 0;
 
    mylog("[%s]", func);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   if (PG_VERSION_GE(SC_get_conn(stmt), 7.4))
+       flag |= PODBC_WITH_HOLD;
    if (SC_opencheck(stmt, func))
        ret = SQL_ERROR;
    else
-       ret = PGAPI_ExecDirect(StatementHandle, StatementText, TextLength, 0);
+   {
+       StartRollbackState(stmt);
+       ret = PGAPI_ExecDirect(StatementHandle, StatementText, TextLength, flag);
+       ret = DiscardStatementSvp(stmt, ret, FALSE);
+   }
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -308,14 +354,21 @@ SQLExecute(HSTMT StatementHandle)
    CSTR func = "SQLExecute";
    RETCODE ret;
    StatementClass *stmt = (StatementClass *) StatementHandle;
+   UWORD   flag = 0;
 
    mylog("[%s]", func);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   if (PG_VERSION_GE(SC_get_conn(stmt), 7.4))
+       flag |= PODBC_WITH_HOLD;
    if (SC_opencheck(stmt, func))
        ret = SQL_ERROR;
    else
-       ret = PGAPI_Execute(StatementHandle, 0);
+   {
+       StartRollbackState(stmt);
+       ret = PGAPI_Execute(StatementHandle, flag);
+       ret = DiscardStatementSvp(stmt, ret, FALSE);
+   }
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -329,6 +382,8 @@ SQLFetch(HSTMT StatementHandle)
 
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
    if (SC_get_conn(stmt)->driver_version >= 0x0300)
    {
        IRDFields   *irdopts = SC_get_IRDF(stmt);
@@ -342,14 +397,38 @@ SQLFetch(HSTMT StatementHandle)
        stmt->transition_status = 6;
    }
    else
+#endif
    {
        mylog("[%s]", func);
        ret = PGAPI_Fetch(StatementHandle);
    }
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
 
+#if (ODBCVER < 0x0300) 
+RETCODE        SQL_API
+SQLFreeConnect(HDBC ConnectionHandle)
+{
+   RETCODE ret;
+
+   mylog("[SQLFreeConnect]");
+   ret = PGAPI_FreeConnect(ConnectionHandle);
+   return ret;
+}
+
+RETCODE        SQL_API
+SQLFreeEnv(HENV EnvironmentHandle)
+{
+   RETCODE ret;
+
+   mylog("[SQLFreeEnv]");
+   ret = PGAPI_FreeEnv(EnvironmentHandle);
+   return ret;
+}
+#endif /* ODBCVER */ 
+
 RETCODE        SQL_API
 SQLFreeStmt(HSTMT StatementHandle,
            SQLUSMALLINT Option)
@@ -361,6 +440,23 @@ SQLFreeStmt(HSTMT StatementHandle,
    return ret;
 }
 
+#if (ODBCVER < 0x0300)
+RETCODE        SQL_API
+SQLGetConnectOption(HDBC ConnectionHandle,
+                   SQLUSMALLINT Option, PTR Value)
+{
+   RETCODE ret;
+   ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
+
+   mylog("[SQLGetConnectOption]");
+   ENTER_CONN_CS(conn);
+   CC_clear_error(conn);
+   ret = PGAPI_GetConnectOption(ConnectionHandle, Option, Value);
+   LEAVE_CONN_CS(conn);
+   return ret;
+}
+#endif /* ODBCVER */
+
 RETCODE        SQL_API
 SQLGetCursorName(HSTMT StatementHandle,
                 SQLCHAR *CursorName, SQLSMALLINT BufferLength,
@@ -372,8 +468,10 @@ SQLGetCursorName(HSTMT StatementHandle,
    mylog("[SQLGetCursorName]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_GetCursorName(StatementHandle, CursorName, BufferLength,
                               NameLength);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -381,8 +479,8 @@ SQLGetCursorName(HSTMT StatementHandle,
 RETCODE        SQL_API
 SQLGetData(HSTMT StatementHandle,
           SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType,
-          PTR TargetValue, SQLINTEGER BufferLength,
-          SQLINTEGER *StrLen_or_Ind)
+          PTR TargetValue, SQLLEN BufferLength,
+          SQLLEN *StrLen_or_Ind)
 {
    RETCODE ret;
    StatementClass *stmt = (StatementClass *) StatementHandle;
@@ -390,8 +488,10 @@ SQLGetData(HSTMT StatementHandle,
    mylog("[SQLGetData]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_GetData(StatementHandle, ColumnNumber, TargetType,
                         TargetValue, BufferLength, StrLen_or_Ind);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -406,10 +506,11 @@ SQLGetFunctions(HDBC ConnectionHandle,
    mylog("[SQLGetFunctions]");
    ENTER_CONN_CS(conn);
    CC_clear_error(conn);
-
+#if (ODBCVER >= 0x0300)
    if (FunctionId == SQL_API_ODBC3_ALL_FUNCTIONS)
        ret = PGAPI_GetFunctions30(ConnectionHandle, FunctionId, Supported);
    else
+#endif
    {
        ret = PGAPI_GetFunctions(ConnectionHandle, FunctionId, Supported);
    }
@@ -421,30 +522,58 @@ SQLGetInfo(HDBC ConnectionHandle,
           SQLUSMALLINT InfoType, PTR InfoValue,
           SQLSMALLINT BufferLength, SQLSMALLINT *StringLength)
 {
+   CSTR    func = "SQLGetInfo";
    RETCODE     ret;
    ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
 
    ENTER_CONN_CS(conn);
    CC_clear_error(conn);
-
+#if (ODBCVER >= 0x0300)
    mylog("[SQLGetInfo(30)]");
    if ((ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
-                            BufferLength, StringLength)) == SQL_ERROR)
+               BufferLength, StringLength)) == SQL_ERROR)
    {
-       if (((ConnectionClass *) ConnectionHandle)->driver_version >= 0x0300)
+       if (conn->driver_version >= 0x0300)
        {
            CC_clear_error(conn);
            ret = PGAPI_GetInfo30(ConnectionHandle, InfoType, InfoValue,
                                   BufferLength, StringLength);
+           goto cleanup;
        }
    }
    if (SQL_ERROR == ret)
-       CC_log_error("SQLGetInfo30", "", conn);
-
+       CC_log_error("SQLGetInfo(30)", "", conn);
+#else
+   mylog("[%s]", func);
+   if (ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
+           BufferLength, StringLength), SQL_ERROR == ret)
+       CC_log_error(func, "", conn);
+#endif
+cleanup:
    LEAVE_CONN_CS(conn);
    return ret;
 }
 
+#if (ODBCVER < 0x0300)
+RETCODE        SQL_API
+SQLGetStmtOption(HSTMT StatementHandle,
+                SQLUSMALLINT Option, PTR Value)
+{
+   CSTR    func = "SQLGetStmtOption";
+   RETCODE ret;
+   StatementClass *stmt = (StatementClass *) StatementHandle;
+
+   mylog("[%s]", func);
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+   ret = PGAPI_GetStmtOption(StatementHandle, Option, Value);
+   ret = DiscardRollbackState(stmt, ret, FALSE);
+   LEAVE_STMT_CS(stmt);
+   return ret;
+}
+#endif /* ODBCVER */
+
 RETCODE        SQL_API
 SQLGetTypeInfo(HSTMT StatementHandle,
               SQLSMALLINT DataType)
@@ -459,7 +588,11 @@ SQLGetTypeInfo(HSTMT StatementHandle,
    if (SC_opencheck(stmt, func))
        ret = SQL_ERROR;
    else
+   {
+       StartRollbackState(stmt);
        ret = PGAPI_GetTypeInfo(StatementHandle, DataType);
+       ret = DiscardStatementSvp(stmt, ret, FALSE);
+   }
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -474,7 +607,9 @@ SQLNumResultCols(HSTMT StatementHandle,
    mylog("[SQLNumResultCols]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_NumResultCols(StatementHandle, ColumnCount);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -490,6 +625,7 @@ SQLParamData(HSTMT StatementHandle,
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
    ret = PGAPI_ParamData(StatementHandle, Value);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -504,14 +640,16 @@ SQLPrepare(HSTMT StatementHandle,
    mylog("[SQLPrepare]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_Prepare(StatementHandle, StatementText, TextLength);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
 
 RETCODE        SQL_API
 SQLPutData(HSTMT StatementHandle,
-          PTR Data, SQLINTEGER StrLen_or_Ind)
+          PTR Data, SQLLEN StrLen_or_Ind)
 {
    RETCODE ret;
    StatementClass *stmt = (StatementClass *) StatementHandle;
@@ -520,13 +658,14 @@ SQLPutData(HSTMT StatementHandle,
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
    ret = PGAPI_PutData(StatementHandle, Data, StrLen_or_Ind);
+   ret = DiscardStatementSvp(stmt, ret, TRUE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
 
 RETCODE        SQL_API
 SQLRowCount(HSTMT StatementHandle,
-           SQLINTEGER *RowCount)
+           SQLLEN *RowCount)
 {
    RETCODE ret;
    StatementClass *stmt = (StatementClass *) StatementHandle;
@@ -534,11 +673,30 @@ SQLRowCount(HSTMT StatementHandle,
    mylog("[SQLRowCount]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_RowCount(StatementHandle, RowCount);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
 
+#if (ODBCVER < 0x0300)
+RETCODE        SQL_API
+SQLSetConnectOption(HDBC ConnectionHandle,
+                   SQLUSMALLINT Option, SQLULEN Value)
+{
+   RETCODE ret;
+   ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
+
+   mylog("[SQLSetConnectionOption]");
+   ENTER_CONN_CS(conn);
+   CC_clear_error(conn);
+   ret = PGAPI_SetConnectOption(ConnectionHandle, Option, Value);
+   LEAVE_CONN_CS(conn);
+   return ret;
+}
+#endif /* ODBCVER */
+
 RETCODE        SQL_API
 SQLSetCursorName(HSTMT StatementHandle,
                 SQLCHAR *CursorName, SQLSMALLINT NameLength)
@@ -549,7 +707,9 @@ SQLSetCursorName(HSTMT StatementHandle,
    mylog("[SQLSetCursorName]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_SetCursorName(StatementHandle, CursorName, NameLength);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -557,9 +717,9 @@ SQLSetCursorName(HSTMT StatementHandle,
 RETCODE        SQL_API
 SQLSetParam(HSTMT StatementHandle,
            SQLUSMALLINT ParameterNumber, SQLSMALLINT ValueType,
-           SQLSMALLINT ParameterType, SQLUINTEGER LengthPrecision,
+           SQLSMALLINT ParameterType, SQLULEN LengthPrecision,
            SQLSMALLINT ParameterScale, PTR ParameterValue,
-           SQLINTEGER *StrLen_or_Ind)
+           SQLLEN *StrLen_or_Ind)
 {
    mylog("[SQLSetParam]");
    SC_clear_error((StatementClass *) StatementHandle);
@@ -572,6 +732,25 @@ SQLSetParam(HSTMT StatementHandle,
    return SQL_ERROR;
 }
 
+#if (ODBCVER < 0x0300)
+RETCODE        SQL_API
+SQLSetStmtOption(HSTMT StatementHandle,
+                SQLUSMALLINT Option, SQLULEN Value)
+{
+   RETCODE ret;
+   StatementClass *stmt = (StatementClass *) StatementHandle;
+
+   mylog("[SQLSetStmtOption]");
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+   ret = PGAPI_SetStmtOption(StatementHandle, Option, Value);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
+   LEAVE_STMT_CS(stmt);
+   return ret;
+}
+#endif /* ODBCVER */
+
 RETCODE        SQL_API
 SQLSpecialColumns(HSTMT StatementHandle,
                  SQLUSMALLINT IdentifierType, SQLCHAR *CatalogName,
@@ -588,13 +767,14 @@ SQLSpecialColumns(HSTMT StatementHandle,
    mylog("[%s]", func);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    if (SC_opencheck(stmt, func))
        ret = SQL_ERROR;
    else
        ret = PGAPI_SpecialColumns(StatementHandle, IdentifierType, ctName,
            NameLength1, scName, NameLength2, tbName, NameLength3,
                            Scope, Nullable);
-   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) 
    {
        BOOL    ifallupper = TRUE, reexec = FALSE;
        char *newCt =NULL, *newSc = NULL, *newTb = NULL;
@@ -602,17 +782,17 @@ SQLSpecialColumns(HSTMT StatementHandle,
 
        if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
            ifallupper = FALSE;
-       if ((newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper)))
+       if (newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper))
        {
            ctName = newCt;
            reexec = TRUE;
        }
-       if ((newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper)))
+       if (newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper))
        {
            scName = newSc;
            reexec = TRUE;
        }
-       if ((newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper)))
+       if (newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper))
        {
            tbName = newTb;
            reexec = TRUE;
@@ -630,6 +810,7 @@ SQLSpecialColumns(HSTMT StatementHandle,
                free(newTb);
        }
    }
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -649,13 +830,14 @@ SQLStatistics(HSTMT StatementHandle,
    mylog("[%s]", func);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    if (SC_opencheck(stmt, func))
        ret = SQL_ERROR;
    else
        ret = PGAPI_Statistics(StatementHandle, ctName, NameLength1,
                 scName, NameLength2, tbName, NameLength3,
                 Unique, Reserved);
-   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) 
    {
        BOOL    ifallupper = TRUE, reexec = FALSE;
        char *newCt =NULL, *newSc = NULL, *newTb = NULL;
@@ -663,17 +845,17 @@ SQLStatistics(HSTMT StatementHandle,
 
        if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
            ifallupper = FALSE;
-       if ((newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper)))
+       if (newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper))
        {
            ctName = newCt;
            reexec = TRUE;
        }
-       if ((newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper)))
+       if (newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper))
        {
            scName = newSc;
            reexec = TRUE;
        }
-       if ((newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper)))
+       if (newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper))
        {
            tbName = newTb;
            reexec = TRUE;
@@ -689,8 +871,9 @@ SQLStatistics(HSTMT StatementHandle,
                free(newSc);
            if (newTb)
                free(newTb);
-       }
+       }   
    }
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -710,13 +893,14 @@ SQLTables(HSTMT StatementHandle,
    mylog("[%s]", func);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    if (SC_opencheck(stmt, func))
        ret = SQL_ERROR;
    else
        ret = PGAPI_Tables(StatementHandle, ctName, NameLength1,
                scName, NameLength2, tbName, NameLength3,
                        TableType, NameLength4);
-   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) 
    {
        BOOL    ifallupper = TRUE, reexec = FALSE;
        char *newCt =NULL, *newSc = NULL, *newTb = NULL;
@@ -724,17 +908,17 @@ SQLTables(HSTMT StatementHandle,
 
        if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
            ifallupper = FALSE;
-       if ((newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper)))
+       if (newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper))
        {
            ctName = newCt;
            reexec = TRUE;
        }
-       if ((newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper)))
+       if (newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper))
        {
            scName = newSc;
            reexec = TRUE;
        }
-       if ((newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper)))
+       if (newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper))
        {
            tbName = newTb;
            reexec = TRUE;
@@ -752,9 +936,55 @@ SQLTables(HSTMT StatementHandle,
                free(newTb);
        }
    }
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
+   LEAVE_STMT_CS(stmt);
+   return ret;
+}
+
+#if (ODBCVER < 0x0300)
+RETCODE        SQL_API
+SQLTransact(HENV EnvironmentHandle,
+           HDBC ConnectionHandle, SQLUSMALLINT CompletionType)
+{
+   RETCODE ret;
+
+   mylog("[SQLTransact]");
+   if (NULL != EnvironmentHandle)
+       ENTER_ENV_CS((EnvironmentClass *) EnvironmentHandle);
+   else
+       ENTER_CONN_CS((ConnectionClass *) ConnectionHandle);
+   ret = PGAPI_Transact(EnvironmentHandle, ConnectionHandle, CompletionType);
+   if (NULL != EnvironmentHandle)
+       LEAVE_ENV_CS((EnvironmentClass *) EnvironmentHandle);
+   else
+       LEAVE_CONN_CS((ConnectionClass *) ConnectionHandle);
+   return ret;
+}
+
+RETCODE        SQL_API
+SQLColAttributes(
+                HSTMT hstmt,
+                SQLUSMALLINT icol,
+                SQLUSMALLINT fDescType,
+                PTR rgbDesc,
+                SQLSMALLINT cbDescMax,
+                SQLSMALLINT *pcbDesc,
+                SQLLEN *pfDesc)
+{
+   RETCODE ret;
+   StatementClass *stmt = (StatementClass *) hstmt;
+
+   mylog("[SQLColAttributes]");
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+   ret = PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc,
+                              cbDescMax, pcbDesc, pfDesc);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
+#endif /* ODBCVER */
 
 RETCODE        SQL_API
 SQLColumnPrivileges(
@@ -773,17 +1003,23 @@ SQLColumnPrivileges(
    StatementClass *stmt = (StatementClass *) hstmt;
    SQLCHAR *ctName = szCatalogName, *scName = szSchemaName,
        *tbName = szTableName, *clName = szColumnName;
+   UWORD   flag = 0;
 
    mylog("[%s]", func);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+   if (stmt->options.metadata_id)
+       flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
    if (SC_opencheck(stmt, func))
        ret = SQL_ERROR;
    else
        ret = PGAPI_ColumnPrivileges(hstmt, ctName, cbCatalogName,
                scName, cbSchemaName, tbName, cbTableName,
-                       clName, cbColumnName);
-   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+                       clName, cbColumnName, flag);
+   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) 
    {
        BOOL    ifallupper = TRUE, reexec = FALSE;
        char *newCt = NULL, *newSc = NULL, *newTb = NULL, *newCl = NULL;
@@ -791,22 +1027,22 @@ SQLColumnPrivileges(
 
        if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
            ifallupper = FALSE;
-       if ((newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper)))
+       if (newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper))
        {
            ctName = newCt;
            reexec = TRUE;
        }
-       if ((newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper)))
+       if (newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper))
        {
            scName = newSc;
            reexec = TRUE;
        }
-       if ((newTb = make_lstring_ifneeded(conn, szTableName, cbTableName, ifallupper)))
+       if (newTb = make_lstring_ifneeded(conn, szTableName, cbTableName, ifallupper))
        {
            tbName = newTb;
            reexec = TRUE;
        }
-       if ((newCl = make_lstring_ifneeded(conn, szColumnName, cbColumnName, ifallupper)))
+       if (newCl = make_lstring_ifneeded(conn, szColumnName, cbColumnName, ifallupper))
        {
            clName = newCl;
            reexec = TRUE;
@@ -815,7 +1051,7 @@ SQLColumnPrivileges(
        {
            ret = PGAPI_ColumnPrivileges(hstmt, ctName, cbCatalogName,
                scName, cbSchemaName, tbName, cbTableName,
-                       clName, cbColumnName);
+                       clName, cbColumnName, flag);
            if (newCt)
                free(newCt);
            if (newSc)
@@ -826,6 +1062,7 @@ SQLColumnPrivileges(
                free(newCl);
        }
    }
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -835,7 +1072,7 @@ SQLDescribeParam(
                 HSTMT hstmt,
                 SQLUSMALLINT ipar,
                 SQLSMALLINT *pfSqlType,
-                SQLUINTEGER *pcbParamDef,
+                SQLULEN *pcbParamDef,
                 SQLSMALLINT *pibScale,
                 SQLSMALLINT *pfNullable)
 {
@@ -845,8 +1082,10 @@ SQLDescribeParam(
    mylog("[SQLDescribeParam]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_DescribeParam(hstmt, ipar, pfSqlType, pcbParamDef,
                               pibScale, pfNullable);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -855,8 +1094,8 @@ RETCODE        SQL_API
 SQLExtendedFetch(
                 HSTMT hstmt,
                 SQLUSMALLINT fFetchType,
-                SQLINTEGER irow,
-                SQLUINTEGER *pcrow,
+                SQLLEN irow,
+                SQLULEN *pcrow,
                 SQLUSMALLINT *rgfRowStatus)
 {
    RETCODE ret;
@@ -865,8 +1104,10 @@ SQLExtendedFetch(
    mylog("[SQLExtendedFetch]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_ExtendedFetch(hstmt, fFetchType, irow, pcrow, rgfRowStatus, 0, SC_get_ARDF(stmt)->size_of_rowset_odbc2);
    stmt->transition_status = 7;
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -897,6 +1138,7 @@ SQLForeignKeys(
    mylog("[%s]", func);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    if (SC_opencheck(stmt, func))
        ret = SQL_ERROR;
    else
@@ -904,7 +1146,7 @@ SQLForeignKeys(
            pkscName, cbPkSchemaName, pktbName, cbPkTableName,
            fkctName, cbFkCatalogName, fkscName, cbFkSchemaName,
            fktbName, cbFkTableName);
-   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) 
    {
        BOOL    ifallupper = TRUE, reexec = FALSE;
        char *newPkct = NULL, *newPksc = NULL, *newPktb = NULL,
@@ -913,32 +1155,32 @@ SQLForeignKeys(
 
        if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
            ifallupper = FALSE;
-       if ((newPkct = make_lstring_ifneeded(conn, szPkCatalogName, cbPkCatalogName, ifallupper)))
+       if (newPkct = make_lstring_ifneeded(conn, szPkCatalogName, cbPkCatalogName, ifallupper))
        {
            pkctName = newPkct;
            reexec = TRUE;
        }
-       if ((newPksc = make_lstring_ifneeded(conn, szPkSchemaName, cbPkSchemaName, ifallupper)))
+       if (newPksc = make_lstring_ifneeded(conn, szPkSchemaName, cbPkSchemaName, ifallupper))
        {
            pkscName = newPksc;
            reexec = TRUE;
        }
-       if ((newPktb = make_lstring_ifneeded(conn, szPkTableName, cbPkTableName, ifallupper)))
+       if (newPktb = make_lstring_ifneeded(conn, szPkTableName, cbPkTableName, ifallupper))
        {
            pktbName = newPktb;
            reexec = TRUE;
        }
-       if ((newFkct = make_lstring_ifneeded(conn, szFkCatalogName, cbFkCatalogName, ifallupper)))
+       if (newFkct = make_lstring_ifneeded(conn, szFkCatalogName, cbFkCatalogName, ifallupper))
        {
            fkctName = newFkct;
            reexec = TRUE;
        }
-       if ((newFksc = make_lstring_ifneeded(conn, szFkSchemaName, cbFkSchemaName, ifallupper)))
+       if (newFksc = make_lstring_ifneeded(conn, szFkSchemaName, cbFkSchemaName, ifallupper))
        {
            fkscName = newFksc;
            reexec = TRUE;
        }
-       if ((newFktb = make_lstring_ifneeded(conn, szFkTableName, cbFkTableName, ifallupper)))
+       if (newFktb = make_lstring_ifneeded(conn, szFkTableName, cbFkTableName, ifallupper))
        {
            fktbName = newFktb;
            reexec = TRUE;
@@ -963,6 +1205,7 @@ SQLForeignKeys(
                free(newFktb);
        }
    }
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -976,7 +1219,9 @@ SQLMoreResults(HSTMT hstmt)
    mylog("[SQLMoreResults]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_MoreResults(hstmt);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -1013,7 +1258,9 @@ SQLNumParams(
    mylog("[SQLNumParams]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_NumParams(hstmt, pcpar);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -1021,8 +1268,8 @@ SQLNumParams(
 RETCODE        SQL_API
 SQLParamOptions(
                HSTMT hstmt,
-               SQLUINTEGER crow,
-               SQLUINTEGER *pirow)
+               SQLULEN crow,
+               SQLULEN *pirow)
 {
    RETCODE ret;
    StatementClass *stmt = (StatementClass *) hstmt;
@@ -1030,7 +1277,9 @@ SQLParamOptions(
    mylog("[SQLParamOptions]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_ParamOptions(hstmt, crow, pirow);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -1054,12 +1303,13 @@ SQLPrimaryKeys(
    mylog("[%s]", func);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    if (SC_opencheck(stmt, func))
        ret = SQL_ERROR;
    else
        ret = PGAPI_PrimaryKeys(hstmt, ctName, cbCatalogName,
            scName, cbSchemaName, tbName, cbTableName);
-   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) 
    {
        BOOL    ifallupper = TRUE, reexec = FALSE;
        char *newCt = NULL, *newSc = NULL, *newTb = NULL;
@@ -1067,17 +1317,17 @@ SQLPrimaryKeys(
 
        if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
            ifallupper = FALSE;
-       if ((newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper)))
+       if (newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper))
        {
            ctName = newCt;
            reexec = TRUE;
        }
-       if ((newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper)))
+       if (newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper))
        {
            scName = newSc;
            reexec = TRUE;
        }
-       if ((newTb = make_lstring_ifneeded(conn, szTableName, cbTableName, ifallupper)))
+       if (newTb = make_lstring_ifneeded(conn, szTableName, cbTableName, ifallupper))
        {
            tbName = newTb;
            reexec = TRUE;
@@ -1094,6 +1344,7 @@ SQLPrimaryKeys(
                free(newTb);
        }
    }
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -1115,17 +1366,23 @@ SQLProcedureColumns(
    StatementClass *stmt = (StatementClass *) hstmt;
    SQLCHAR *ctName = szCatalogName, *scName = szSchemaName,
        *prName = szProcName, *clName = szColumnName;
+   UWORD   flag = 0;
 
    mylog("[%s]", func);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+   if (stmt->options.metadata_id)
+       flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
    if (SC_opencheck(stmt, func))
        ret = SQL_ERROR;
    else
        ret = PGAPI_ProcedureColumns(hstmt, ctName, cbCatalogName,
                scName, cbSchemaName, prName, cbProcName,
-                   clName, cbColumnName);
-   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+                   clName, cbColumnName, flag);
+   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) 
    {
        BOOL    ifallupper = TRUE, reexec = FALSE;
        char *newCt = NULL, *newSc = NULL, *newPr = NULL, *newCl = NULL;
@@ -1133,22 +1390,22 @@ SQLProcedureColumns(
 
        if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
            ifallupper = FALSE;
-       if ((newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper)))
+       if (newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper))
        {
            ctName = newCt;
            reexec = TRUE;
        }
-       if ((newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper)))
+       if (newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper))
        {
            scName = newSc;
            reexec = TRUE;
        }
-       if ((newPr = make_lstring_ifneeded(conn, szProcName, cbProcName, ifallupper)))
+       if (newPr = make_lstring_ifneeded(conn, szProcName, cbProcName, ifallupper))
        {
            prName = newPr;
            reexec = TRUE;
        }
-       if ((newCl = make_lstring_ifneeded(conn, szColumnName, cbColumnName, ifallupper)))
+       if (newCl = make_lstring_ifneeded(conn, szColumnName, cbColumnName, ifallupper))
        {
            clName = newCl;
            reexec = TRUE;
@@ -1157,7 +1414,7 @@ SQLProcedureColumns(
        {
            ret = PGAPI_ProcedureColumns(hstmt, ctName, cbCatalogName,
                scName, cbSchemaName, prName, cbProcName,
-                   clName, cbColumnName);
+                   clName, cbColumnName, flag);
            if (newCt)
                free(newCt);
            if (newSc)
@@ -1168,6 +1425,7 @@ SQLProcedureColumns(
                free(newCl);
        }
    }
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -1191,12 +1449,13 @@ SQLProcedures(
    mylog("[%s]", func);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    if (SC_opencheck(stmt, func))
        ret = SQL_ERROR;
    else
        ret = PGAPI_Procedures(hstmt, ctName, cbCatalogName,
                     scName, cbSchemaName, prName, cbProcName);
-   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) 
    {
        BOOL    ifallupper = TRUE, reexec = FALSE;
        char *newCt = NULL, *newSc = NULL, *newPr = NULL;
@@ -1204,17 +1463,17 @@ SQLProcedures(
 
        if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
            ifallupper = FALSE;
-       if ((newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper)))
+       if (newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper))
        {
            ctName = newCt;
            reexec = TRUE;
        }
-       if ((newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper)))
+       if (newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper))
        {
            scName = newSc;
            reexec = TRUE;
        }
-       if ((newPr = make_lstring_ifneeded(conn, szProcName, cbProcName, ifallupper)))
+       if (newPr = make_lstring_ifneeded(conn, szProcName, cbProcName, ifallupper))
        {
            prName = newPr;
            reexec = TRUE;
@@ -1231,6 +1490,7 @@ SQLProcedures(
                free(newPr);
        }
    }
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -1238,7 +1498,7 @@ SQLProcedures(
 RETCODE        SQL_API
 SQLSetPos(
          HSTMT hstmt,
-         SQLUSMALLINT irow,
+         SQLSETPOSIROW irow,
          SQLUSMALLINT fOption,
          SQLUSMALLINT fLock)
 {
@@ -1248,7 +1508,9 @@ SQLSetPos(
    mylog("[SQLSetPos]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_SetPos(hstmt, irow, fOption, fLock);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -1268,16 +1530,22 @@ SQLTablePrivileges(
    StatementClass *stmt = (StatementClass *) hstmt;
    SQLCHAR *ctName = szCatalogName, *scName = szSchemaName,
        *tbName = szTableName;
+   UWORD   flag = 0;
 
    mylog("[%s]", func);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+   if (stmt->options.metadata_id)
+       flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
    if (SC_opencheck(stmt, func))
        ret = SQL_ERROR;
    else
        ret = PGAPI_TablePrivileges(hstmt, ctName, cbCatalogName,
-           scName, cbSchemaName, tbName, cbTableName, 0);
-   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+           scName, cbSchemaName, tbName, cbTableName, flag);
+   if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) 
    {
        BOOL    ifallupper = TRUE, reexec = FALSE;
        char *newCt = NULL, *newSc = NULL, *newTb = NULL;
@@ -1285,17 +1553,17 @@ SQLTablePrivileges(
 
        if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
            ifallupper = FALSE;
-       if ((newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper)))
+       if (newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper))
        {
            ctName = newCt;
            reexec = TRUE;
        }
-       if ((newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper)))
+       if (newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper))
        {
            scName = newSc;
            reexec = TRUE;
        }
-       if ((newTb = make_lstring_ifneeded(conn, szTableName, cbTableName, ifallupper)))
+       if (newTb = make_lstring_ifneeded(conn, szTableName, cbTableName, ifallupper))
        {
            tbName = newTb;
            reexec = TRUE;
@@ -1312,6 +1580,7 @@ SQLTablePrivileges(
                free(newTb);
        }
    }
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -1323,11 +1592,11 @@ SQLBindParameter(
                 SQLSMALLINT fParamType,
                 SQLSMALLINT fCType,
                 SQLSMALLINT fSqlType,
-                SQLUINTEGER cbColDef,
+                SQLULEN cbColDef,
                 SQLSMALLINT ibScale,
                 PTR rgbValue,
-                SQLINTEGER cbValueMax,
-                SQLINTEGER *pcbValue)
+                SQLLEN cbValueMax,
+                SQLLEN *pcbValue)
 {
    RETCODE ret;
    StatementClass *stmt = (StatementClass *) hstmt;
@@ -1335,9 +1604,11 @@ SQLBindParameter(
    mylog("[SQLBindParameter]");
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_BindParameter(hstmt, ipar, fParamType, fCType,
                       fSqlType, cbColDef, ibScale, rgbValue, cbValueMax,
                               pcbValue);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
diff --git a/odbcapi25w.c b/odbcapi25w.c
new file mode 100644 (file)
index 0000000..e0ff398
--- /dev/null
@@ -0,0 +1,81 @@
+/*-------
+ * Module:         odbcapi25w.c
+ *
+ * Description:        This module contains UNICODE routines
+ *
+ * Classes:            n/a
+ *
+ * API functions:  SQLColAttributesW, SQLErrorW, SQLGetConnectOptionW,
+           SQLSetConnectOptionW
+ *-------
+ */
+
+#include "psqlodbc.h"
+#include <stdio.h>
+#include <string.h>
+
+#include "pgapifunc.h"
+#include "connection.h"
+#include "statement.h"
+
+RETCODE  SQL_API SQLErrorW(HENV EnvironmentHandle,
+           HDBC ConnectionHandle, HSTMT StatementHandle,
+           SQLWCHAR *Sqlstate, SQLINTEGER *NativeError,
+           SQLWCHAR *MessageText, SQLSMALLINT BufferLength,
+           SQLSMALLINT *TextLength)
+{
+   RETCODE ret;
+   SWORD   tlen, buflen;
+   char    *qst = NULL, *mtxt = NULL;
+
+   mylog("[SQLErrorW]");
+   if (Sqlstate)
+       qst = malloc(8);
+   buflen = 0;
+   if (MessageText && BufferLength > 0)
+   {
+       buflen = BufferLength * 3 + 1;
+       mtxt = malloc(buflen);
+   }
+   ret = PGAPI_Error(EnvironmentHandle, ConnectionHandle, StatementHandle,
+               qst, NativeError, mtxt, buflen, &tlen);
+   if (qst)
+       utf8_to_ucs2(qst, strlen(qst), Sqlstate, 5);
+   if (TextLength)
+       *TextLength = utf8_to_ucs2(mtxt, tlen, MessageText, BufferLength);
+   free(qst);
+   if (mtxt)
+       free(mtxt);
+   return ret;
+}
+
+RETCODE  SQL_API SQLGetConnectOptionW(HDBC ConnectionHandle,
+           SQLUSMALLINT Option, PTR Value)
+{
+   mylog("[SQLGetConnectOptionW]");
+   CC_set_in_unicode_driver((ConnectionClass *) ConnectionHandle);
+   return PGAPI_GetConnectOption(ConnectionHandle, Option, Value);
+} 
+
+RETCODE  SQL_API SQLSetConnectOptionW(HDBC ConnectionHandle,
+           SQLUSMALLINT Option, SQLUINTEGER Value)
+{
+   mylog("[SQLSetConnectionOptionW]");
+if (!ConnectionHandle) return SQL_ERROR;
+   ((ConnectionClass *) ConnectionHandle)->unicode = 1;
+   return PGAPI_SetConnectOption(ConnectionHandle, Option, Value);
+}
+
+RETCODE SQL_API SQLColAttributesW(
+    HSTMT           hstmt,
+    SQLUSMALLINT       icol,
+    SQLUSMALLINT       fDescType,
+    PTR         rgbDesc,
+    SQLSMALLINT        cbDescMax,
+    SQLSMALLINT      *pcbDesc,
+    SQLINTEGER           *pfDesc)
+{
+   mylog("[SQLColAttributesW]");
+   return PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc,
+       cbDescMax, pcbDesc, pfDesc);
+}
index dd7810e5442af6fcbbe17516b38cf69fa43d175b..3e148caea9cba53e3e1b2153ef2d22719da583a5 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "psqlodbc.h"
 
+#if (ODBCVER >= 0x0300)
 #include <stdio.h>
 #include <string.h>
 
@@ -33,10 +34,11 @@ RETCODE     SQL_API
 SQLAllocHandle(SQLSMALLINT HandleType,
               SQLHANDLE InputHandle, SQLHANDLE * OutputHandle)
 {
+   CSTR    func = "SQLAllocHandle";
    RETCODE     ret;
    ConnectionClass *conn;
 
-   mylog("[[SQLAllocHandle]]");
+   mylog("[[%s]]", func);
    switch (HandleType)
    {
        case SQL_HANDLE_ENV:
@@ -57,7 +59,7 @@ SQLAllocHandle(SQLSMALLINT HandleType,
            ENTER_CONN_CS(conn);
            ret = PGAPI_AllocDesc(InputHandle, OutputHandle);
            LEAVE_CONN_CS(conn);
-           mylog("Descriptor OutputHandle=%x\n", *OutputHandle);
+inolog("OutputHandle=%x\n", *OutputHandle);
            break;
        default:
            ret = SQL_ERROR;
@@ -70,18 +72,22 @@ SQLAllocHandle(SQLSMALLINT HandleType,
 RETCODE        SQL_API
 SQLBindParam(HSTMT StatementHandle,
             SQLUSMALLINT ParameterNumber, SQLSMALLINT ValueType,
-            SQLSMALLINT ParameterType, SQLUINTEGER LengthPrecision,
+            SQLSMALLINT ParameterType, SQLULEN LengthPrecision,
             SQLSMALLINT ParameterScale, PTR ParameterValue,
-            SQLINTEGER *StrLen_or_Ind)
+            SQLLEN *StrLen_or_Ind)
 {
+   CSTR    func = "SQLBindParam";
    RETCODE         ret;
+   StatementClass  *stmt = (StatementClass *) StatementHandle;
    int         BufferLength = 512;     /* Is it OK ? */
 
-   mylog("[[SQLBindParam]]");
-   ENTER_STMT_CS((StatementClass *) StatementHandle);
-   SC_clear_error((StatementClass *) StatementHandle);
+   mylog("[[%s]]", func);
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_BindParameter(StatementHandle, ParameterNumber, SQL_PARAM_INPUT, ValueType, ParameterType, LengthPrecision, ParameterScale, ParameterValue, BufferLength, StrLen_or_Ind);
-   LEAVE_STMT_CS((StatementClass *) StatementHandle);
+   ret = DiscardStatementSvp(stmt,ret, FALSE);
+   LEAVE_STMT_CS(stmt);
    return ret;
 }
 
@@ -89,32 +95,48 @@ SQLBindParam(HSTMT StatementHandle,
 RETCODE        SQL_API
 SQLCloseCursor(HSTMT StatementHandle)
 {
+   CSTR    func = "SQLCloseCursor";
+   StatementClass  *stmt = (StatementClass *) StatementHandle;
    RETCODE ret;
 
-   mylog("[[SQLCloseCursor]]");
-   ENTER_STMT_CS((StatementClass *) StatementHandle);
-   SC_clear_error((StatementClass *) StatementHandle);
+   mylog("[[%s]]", func);
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_FreeStmt(StatementHandle, SQL_CLOSE);
-   LEAVE_STMT_CS((StatementClass *) StatementHandle);
+   ret = DiscardStatementSvp(stmt,ret, FALSE);
+   LEAVE_STMT_CS(stmt);
    return ret;
 }
 
 /* SQLColAttributes -> SQLColAttribute */
-RETCODE        SQL_API
-SQLColAttribute(HSTMT StatementHandle,
-               SQLUSMALLINT ColumnNumber, SQLUSMALLINT FieldIdentifier,
-               PTR CharacterAttribute, SQLSMALLINT BufferLength,
-               SQLSMALLINT *StringLength, PTR NumericAttribute)
+SQLRETURN  SQL_API
+SQLColAttribute(SQLHSTMT StatementHandle,
+           SQLUSMALLINT ColumnNumber,
+           SQLUSMALLINT FieldIdentifier,
+           SQLPOINTER CharacterAttribute,
+           SQLSMALLINT BufferLength,
+           SQLSMALLINT *StringLength,
+#if defined(WITH_UNIXODBC) || defined(WIN32)
+           SQLPOINTER NumericAttribute
+#else
+           SQLLEN *NumericAttribute
+#endif
+           )
 {
+   CSTR    func = "SQLColAttribute";
    RETCODE ret;
+   StatementClass  *stmt = (StatementClass *) StatementHandle;
 
-   mylog("[[SQLColAttribute]]");
-   ENTER_STMT_CS((StatementClass *) StatementHandle);
-   SC_clear_error((StatementClass *) StatementHandle);
+   mylog("[[%s]]", func);
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_ColAttributes(StatementHandle, ColumnNumber,
                       FieldIdentifier, CharacterAttribute, BufferLength,
                               StringLength, NumericAttribute);
-   LEAVE_STMT_CS((StatementClass *) StatementHandle);
+   ret = DiscardStatementSvp(stmt,ret, FALSE);
+   LEAVE_STMT_CS(stmt);
    return ret;
 }
 
@@ -123,10 +145,10 @@ RETCODE       SQL_API
 SQLCopyDesc(SQLHDESC SourceDescHandle,
            SQLHDESC TargetDescHandle)
 {
+   CSTR    func = "SQLCopyDesc";
    RETCODE ret;
 
-   mylog("[[SQLCopyDesc]]\n");
-   DC_clear_error((DescriptorClass *) TargetDescHandle);
+   mylog("[[%s]]\n", func);
    ret = PGAPI_CopyDesc(SourceDescHandle, TargetDescHandle);
    return ret;
 }
@@ -136,9 +158,10 @@ RETCODE        SQL_API
 SQLEndTran(SQLSMALLINT HandleType, SQLHANDLE Handle,
           SQLSMALLINT CompletionType)
 {
+   CSTR    func = "SQLEndTran";
    RETCODE ret;
 
-   mylog("[[SQLEndTran]]");
+   mylog("[[%s]]", func);
    switch (HandleType)
    {
        case SQL_HANDLE_ENV:
@@ -162,7 +185,7 @@ SQLEndTran(SQLSMALLINT HandleType, SQLHANDLE Handle,
 /* SQLExtendedFetch -> SQLFetchScroll */
 RETCODE        SQL_API
 SQLFetchScroll(HSTMT StatementHandle,
-              SQLSMALLINT FetchOrientation, SQLINTEGER FetchOffset)
+              SQLSMALLINT FetchOrientation, SQLLEN FetchOffset)
 {
    CSTR func = "SQLFetchScroll";
    StatementClass *stmt = (StatementClass *) StatementHandle;
@@ -174,6 +197,7 @@ SQLFetchScroll(HSTMT StatementHandle,
    mylog("[[%s]] %d,%d\n", func, FetchOrientation, FetchOffset);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    if (FetchOrientation == SQL_FETCH_BOOKMARK)
    {
        if (stmt->options.bookmark_ptr)
@@ -184,8 +208,7 @@ mylog("bookmark=%u FetchOffset = %d\n", FetchOffset, bkmarkoff);
        }
        else
        {
-           SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Bookmark isn't specifed yet");
-           SC_log_error(func, "", stmt);
+           SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Bookmark isn't specifed yet", func);
            ret = SQL_ERROR;
        }
    }
@@ -197,6 +220,7 @@ mylog("bookmark=%u FetchOffset = %d\n", FetchOffset, bkmarkoff);
                pcRow, rowStatusArray, bkmarkoff, opts->size_of_rowset);
        stmt->transition_status = 6;
    }
+   ret = DiscardStatementSvp(stmt,ret, FALSE);
    LEAVE_STMT_CS(stmt);
    if (ret != SQL_SUCCESS)
        mylog("%s return = %d\n", func, ret);
@@ -207,8 +231,9 @@ mylog("bookmark=%u FetchOffset = %d\n", FetchOffset, bkmarkoff);
 RETCODE        SQL_API
 SQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle)
 {
+   CSTR    func = "SQLFreeHandle";
    RETCODE     ret;
-   mylog("[[SQLFreeHandle]]");
+   mylog("[[%s]]", func);
    switch (HandleType)
    {
        case SQL_HANDLE_ENV:
@@ -240,24 +265,22 @@ SQLGetDescField(SQLHDESC DescriptorHandle,
    RETCODE ret;
 
    mylog("[[SQLGetDescField]]\n");
-   DC_clear_error((DescriptorClass *) DescriptorHandle);
    ret = PGAPI_GetDescField(DescriptorHandle, RecNumber, FieldIdentifier,
            Value, BufferLength, StringLength);
    return ret;
 }
 
-/* TODO - Implement this!! */
+/* new function */
 RETCODE        SQL_API
 SQLGetDescRec(SQLHDESC DescriptorHandle,
              SQLSMALLINT RecNumber, SQLCHAR *Name,
              SQLSMALLINT BufferLength, SQLSMALLINT *StringLength,
              SQLSMALLINT *Type, SQLSMALLINT *SubType,
-             SQLINTEGER *Length, SQLSMALLINT *Precision,
+             SQLLEN *Length, SQLSMALLINT *Precision,
              SQLSMALLINT *Scale, SQLSMALLINT *Nullable)
 {
    mylog("[[SQLGetDescRec]]\n");
    mylog("Error not implemented\n");
-   DC_clear_error((DescriptorClass *) DescriptorHandle);
    return SQL_ERROR;
 }
 
@@ -350,13 +373,16 @@ SQLGetStmtAttr(HSTMT StatementHandle,
 {
    RETCODE ret;
    CSTR func = "SQLGetStmtAttr";
+   StatementClass  *stmt = (StatementClass *) StatementHandle;
 
    mylog("[[%s]] Handle=%u %d\n", func, StatementHandle, Attribute);
-   ENTER_STMT_CS((StatementClass *) StatementHandle);
-   SC_clear_error((StatementClass *) StatementHandle);
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_GetStmtAttr(StatementHandle, Attribute, Value,
            BufferLength, StringLength);
-   LEAVE_STMT_CS((StatementClass *) StatementHandle);
+   ret = DiscardStatementSvp(stmt,ret, FALSE);
+   LEAVE_STMT_CS(stmt);
    return ret;
 }
 
@@ -386,25 +412,25 @@ SQLSetDescField(SQLHDESC DescriptorHandle,
 {
    RETCODE     ret;
 
-   mylog("[[SQLSetDescField]] h=%u rec=%d field=%d val=%x\n", DescriptorHandle, RecNumber, FieldIdentifier, Value);
-   DC_clear_error((DescriptorClass *) DescriptorHandle);
+   mylog("[[SQLSetDescField]] h=%x rec=%d field=%d val=%x\n", DescriptorHandle, RecNumber, FieldIdentifier, Value);
    ret = PGAPI_SetDescField(DescriptorHandle, RecNumber, FieldIdentifier,
                Value, BufferLength);
    return ret;
 }
 
-/* TODO - Implement this! */
+/* new fucntion */
 RETCODE        SQL_API
 SQLSetDescRec(SQLHDESC DescriptorHandle,
              SQLSMALLINT RecNumber, SQLSMALLINT Type,
-             SQLSMALLINT SubType, SQLINTEGER Length,
+             SQLSMALLINT SubType, SQLLEN Length,
              SQLSMALLINT Precision, SQLSMALLINT Scale,
-             PTR Data, SQLINTEGER *StringLength,
-             SQLINTEGER *Indicator)
+             PTR Data, SQLLEN *StringLength,
+             SQLLEN *Indicator)
 {
+   CSTR func = "SQLSetDescRec";
+
    mylog("[[SQLSetDescRec]]\n");
    mylog("Error not implemented\n");
-   DC_clear_error((DescriptorClass *) DescriptorHandle);
    return SQL_ERROR;
 }
 
@@ -422,21 +448,20 @@ SQLSetEnvAttr(HENV EnvironmentHandle,
    switch (Attribute)
    {
        case SQL_ATTR_CONNECTION_POOLING:
-           if (Value == (PTR) SQL_CP_OFF)
+           switch ((SQLUINTEGER) Value)
            {
-               EN_unset_pooling(env);
-               ret = SQL_SUCCESS;
-           }
+               case SQL_CP_OFF:
+                   EN_unset_pooling(env);
+                   ret = SQL_SUCCESS;
+                   break;
 #if defined(WIN_MULTITHREAD_SUPPORT) || defined(POSIX_MULTITHREAD_SUPPORT)
-           else if (Value == (PTR) SQL_CP_ONE_PER_DRIVER)
-           {
-               EN_set_pooling(env);
-               ret = SQL_SUCCESS;
-           }
+               case SQL_CP_ONE_PER_DRIVER:
+                   EN_set_pooling(env);
+                   ret = SQL_SUCCESS;
+                   break;
 #endif /* WIN_MULTITHREAD_SUPPORT */
-           else
-           {
-               ret = SQL_SUCCESS_WITH_INFO;
+               default:
+                   ret = SQL_SUCCESS_WITH_INFO;
            }
            break;
        case SQL_ATTR_CP_MATCH:
@@ -444,18 +469,18 @@ SQLSetEnvAttr(HENV EnvironmentHandle,
            ret = SQL_SUCCESS;
            break;
        case SQL_ATTR_ODBC_VERSION:
-           if (Value == (PTR) SQL_OV_ODBC2)
+           if ((SQLUINTEGER) Value == SQL_OV_ODBC2)
                EN_set_odbc2(env);
            else
                EN_set_odbc3(env);
            ret = SQL_SUCCESS;
            break;
        case SQL_ATTR_OUTPUT_NTS:
-           if (Value == (PTR) SQL_TRUE)
+           if ((SQLUINTEGER) Value == SQL_TRUE)
                ret = SQL_SUCCESS;
            else
                ret = SQL_SUCCESS_WITH_INFO;
-
+   
            break;
        default:
            env->errornumber = CONN_INVALID_ARGUMENT_NO;
@@ -480,10 +505,12 @@ SQLSetStmtAttr(HSTMT StatementHandle,
    StatementClass *stmt = (StatementClass *) StatementHandle;
    RETCODE ret;
 
-   mylog("[[%s]] Handle=%u %d,%u\n", func, StatementHandle, Attribute, Value);
+   mylog("[[%s]] Handle=%x %d,%u\n", func, StatementHandle, Attribute, Value);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_SetStmtAttr(StatementHandle, Attribute, Value, StringLength);
+   ret = DiscardStatementSvp(stmt,ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
 }
@@ -493,11 +520,12 @@ SQLSetStmtAttr(HSTMT StatementHandle,
            |= (1 << ((uwAPI) & 0x000F)) \
                )
 RETCODE        SQL_API
-PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
+PGAPI_GetFunctions30(HDBC hdbc, SQLUSMALLINT fFunction, SQLUSMALLINT FAR * pfExists)
 {
    ConnectionClass *conn = (ConnectionClass *) hdbc;
    ConnInfo    *ci = &(conn->connInfo);
 
+inolog("lie=%d\n", ci->drivers.lie);
    CC_clear_error(conn);
    if (fFunction != SQL_API_ODBC3_ALL_FUNCTIONS)
        return SQL_ERROR;
@@ -512,7 +540,7 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
     * i);
     */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLBINDCOL);        /* 4 */
-   SQL_FUNC_ESET(pfExists, SQL_API_SQLCANCEL); /* 5 */
+   SQL_FUNC_ESET(pfExists, SQL_API_SQLCANCEL);     /* 5 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLATTRIBUTE);   /* 6 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLCONNECT);        /* 7 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLDESCRIBECOL);    /* 8 */
@@ -551,14 +579,14 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
    /* SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSTMTOPTION); 51 deprecated */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLSPECIALCOLUMNS); /* 52 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLSTATISTICS);     /* 53 */
-   SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLES); /* 54 */
-   if (ci->drivers.lie)
-       SQL_FUNC_ESET(pfExists, SQL_API_SQLBROWSECONNECT); /* 55 not implmented yet */
+   SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLES);     /* 54 */
    if (ci->drivers.lie)
-       SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLUMNPRIVILEGES); /* 56 not implemented yet */
+       SQL_FUNC_ESET(pfExists, SQL_API_SQLBROWSECONNECT);  /* 55 */
+   /* if (PG_VERSION_GE(conn, 7.4) || ci->drivers.lie)
+       SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLUMNPRIVILEGES); */ /* 56 */ 
    SQL_FUNC_ESET(pfExists, SQL_API_SQLDATASOURCES);    /* 57 */
-   if (ci->drivers.lie)
-       SQL_FUNC_ESET(pfExists, SQL_API_SQLDESCRIBEPARAM); /* 58 not properly implemented */
+   if ((PROTOCOL_74(ci)  && ci->use_server_side_prepare) || ci->drivers.lie)
+       SQL_FUNC_ESET(pfExists, SQL_API_SQLDESCRIBEPARAM); /* 58 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLEXTENDEDFETCH); /* 59 deprecated ? */
 
    /*
@@ -571,11 +599,11 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
    SQL_FUNC_ESET(pfExists, SQL_API_SQLNUMPARAMS);      /* 63 */
    /* SQL_FUNC_ESET(pfExists, SQL_API_SQLPARAMOPTIONS); 64 deprecated */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLPRIMARYKEYS);    /* 65 */
-   SQL_FUNC_ESET(pfExists, SQL_API_SQLPROCEDURECOLUMNS);   /* 66 */
+   SQL_FUNC_ESET(pfExists, SQL_API_SQLPROCEDURECOLUMNS);   /* 66 */ 
    SQL_FUNC_ESET(pfExists, SQL_API_SQLPROCEDURES);     /* 67 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLSETPOS);     /* 68 */
    /* SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSCROLLOPTIONS); 69 deprecated */
-   SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLEPRIVILEGES);        /* 70 */
+   SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLEPRIVILEGES);    /* 70 */
    /* SQL_FUNC_ESET(pfExists, SQL_API_SQLDRIVERS); */  /* 71 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLBINDPARAMETER);  /* 72 */
 
@@ -604,7 +632,7 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
    SQL_FUNC_ESET(pfExists, SQL_API_SQLSETENVATTR);     /* 1019 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSTMTATTR);    /* 1020 */
    SQL_FUNC_ESET(pfExists, SQL_API_SQLFETCHSCROLL);    /* 1021 */
-   if (ci->updatable_cursors)
+   if (0 != ci->updatable_cursors)
        SQL_FUNC_ESET(pfExists, SQL_API_SQLBULKOPERATIONS); /* 24 */
 
    return SQL_SUCCESS;
@@ -618,17 +646,12 @@ SQLBulkOperations(HSTMT hstmt, SQLSMALLINT operation)
    StatementClass  *stmt = (StatementClass *) hstmt;
 
    ENTER_STMT_CS(stmt);
-#ifndef    DRIVER_CURSOR_IMPLEMENT
-   SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR,
-   "driver must be compiled with the DRIVER_CURSOR_IMPLEMENT option");
-   SC_log_error(func, "", stmt);
-   ret = SQL_ERROR;
-#else
-   mylog("[[%s]] Handle=%u %d\n", func, hstmt, operation);
-   SC_clear_error((StatementClass *) hstmt);
+   mylog("[[%s]] Handle=%x %d\n", func, hstmt, operation);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_BulkOperations(hstmt, operation);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
+   ret = DiscardStatementSvp(stmt,ret, FALSE);
    LEAVE_STMT_CS(stmt);
    return ret;
-}
-
+}  
+#endif /* ODBCVER >= 0x0300 */
index eeeb43c4750c69f419705105efe4cd8a46101682..136909ce92c7fed8fb3319bbbe2f20f5596ab3cc 100644 (file)
@@ -7,13 +7,14 @@
  *
  * API functions:  SQLColAttributeW, SQLGetStmtAttrW, SQLSetStmtAttrW,
            SQLSetConnectAttrW, SQLGetConnectAttrW,
-           SQLGetDescFieldW, SQLGetDiagFieldW,
+           SQLGetDescFieldW, SQLGetDescRecW, SQLGetDiagFieldW,
            SQLGetDiagRecW,
  *-------
  */
 
 #include "psqlodbc.h"
 
+#if (ODBCVER >= 0x0300)
 #include <stdio.h>
 #include <string.h>
 
@@ -28,13 +29,17 @@ RETCODE SQL_API SQLGetStmtAttrW(SQLHSTMT hstmt,
        SQLINTEGER  cbValueMax,
        SQLINTEGER  *pcbValue)
 {
+   CSTR func = "SQLGetStmtAttrW";
    RETCODE ret;
+   StatementClass  *stmt = (StatementClass *) hstmt;
 
-   mylog("[SQLGetStmtAttrW]");
+   mylog("[%s]", func);
    ENTER_STMT_CS((StatementClass *) hstmt);
    SC_clear_error((StatementClass *) hstmt);
+   StartRollbackState(stmt);
    ret = PGAPI_GetStmtAttr(hstmt, fAttribute, rgbValue,
        cbValueMax, pcbValue);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS((StatementClass *) hstmt);
    return ret;
 }
@@ -44,14 +49,18 @@ RETCODE SQL_API SQLSetStmtAttrW(SQLHSTMT hstmt,
        PTR     rgbValue,
        SQLINTEGER  cbValueMax)
 {
+   CSTR func = "SQLSetStmtAttrW";
    RETCODE ret;
+   StatementClass  *stmt = (StatementClass *) hstmt;
 
-   mylog("[SQLSetStmtAttrW]");
-   ENTER_STMT_CS((StatementClass *) hstmt);
-   SC_clear_error((StatementClass *) hstmt);
+   mylog("[%s]", func);
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_SetStmtAttr(hstmt, fAttribute, rgbValue,
        cbValueMax);
-   LEAVE_STMT_CS((StatementClass *) hstmt);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
+   LEAVE_STMT_CS(stmt);
    return ret;
 }
 
@@ -61,9 +70,10 @@ RETCODE SQL_API  SQLGetConnectAttrW(HDBC hdbc,
        SQLINTEGER  cbValueMax,
        SQLINTEGER  *pcbValue)
 {
+   CSTR func = "SQLGetConnectAttrW";
    RETCODE ret;
 
-   mylog("[SQLGetConnectAttrW]");
+   mylog("[%s]", func);
    ENTER_CONN_CS((ConnectionClass *) hdbc);
    CC_clear_error((ConnectionClass *) hdbc);
    ret = PGAPI_GetConnectAttr(hdbc, fAttribute, rgbValue,
@@ -77,30 +87,34 @@ RETCODE SQL_API SQLSetConnectAttrW(HDBC hdbc,
        PTR     rgbValue,
        SQLINTEGER  cbValue)
 {
+   CSTR func = "SQLSetConnectAttrW";
    RETCODE ret;
+   ConnectionClass *conn = (ConnectionClass *) hdbc;
 
-   mylog("[SQLSetConnectAttrW]");
-   ENTER_CONN_CS((ConnectionClass *) hdbc);
-   CC_clear_error((ConnectionClass *) hdbc);
+   mylog("[%s]", func);
+   ENTER_CONN_CS(conn);
+   CC_clear_error(conn);
+   CC_set_in_unicode_driver(conn);
    ret = PGAPI_SetConnectAttr(hdbc, fAttribute, rgbValue,
        cbValue);
-   LEAVE_CONN_CS((ConnectionClass *) hdbc);
+   LEAVE_CONN_CS(conn);
    return ret;
 }
 
 /*      new function */
 RETCODE  SQL_API
 SQLSetDescFieldW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber,
-               SQLSMALLINT FieldIdentifier, PTR Value,
+               SQLSMALLINT FieldIdentifier, PTR Value, 
                SQLINTEGER BufferLength)
 {
+   CSTR func = "SQLSetDescFieldW";
    RETCODE ret;
-   UInt4   vallen;
+   Int4    vallen;
         char    *uval = NULL;
    BOOL    val_alloced = FALSE;
 
-   mylog("[SQLSetDescFieldW]");
-   if (BufferLength > 0)
+   mylog("[%s]", func);
+   if (BufferLength > 0 || SQL_NTS == BufferLength)
    {
        switch (FieldIdentifier)
        {
@@ -115,7 +129,7 @@ SQLSetDescFieldW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber,
            case SQL_DESC_SCHEMA_NAME:
            case SQL_DESC_TABLE_NAME:
            case SQL_DESC_TYPE_NAME:
-               uval = ucs2_to_utf8(Value, BufferLength / 2, &vallen, FALSE);
+               uval = ucs2_to_utf8(Value, BufferLength > 0 ? BufferLength / WCLEN : BufferLength, &vallen, FALSE);
                val_alloced = TRUE;
            break;
        }
@@ -136,12 +150,12 @@ SQLGetDescFieldW(SQLHDESC hdesc, SQLSMALLINT iRecord, SQLSMALLINT iField,
                PTR rgbValue, SQLINTEGER cbValueMax,
                    SQLINTEGER *pcbValue)
 {
+   CSTR func = "SQLGetDescFieldW";
    RETCODE ret;
-   BOOL    alloced = FALSE;
-   SQLINTEGER  blen=0, bMax, *pcbV;
+   SQLINTEGER  blen = 0, bMax, *pcbV;
         char    *rgbV = NULL;
 
-   mylog("[SQLGetDescFieldW]");
+   mylog("[%s]", func);
    switch (iField)
    {
        case SQL_DESC_BASE_COLUMN_NAME:
@@ -155,35 +169,41 @@ SQLGetDescFieldW(SQLHDESC hdesc, SQLSMALLINT iRecord, SQLSMALLINT iField,
        case SQL_DESC_SCHEMA_NAME:
        case SQL_DESC_TABLE_NAME:
        case SQL_DESC_TYPE_NAME:
-           alloced = TRUE;
-           bMax = cbValueMax * 3 / 2;
+           bMax = cbValueMax * 3 / WCLEN;
            rgbV = malloc(bMax + 1);
            pcbV = &blen;
-                   break;
+           for (;; bMax = blen + 1, rgbV = realloc(rgbV, bMax))
+           {
+               ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbV, bMax, pcbV);
+               if (SQL_SUCCESS_WITH_INFO != ret || blen < bMax)
+                   break;
+           }
+           if (SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret)
+           {
+               blen = utf8_to_ucs2(rgbV, blen, (SQLWCHAR *) rgbValue, cbValueMax / WCLEN);
+               if (SQL_SUCCESS == ret && blen * WCLEN >= cbValueMax)
+               {
+                   ret = SQL_SUCCESS_WITH_INFO;
+                   DC_set_error(hdesc, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.");
+               }
+               if (pcbValue)
+                   *pcbValue = blen * WCLEN;
+           }
+           if (rgbV)
+               free(rgbV);
+           break;
        default:
            rgbV = rgbValue;
            bMax = cbValueMax;
            pcbV = pcbValue;
+           ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbV, bMax, pcbV);
            break;
    }
-   ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbV, bMax, pcbV);
-   if (alloced)
-   {
-       blen = utf8_to_ucs2(rgbV, blen, (SQLWCHAR *) rgbValue, cbValueMax / 2);
-       if (SQL_SUCCESS == ret && blen * 2 > cbValueMax)
-       {
-           ret = SQL_SUCCESS_WITH_INFO;
-           DC_set_error(hdesc, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.");
-       }
-       if (pcbValue)
-           *pcbValue = blen * 2;
-       free(rgbV);
-   }
 
    return ret;
 }
 
-RETCODE SQL_API    SQLGetDiagRecW(SWORD fHandleType,
+RETCODE SQL_API    SQLGetDiagRecW(SQLSMALLINT fHandleType,
        SQLHANDLE   handle,
        SQLSMALLINT iRecord,
        SQLWCHAR    *szSqlState,
@@ -192,11 +212,12 @@ RETCODE SQL_API   SQLGetDiagRecW(SWORD fHandleType,
        SQLSMALLINT cbErrorMsgMax,
        SQLSMALLINT *pcbErrorMsg)
 {
+   CSTR func = "SQLGetDiagRecW";
    RETCODE ret;
         SWORD   buflen, tlen;
         char    *qstr = NULL, *mtxt = NULL;
 
-   mylog("[SQLGetDiagRecW]");
+   mylog("[%s]", func);
         if (szSqlState)
                 qstr = malloc(8);
    buflen = 0;
@@ -227,25 +248,32 @@ RETCODE SQL_API   SQLGetDiagRecW(SWORD fHandleType,
         return ret;
 }
 
-RETCODE SQL_API SQLColAttributeW(
-   SQLHSTMT        hstmt,
+SQLRETURN SQL_API SQLColAttributeW(
+   SQLHSTMT    hstmt,
    SQLUSMALLINT    iCol,
    SQLUSMALLINT    iField,
-   SQLPOINTER      pCharAttr,
-   SQLSMALLINT     cbCharAttrMax,
-   SQLSMALLINT  *pcbCharAttr,
-   SQLPOINTER      pNumAttr)
+   SQLPOINTER  pCharAttr,
+   SQLSMALLINT cbCharAttrMax,  
+   SQLSMALLINT *pcbCharAttr,
+#if defined(WITH_UNIXODBC) || defined(WIN32)
+   SQLPOINTER  pNumAttr
+#else
+   SQLLEN      *pNumAttr
+#endif
+   )
 {
+   CSTR func = "SQLColAttributeW";
    RETCODE ret;
-   BOOL    alloced = FALSE;
-   SQLSMALLINT *rgbL, blen=0, bMax;
+   StatementClass  *stmt = (StatementClass *) hstmt;
+   SQLSMALLINT *rgbL, blen = 0, bMax;
         char    *rgbD = NULL;
 
-   mylog("[SQLColAttributeW]");
-   ENTER_STMT_CS((StatementClass *) hstmt);
-   SC_clear_error((StatementClass *) hstmt);
+   mylog("[%s]", func);
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
    switch (iField)
-   {
+   { 
        case SQL_DESC_BASE_COLUMN_NAME:
        case SQL_DESC_BASE_TABLE_NAME:
        case SQL_DESC_CATALOG_NAME:
@@ -258,35 +286,40 @@ RETCODE SQL_API SQLColAttributeW(
        case SQL_DESC_TABLE_NAME:
        case SQL_DESC_TYPE_NAME:
        case SQL_COLUMN_NAME:
-           alloced = TRUE;
-           bMax = cbCharAttrMax * 3 / 2;
-           rgbD = malloc(bMax + 1);
+           bMax = cbCharAttrMax * 3 / WCLEN;
+           rgbD = malloc(bMax);
            rgbL = &blen;
-                   break;
+           for (;; bMax = blen + 1, rgbD = realloc(rgbD, bMax))
+           {
+               ret = PGAPI_ColAttributes(hstmt, iCol, iField, rgbD,
+                   bMax, rgbL, pNumAttr);
+               if (SQL_SUCCESS_WITH_INFO != ret || blen < bMax)
+                   break;
+           }
+           if (SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret)
+           {
+               blen = utf8_to_ucs2(rgbD, blen, (SQLWCHAR *) pCharAttr, cbCharAttrMax / WCLEN);
+               if (SQL_SUCCESS == ret && blen * WCLEN >= cbCharAttrMax)
+               {
+                   ret = SQL_SUCCESS_WITH_INFO;
+                   SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the pCharAttr.", func);
+               }
+               if (pcbCharAttr)
+                   *pcbCharAttr = blen * WCLEN;
+           }
+           if (rgbD)
+               free(rgbD);
+           break;
        default:
            rgbD = pCharAttr;
            bMax = cbCharAttrMax;
            rgbL = pcbCharAttr;
+           ret = PGAPI_ColAttributes(hstmt, iCol, iField, rgbD,
+                   bMax, rgbL, pNumAttr);
            break;
    }
-
-   ret = PGAPI_ColAttributes(hstmt, iCol, iField, rgbD,
-       bMax, rgbL, pNumAttr);
-   if (alloced)
-   {
-       blen = utf8_to_ucs2(rgbD, blen, (SQLWCHAR *) pCharAttr, cbCharAttrMax / 2);
-       if (SQL_SUCCESS == ret && blen * 2 > cbCharAttrMax)
-       {
-           StatementClass  *stmt = (StatementClass *) hstmt;
-
-           ret = SQL_SUCCESS_WITH_INFO;
-           SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the pCharAttr.");
-       }
-       if (pcbCharAttr)
-           *pcbCharAttr = blen * 2;
-       free(rgbD);
-   }
-   LEAVE_STMT_CS((StatementClass *) hstmt);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
+   LEAVE_STMT_CS(stmt);
 
    return ret;
 }
@@ -300,15 +333,16 @@ RETCODE SQL_API SQLGetDiagFieldW(
     SQLSMALLINT        cbDiagInfoMax,
     SQLSMALLINT    *pcbDiagInfo)
 {
+   CSTR func = "SQLGetDiagFieldW";
    RETCODE ret;
-   BOOL    alloced = FALSE;
-   SQLSMALLINT *rgbL, blen=0, bMax;
+   SQLSMALLINT *rgbL, blen = 0, bMax;
         char    *rgbD = NULL;
+   StatementClass  *stmt = (StatementClass *) handle;
 
-   mylog("[[SQLGetDiagFieldW]] Handle=(%u,%x) Rec=%d Id=%d\n", fHandleType,
-           handle, iRecord, fDiagField);
+   mylog("[[%s]] Handle=(%u,%x) Rec=%d Id=%d info=(%x,%d)\n", func, fHandleType,
+           handle, iRecord, fDiagField, rgbDiagInfo, cbDiagInfoMax);
    switch (fDiagField)
-   {
+   { 
        case SQL_DIAG_DYNAMIC_FUNCTION:
        case SQL_DIAG_CLASS_ORIGIN:
        case SQL_DIAG_CONNECTION_NAME:
@@ -316,35 +350,44 @@ RETCODE SQL_API SQLGetDiagFieldW(
        case SQL_DIAG_SERVER_NAME:
        case SQL_DIAG_SQLSTATE:
        case SQL_DIAG_SUBCLASS_ORIGIN:
-           alloced = TRUE;
-           bMax = cbDiagInfoMax * 3 / 2;
-           rgbD = malloc(bMax + 1);
+           bMax = cbDiagInfoMax * 3 / WCLEN;
+           if (rgbD = malloc(bMax + 1), !rgbD)
+           {
+               SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Can't allocate a rgbD buffer.", func);
+               return SQL_ERROR;
+           }
            rgbL = &blen;
-                   break;
+           for (;; bMax = blen + 1, rgbD = realloc(rgbD, bMax))
+           {
+               ret = PGAPI_GetDiagField(fHandleType, handle, iRecord, fDiagField, rgbD,
+                   bMax, rgbL);
+               if (SQL_SUCCESS_WITH_INFO != ret || blen < bMax)
+                   break;
+           }
+           if (SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret)
+           {
+               blen = utf8_to_ucs2(rgbD, blen, (SQLWCHAR *) rgbDiagInfo, cbDiagInfoMax / WCLEN);
+               if (SQL_SUCCESS == ret && blen * WCLEN >= cbDiagInfoMax)
+               {
+                   ret = SQL_SUCCESS_WITH_INFO;
+               SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the rgbDiagInfo.", func);
+               }
+               if (pcbDiagInfo)
+                   *pcbDiagInfo = blen * WCLEN;
+           }
+           if (rgbD)
+               free(rgbD);
+           break;
        default:
            rgbD = rgbDiagInfo;
            bMax = cbDiagInfoMax;
            rgbL = pcbDiagInfo;
+           ret = PGAPI_GetDiagField(fHandleType, handle, iRecord, fDiagField, rgbD,
+               bMax, rgbL);
            break;
    }
 
-   ret = PGAPI_GetDiagField(fHandleType, handle, iRecord, fDiagField, rgbD,
-       bMax, rgbL);
-   if (alloced)
-   {
-       blen = utf8_to_ucs2(rgbD, blen, (SQLWCHAR *) rgbDiagInfo, cbDiagInfoMax / 2);
-       if (SQL_SUCCESS == ret && blen * 2 > cbDiagInfoMax)
-       {
-           StatementClass  *stmt = (StatementClass *) handle;
-
-           ret = SQL_SUCCESS_WITH_INFO;
-           SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the rgbDiagInfo.");
-       }
-       if (pcbDiagInfo)
-           *pcbDiagInfo = blen * 2;
-       free(rgbD);
-   }
-
    return ret;
 }
 
+#endif /* ODBCVER >= 0x0300 */
index 19e7976317362a519b2405e74063a5607bf2ec2f..ff5a0fef3b6893c790f4a3fc42a4712eb78ef821 100644 (file)
@@ -31,14 +31,16 @@ RETCODE  SQL_API SQLColumnsW(HSTMT StatementHandle,
            SQLWCHAR *TableName, SQLSMALLINT NameLength3,
            SQLWCHAR *ColumnName, SQLSMALLINT NameLength4)
 {
+   CSTR func = "SQLColumnsW";
    RETCODE ret;
    char    *ctName, *scName, *tbName, *clName;
-   UInt4   nmlen1, nmlen2, nmlen3, nmlen4;
+   Int4    nmlen1, nmlen2, nmlen3, nmlen4;
    StatementClass *stmt = (StatementClass *) StatementHandle;
    ConnectionClass *conn;
    BOOL    lower_id;
+   UWORD   flag = PODBC_SEARCH_PUBLIC_SCHEMA; 
 
-   mylog("[SQLColumnsW]");
+   mylog("[%s]", func);
    conn = SC_get_conn(stmt);
    lower_id = SC_is_lower_case(stmt, conn);
    ctName = ucs2_to_utf8(CatalogName, NameLength1, &nmlen1, lower_id);
@@ -46,9 +48,19 @@ RETCODE  SQL_API SQLColumnsW(HSTMT StatementHandle,
    tbName = ucs2_to_utf8(TableName, NameLength3, &nmlen3, lower_id);
    clName = ucs2_to_utf8(ColumnName, NameLength4, &nmlen4, lower_id);
    ENTER_STMT_CS(stmt);
-   ret = PGAPI_Columns(StatementHandle, ctName, (SWORD) nmlen1,
-               scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
-               clName, (SWORD) nmlen4, PODBC_SEARCH_PUBLIC_SCHEMA);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+   if (stmt->options.metadata_id)
+       flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
+   if (SC_opencheck(stmt, func))
+       ret = SQL_ERROR;
+   else
+       ret = PGAPI_Columns(StatementHandle, ctName, (SQLSMALLINT) nmlen1,
+                   scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3,
+                   clName, (SQLSMALLINT) nmlen4, flag, 0, 0);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    if (ctName)
        free(ctName);
@@ -67,19 +79,22 @@ RETCODE  SQL_API SQLConnectW(HDBC ConnectionHandle,
            SQLWCHAR *UserName, SQLSMALLINT NameLength2,
            SQLWCHAR *Authentication, SQLSMALLINT NameLength3)
 {
+   CSTR func = "SQLConnectW";
    char    *svName, *usName, *auth;
-   UInt4   nmlen1, nmlen2, nmlen3;
+   Int4    nmlen1, nmlen2, nmlen3;
    RETCODE ret;
-
-   mylog("[SQLConnectW]");
-   ENTER_CONN_CS((ConnectionClass *) ConnectionHandle);
-   ((ConnectionClass *) ConnectionHandle)->unicode = 1;
+   ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
+   
+   mylog("[%s]", func);
+   ENTER_CONN_CS(conn);
+   CC_clear_error(conn);
+   CC_set_in_unicode_driver(conn);
    svName = ucs2_to_utf8(ServerName, NameLength1, &nmlen1, FALSE);
    usName = ucs2_to_utf8(UserName, NameLength2, &nmlen2, FALSE);
    auth = ucs2_to_utf8(Authentication, NameLength3, &nmlen3, FALSE);
-   ret = PGAPI_Connect(ConnectionHandle, svName, (SWORD) nmlen1,
-               usName, (SWORD) nmlen2, auth, (SWORD) nmlen3);
-   LEAVE_CONN_CS((ConnectionClass *) ConnectionHandle);
+   ret = PGAPI_Connect(ConnectionHandle, svName, (SQLSMALLINT) nmlen1,
+               usName, (SQLSMALLINT) nmlen2, auth, (SQLSMALLINT) nmlen3);
+   LEAVE_CONN_CS(conn);
    if (svName)
        free(svName);
    if (usName)
@@ -92,33 +107,54 @@ RETCODE  SQL_API SQLConnectW(HDBC ConnectionHandle,
 RETCODE SQL_API SQLDriverConnectW(HDBC hdbc,
                                  HWND hwnd,
                                  SQLWCHAR *szConnStrIn,
-                                 SWORD cbConnStrIn,
+                                 SQLSMALLINT cbConnStrIn,
                                  SQLWCHAR *szConnStrOut,
-                                 SWORD cbConnStrOutMax,
-                                 SWORD FAR *pcbConnStrOut,
-                                 UWORD fDriverCompletion)
+                                 SQLSMALLINT cbConnStrOutMax,
+                                 SQLSMALLINT FAR *pcbConnStrOut,
+                                 SQLUSMALLINT fDriverCompletion)
 {
-   char    *szIn, *szOut;
-   UInt4   inlen, obuflen;
-   SWORD   olen;
+   CSTR func = "SQLDriverConnectW";
+   char    *szIn, *szOut = NULL;
+   Int4    maxlen, inlen, obuflen = 0;
+   SQLSMALLINT olen;
    RETCODE ret;
+   ConnectionClass *conn = (ConnectionClass *) hdbc;
 
-   mylog("[SQLDriverConnectW]");
-   ENTER_CONN_CS((ConnectionClass *) hdbc);
-   ((ConnectionClass *) hdbc)->unicode = 1;
+   mylog("[%s]", func);
+   ENTER_CONN_CS(conn);
+   CC_clear_error(conn);
+   CC_set_in_unicode_driver(conn);
    szIn = ucs2_to_utf8(szConnStrIn, cbConnStrIn, &inlen, FALSE);
-   obuflen = cbConnStrOutMax + 1;
-   szOut = malloc(obuflen);
-   ret = PGAPI_DriverConnect(hdbc, hwnd, szIn, (SWORD) inlen,
-       szOut, cbConnStrOutMax, &olen, fDriverCompletion);
-   LEAVE_CONN_CS((ConnectionClass *) hdbc);
+   maxlen = cbConnStrOutMax;
+   if (maxlen > 0)
+   {
+       obuflen = maxlen + 1;
+       szOut = malloc(obuflen);
+   }
+   ret = PGAPI_DriverConnect(hdbc, hwnd, szIn, (SQLSMALLINT) inlen,
+       szOut, maxlen, &olen, fDriverCompletion);
    if (ret != SQL_ERROR)
    {
-       UInt4 outlen = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
+       UInt4 outlen = olen;
+
+       if (olen < obuflen)
+           outlen = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
+       else
+           utf8_to_ucs2(szOut, maxlen, szConnStrOut, cbConnStrOutMax);
+       if (outlen >= (UInt4) cbConnStrOutMax)
+       {
+           if (SQL_SUCCESS == ret)
+           {
+               CC_set_error(conn, CONN_TRUNCATED, "the ConnStrOut is too small", func);
+               ret = SQL_SUCCESS_WITH_INFO;
+           }
+       }
        if (pcbConnStrOut)
            *pcbConnStrOut = outlen;
    }
-   free(szOut);
+   LEAVE_CONN_CS(conn);
+   if (szOut)
+       free(szOut);
    if (szIn)
        free(szIn);
    return ret;
@@ -131,20 +167,24 @@ RETCODE SQL_API SQLBrowseConnectW(
     SQLSMALLINT        cbConnStrOutMax,
     SQLSMALLINT       *pcbConnStrOut)
 {
+   CSTR func = "SQLBrowseConnectW";
    char    *szIn, *szOut;
-   UInt4   inlen, obuflen;
-   SWORD   olen;
+   Int4    inlen;
+   UInt4   obuflen;
+   SQLSMALLINT olen;
    RETCODE ret;
+   ConnectionClass *conn = (ConnectionClass *) hdbc;
 
-   mylog("[SQLBrowseConnectW]");
-   ENTER_CONN_CS((ConnectionClass *) hdbc);
-   ((ConnectionClass *) hdbc)->unicode = 1;
+   mylog("[%s]", func);
+   ENTER_CONN_CS(conn);
+   CC_clear_error(conn);
+   CC_set_in_unicode_driver(conn);
    szIn = ucs2_to_utf8(szConnStrIn, cbConnStrIn, &inlen, FALSE);
    obuflen = cbConnStrOutMax + 1;
    szOut = malloc(obuflen);
-   ret = PGAPI_BrowseConnect(hdbc, szIn, (SWORD) inlen,
+   ret = PGAPI_BrowseConnect(hdbc, szIn, (SQLSMALLINT) inlen,
        szOut, cbConnStrOutMax, &olen);
-   LEAVE_CONN_CS((ConnectionClass *) hdbc);
+   LEAVE_CONN_CS(conn);
    if (ret != SQL_ERROR)
    {
        UInt4   outlen = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
@@ -163,7 +203,8 @@ RETCODE  SQL_API SQLDataSourcesW(HENV EnvironmentHandle,
            SQLWCHAR *Description, SQLSMALLINT BufferLength2,
            SQLSMALLINT *NameLength2)
 {
-   mylog("[SQLDataSourcesW]");
+   CSTR func = "SQLDataSourcesW";
+   mylog("[%s]", func);
    /*
    return PGAPI_DataSources(EnvironmentHandle, Direction, ServerName,
         BufferLength1, NameLength1, Description, BufferLength2,
@@ -175,49 +216,72 @@ RETCODE  SQL_API SQLDataSourcesW(HENV EnvironmentHandle,
 RETCODE  SQL_API SQLDescribeColW(HSTMT StatementHandle,
            SQLUSMALLINT ColumnNumber, SQLWCHAR *ColumnName,
            SQLSMALLINT BufferLength, SQLSMALLINT *NameLength,
-           SQLSMALLINT *DataType, SQLUINTEGER *ColumnSize,
+           SQLSMALLINT *DataType, SQLULEN *ColumnSize,
            SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable)
 {
+   CSTR func = "SQLDescribeColW";
    RETCODE ret;
-   SWORD   buflen, nmlen;
+   StatementClass  *stmt = (StatementClass *) StatementHandle;
+   SQLSMALLINT buflen, nmlen;
    char    *clName;
 
-   mylog("[SQLDescribeColW]");
+   mylog("[%s]", func);
    buflen = BufferLength * 3 + 1;
    clName = malloc(buflen);
-   ENTER_STMT_CS((StatementClass *) StatementHandle);
-   ret = PGAPI_DescribeCol(StatementHandle, ColumnNumber,
-       clName, buflen, &nmlen, DataType, ColumnSize,
-       DecimalDigits, Nullable);
-   if (ret == SQL_SUCCESS)
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+   for (;; buflen = nmlen + 1, clName = realloc(clName, buflen))
+   {
+       ret = PGAPI_DescribeCol(StatementHandle, ColumnNumber,
+           clName, buflen, &nmlen, DataType, ColumnSize,
+           DecimalDigits, Nullable);
+       if (SQL_SUCCESS_WITH_INFO != ret || nmlen < buflen)
+           break;
+   }
+   if (SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret)
    {
-       UInt4   nmcount = utf8_to_ucs2(clName, nmlen, ColumnName, BufferLength);
-       if (nmcount > (UInt4) BufferLength)
+       UInt4   nmcount = nmlen;
+
+       if (nmlen < buflen)
+           nmcount = utf8_to_ucs2(clName, nmlen, ColumnName, BufferLength);
+       if (SQL_SUCCESS == ret && nmcount > (UInt4) BufferLength)
        {
-           StatementClass  *stmt = (StatementClass *) StatementHandle;
            ret = SQL_SUCCESS_WITH_INFO;
-           SC_set_error(stmt, STMT_TRUNCATED, "Column name too large");
+           SC_set_error(stmt, STMT_TRUNCATED, "Column name too large", func);
        }
        if (NameLength)
            *NameLength = nmcount;
    }
-   LEAVE_STMT_CS((StatementClass *) StatementHandle);
-   free(clName);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
+   LEAVE_STMT_CS(stmt);
+   free(clName); 
    return ret;
 }
 
 RETCODE  SQL_API SQLExecDirectW(HSTMT StatementHandle,
            SQLWCHAR *StatementText, SQLINTEGER TextLength)
 {
+   CSTR    func = "SQLExecDirectW";
    RETCODE ret;
    char    *stxt;
-   UInt4   slen;
+   Int4    slen;
+   StatementClass  *stmt = (StatementClass *) StatementHandle;
+   UWORD   flag = 0;
 
-   mylog("[SQLExecDirectW]");
+   mylog("[%s]", func);
    stxt = ucs2_to_utf8(StatementText, TextLength, &slen, FALSE);
-   ENTER_STMT_CS((StatementClass *) StatementHandle);
-   ret = PGAPI_ExecDirect(StatementHandle, stxt, slen, 0);
-   LEAVE_STMT_CS((StatementClass *) StatementHandle);
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   if (PG_VERSION_GE(SC_get_conn(stmt), 7.4))
+       flag |= PODBC_WITH_HOLD;
+   StartRollbackState(stmt);
+   if (SC_opencheck(stmt, func))
+       ret = SQL_ERROR;
+   else
+       ret = PGAPI_ExecDirect(StatementHandle, stxt, slen, flag);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
+   LEAVE_STMT_CS(stmt);
    if (stxt)
        free(stxt);
    return ret;
@@ -227,28 +291,40 @@ RETCODE  SQL_API SQLGetCursorNameW(HSTMT StatementHandle,
            SQLWCHAR *CursorName, SQLSMALLINT BufferLength,
            SQLSMALLINT *NameLength)
 {
+   CSTR func = "SQLGetCursorNameW";
    RETCODE ret;
+   StatementClass * stmt = (StatementClass *) StatementHandle;
    char    *crName;
-   SWORD   clen, buflen;
+   SQLSMALLINT clen, buflen;
 
-   mylog("[SQLGetCursorNameW]");
+   mylog("[%s]", func);
    buflen = BufferLength * 3 + 1;
    crName = malloc(buflen);
-   ENTER_STMT_CS((StatementClass *) StatementHandle);
-   ret = PGAPI_GetCursorName(StatementHandle, crName, buflen, &clen);
-   if (ret == SQL_SUCCESS)
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+   for (;; buflen = clen + 1, crName = realloc(crName, buflen))
+   {
+       ret = PGAPI_GetCursorName(StatementHandle, crName, buflen, &clen);
+       if (SQL_SUCCESS_WITH_INFO != ret || clen < buflen)
+           break;
+   }
+   if (SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret) 
    {
-       UInt4   nmcount = utf8_to_ucs2(crName, (Int4) clen, CursorName, BufferLength);
-       if (nmcount > (UInt4) BufferLength)
+       UInt4   nmcount = clen;
+
+       if (clen < buflen)
+           nmcount = utf8_to_ucs2(crName, (Int4) clen, CursorName, BufferLength);
+       if (SQL_SUCCESS == ret && nmcount > (UInt4) BufferLength)
        {
-           StatementClass *stmt = (StatementClass *) StatementHandle;
            ret = SQL_SUCCESS_WITH_INFO;
-           SC_set_error(stmt, STMT_TRUNCATED, "Cursor name too large");
+           SC_set_error(stmt, STMT_TRUNCATED, "Cursor name too large", func);
        }
        if (NameLength)
-           *NameLength = utf8_to_ucs2(crName, (Int4) clen, CursorName, BufferLength);
+           *NameLength = nmcount;
    }
-   LEAVE_STMT_CS((StatementClass *) StatementHandle);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
+   LEAVE_STMT_CS(stmt);
    free(crName);
    return ret;
 }
@@ -257,14 +333,15 @@ RETCODE  SQL_API SQLGetInfoW(HDBC ConnectionHandle,
            SQLUSMALLINT InfoType, PTR InfoValue,
            SQLSMALLINT BufferLength, SQLSMALLINT *StringLength)
 {
+   CSTR func = "SQLGetInfoW";
    ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
    RETCODE ret;
 
-   ENTER_CONN_CS((ConnectionClass *) ConnectionHandle);
-   conn->unicode = 1;
+   ENTER_CONN_CS(conn);
+   CC_set_in_unicode_driver(conn);
    CC_clear_error(conn);
-
-   mylog("[SQLGetInfoW(30)]");
+#if (ODBCVER >= 0x0300)
+   mylog("[%s(30)]", func);
    if ((ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
                BufferLength, StringLength)) == SQL_ERROR)
    {
@@ -277,23 +354,34 @@ RETCODE  SQL_API SQLGetInfoW(HDBC ConnectionHandle,
    }
    if (SQL_ERROR == ret)
        CC_log_error("SQLGetInfoW(30)", "", conn);
-
-   LEAVE_CONN_CS((ConnectionClass *) ConnectionHandle);
+#else
+   mylog("[%s]", func);
+   ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
+               BufferLength, StringLength);
+   if (SQL_ERROR == ret)
+       CC_log_error("SQLGetInfoW", "", conn);
+#endif
+   LEAVE_CONN_CS(conn);
    return ret;
 }
 
 RETCODE  SQL_API SQLPrepareW(HSTMT StatementHandle,
            SQLWCHAR *StatementText, SQLINTEGER TextLength)
 {
+   CSTR func = "SQLPrepareW";
+   StatementClass *stmt = (StatementClass *) StatementHandle;
    RETCODE ret;
    char    *stxt;
-   UInt4   slen;
+   Int4    slen;
 
-   mylog("[SQLPrepareW]");
+   mylog("[%s]", func);
    stxt = ucs2_to_utf8(StatementText, TextLength, &slen, FALSE);
-   ENTER_STMT_CS((StatementClass *) StatementHandle);
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
    ret = PGAPI_Prepare(StatementHandle, stxt, slen);
-   LEAVE_STMT_CS((StatementClass *) StatementHandle);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
+   LEAVE_STMT_CS(stmt);
    if (stxt)
        free(stxt);
    return ret;
@@ -302,15 +390,20 @@ RETCODE  SQL_API SQLPrepareW(HSTMT StatementHandle,
 RETCODE  SQL_API SQLSetCursorNameW(HSTMT StatementHandle,
            SQLWCHAR *CursorName, SQLSMALLINT NameLength)
 {
+   CSTR func = "SQLSetCursorNameW";
    RETCODE ret;
+   StatementClass *stmt = (StatementClass *) StatementHandle;
    char    *crName;
-   UInt4   nlen;
+   Int4    nlen;
 
-   mylog("[SQLSetCursorNameW]");
+   mylog("[%s]", func);
    crName = ucs2_to_utf8(CursorName, NameLength, &nlen, FALSE);
-   ENTER_STMT_CS((StatementClass *) StatementHandle);
-   ret = PGAPI_SetCursorName(StatementHandle, crName, (SWORD) nlen);
-   LEAVE_STMT_CS((StatementClass *) StatementHandle);
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+   ret = PGAPI_SetCursorName(StatementHandle, crName, (SQLSMALLINT) nlen);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
+   LEAVE_STMT_CS(stmt);
    if (crName)
        free(crName);
    return ret;
@@ -323,23 +416,30 @@ RETCODE  SQL_API SQLSpecialColumnsW(HSTMT StatementHandle,
            SQLSMALLINT NameLength3, SQLUSMALLINT Scope,
            SQLUSMALLINT Nullable)
 {
+   CSTR func = "SQLSpecialColumnsW";
    RETCODE ret;
    char    *ctName, *scName, *tbName;
-   UInt4   nmlen1, nmlen2, nmlen3;
+   Int4    nmlen1, nmlen2, nmlen3;
    StatementClass *stmt = (StatementClass *) StatementHandle;
    ConnectionClass *conn;
    BOOL lower_id;
-
-   mylog("[SQLSpecialColumnsW]");
+   
+   mylog("[%s]", func);
    conn = SC_get_conn(stmt);
    lower_id = SC_is_lower_case(stmt, conn);
    ctName = ucs2_to_utf8(CatalogName, NameLength1, &nmlen1, lower_id);
    scName = ucs2_to_utf8(SchemaName, NameLength2, &nmlen2, lower_id);
    tbName = ucs2_to_utf8(TableName, NameLength3, &nmlen3, lower_id);
    ENTER_STMT_CS(stmt);
-   ret = PGAPI_SpecialColumns(StatementHandle, IdentifierType, ctName,
-           (SWORD) nmlen1, scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+   if (SC_opencheck(stmt, func))
+       ret = SQL_ERROR;
+   else
+       ret = PGAPI_SpecialColumns(StatementHandle, IdentifierType, ctName,
+               (SQLSMALLINT) nmlen1, scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3,
        Scope, Nullable);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    if (ctName)
        free(ctName);
@@ -356,23 +456,30 @@ RETCODE  SQL_API SQLStatisticsW(HSTMT StatementHandle,
            SQLWCHAR *TableName, SQLSMALLINT NameLength3,
            SQLUSMALLINT Unique, SQLUSMALLINT Reserved)
 {
+   CSTR func = "SQLStatisticsW";
    RETCODE ret;
    char    *ctName, *scName, *tbName;
-   UInt4   nmlen1, nmlen2, nmlen3;
+   Int4    nmlen1, nmlen2, nmlen3;
    StatementClass *stmt = (StatementClass *) StatementHandle;
    ConnectionClass *conn;
    BOOL lower_id;
 
-   mylog("[SQLStatisticsW]");
+   mylog("[%s]", func);
    conn = SC_get_conn(stmt);
    lower_id = SC_is_lower_case(stmt, conn);
    ctName = ucs2_to_utf8(CatalogName, NameLength1, &nmlen1, lower_id);
    scName = ucs2_to_utf8(SchemaName, NameLength2, &nmlen2, lower_id);
    tbName = ucs2_to_utf8(TableName, NameLength3, &nmlen3, lower_id);
    ENTER_STMT_CS(stmt);
-   ret = PGAPI_Statistics(StatementHandle, ctName, (SWORD) nmlen1,
-           scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3, Unique,
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+   if (SC_opencheck(stmt, func))
+       ret = SQL_ERROR;
+   else
+       ret = PGAPI_Statistics(StatementHandle, ctName, (SQLSMALLINT) nmlen1,
+           scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3, Unique,
        Reserved);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    if (ctName)
        free(ctName);
@@ -389,14 +496,15 @@ RETCODE  SQL_API SQLTablesW(HSTMT StatementHandle,
            SQLWCHAR *TableName, SQLSMALLINT NameLength3,
            SQLWCHAR *TableType, SQLSMALLINT NameLength4)
 {
+   CSTR func = "SQLTablesW";
    RETCODE ret;
    char    *ctName, *scName, *tbName, *tbType;
-   UInt4   nmlen1, nmlen2, nmlen3, nmlen4;
+   Int4    nmlen1, nmlen2, nmlen3, nmlen4;
    StatementClass *stmt = (StatementClass *) StatementHandle;
    ConnectionClass *conn;
    BOOL lower_id;
 
-   mylog("[SQLTablesW]");
+   mylog("[%s]", func);
    conn = SC_get_conn(stmt);
    lower_id = SC_is_lower_case(stmt, conn);
    ctName = ucs2_to_utf8(CatalogName, NameLength1, &nmlen1, lower_id);
@@ -404,9 +512,15 @@ RETCODE  SQL_API SQLTablesW(HSTMT StatementHandle,
    tbName = ucs2_to_utf8(TableName, NameLength3, &nmlen3, lower_id);
    tbType = ucs2_to_utf8(TableType, NameLength4, &nmlen4, FALSE);
    ENTER_STMT_CS(stmt);
-   ret = PGAPI_Tables(StatementHandle, ctName, (SWORD) nmlen1,
-           scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
-           tbType, (SWORD) nmlen4);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+   if (SC_opencheck(stmt, func))
+       ret = SQL_ERROR;
+   else
+       ret = PGAPI_Tables(StatementHandle, ctName, (SQLSMALLINT) nmlen1,
+                   scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3,
+                   tbType, (SQLSMALLINT) nmlen4);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    if (ctName)
        free(ctName);
@@ -430,14 +544,16 @@ RETCODE SQL_API SQLColumnPrivilegesW(
     SQLWCHAR         *szColumnName,
     SQLSMALLINT        cbColumnName)
 {
+   CSTR func = "SQLColumnPrivilegesW";
    RETCODE ret;
    char    *ctName, *scName, *tbName, *clName;
-   UInt4   nmlen1, nmlen2, nmlen3, nmlen4;
+   Int4    nmlen1, nmlen2, nmlen3, nmlen4;
    StatementClass *stmt = (StatementClass *) hstmt;
    ConnectionClass *conn;
    BOOL    lower_id;
+   UWORD   flag = 0; 
 
-   mylog("[SQLColumnPrivilegesW]");
+   mylog("[%s]", func);
    conn = SC_get_conn(stmt);
    lower_id = SC_is_lower_case(stmt, conn);
    ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1, lower_id);
@@ -445,9 +561,19 @@ RETCODE SQL_API SQLColumnPrivilegesW(
    tbName = ucs2_to_utf8(szTableName, cbTableName, &nmlen3, lower_id);
    clName = ucs2_to_utf8(szColumnName, cbColumnName, &nmlen4, lower_id);
    ENTER_STMT_CS(stmt);
-   ret = PGAPI_ColumnPrivileges(hstmt, ctName, (SWORD) nmlen1,
-       scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
-       clName, (SWORD) nmlen4);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+   if (stmt->options.metadata_id)
+       flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
+   if (SC_opencheck(stmt, func))
+       ret = SQL_ERROR;
+   else
+       ret = PGAPI_ColumnPrivileges(hstmt, ctName, (SQLSMALLINT) nmlen1,
+           scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3,
+           clName, (SQLSMALLINT) nmlen4, flag);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    if (ctName)
        free(ctName);
@@ -475,14 +601,15 @@ RETCODE SQL_API SQLForeignKeysW(
     SQLWCHAR         *szFkTableName,
     SQLSMALLINT        cbFkTableName)
 {
+   CSTR func = "SQLForeignKeysW";
    RETCODE ret;
    char    *ctName, *scName, *tbName, *fkctName, *fkscName, *fktbName;
-   UInt4   nmlen1, nmlen2, nmlen3, nmlen4, nmlen5, nmlen6;
+   Int4    nmlen1, nmlen2, nmlen3, nmlen4, nmlen5, nmlen6;
    StatementClass *stmt = (StatementClass *) hstmt;
    ConnectionClass *conn;
-   BOOL    lower_id;
+   BOOL    lower_id; 
 
-   mylog("[SQLForeignKeysW]");
+   mylog("[%s]", func);
    conn = SC_get_conn(stmt);
    lower_id = SC_is_lower_case(stmt, conn);
    ctName = ucs2_to_utf8(szPkCatalogName, cbPkCatalogName, &nmlen1, lower_id);
@@ -492,10 +619,16 @@ RETCODE SQL_API SQLForeignKeysW(
    fkscName = ucs2_to_utf8(szFkSchemaName, cbFkSchemaName, &nmlen5, lower_id);
    fktbName = ucs2_to_utf8(szFkTableName, cbFkTableName, &nmlen6, lower_id);
    ENTER_STMT_CS(stmt);
-   ret = PGAPI_ForeignKeys(hstmt, ctName, (SWORD) nmlen1,
-       scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
-       fkctName, (SWORD) nmlen4, fkscName, (SWORD) nmlen5,
-       fktbName, (SWORD) nmlen6);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+   if (SC_opencheck(stmt, func))
+       ret = SQL_ERROR;
+   else
+       ret = PGAPI_ForeignKeys(hstmt, ctName, (SQLSMALLINT) nmlen1,
+           scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3,
+           fkctName, (SQLSMALLINT) nmlen4, fkscName, (SQLSMALLINT) nmlen5,
+           fktbName, (SQLSMALLINT) nmlen6);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    if (ctName)
        free(ctName);
@@ -520,35 +653,46 @@ RETCODE SQL_API SQLNativeSqlW(
     SQLINTEGER         cbSqlStrMax,
     SQLINTEGER           *pcbSqlStr)
 {
+   CSTR func = "SQLNativeSqlW";
    RETCODE     ret;
    char        *szIn, *szOut;
-   UInt4       slen;
+   Int4        slen;
    SQLINTEGER  buflen, olen;
+   ConnectionClass *conn = (ConnectionClass *) hdbc;
 
-   mylog("[SQLNativeSqlW]");
-   ENTER_CONN_CS((ConnectionClass *) hdbc);
-   ((ConnectionClass *) hdbc)->unicode = 1;
+   mylog("[%s}", func);
+   ENTER_CONN_CS(conn);
+   CC_clear_error(conn);
+   CC_set_in_unicode_driver(conn);
    szIn = ucs2_to_utf8(szSqlStrIn, cbSqlStrIn, &slen, FALSE);
    buflen = 3 * cbSqlStrMax + 1;
    szOut = malloc(buflen);
-   ret = PGAPI_NativeSql(hdbc, szIn, (SQLINTEGER) slen,
-       szOut, buflen, &olen);
+   for (;; buflen = olen + 1, szOut = realloc(szOut, buflen))
+   {
+       ret = PGAPI_NativeSql(hdbc, szIn, (SQLINTEGER) slen,
+           szOut, buflen, &olen);
+       if (SQL_SUCCESS_WITH_INFO == ret || olen < buflen)
+           break;
+   }
    if (szIn)
        free(szIn);
-   if (ret == SQL_SUCCESS)
+   if (SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret)
    {
-       UInt4   szcount = utf8_to_ucs2(szOut, olen, szSqlStr, cbSqlStrMax);
-       if (szcount > (UInt4) cbSqlStrMax)
+       UInt4   szcount = olen;
+
+       if (olen < buflen)
+           szcount = utf8_to_ucs2(szOut, olen, szSqlStr, cbSqlStrMax);
+       if (SQL_SUCCESS == ret && szcount > (UInt4) cbSqlStrMax)
        {
            ConnectionClass *conn = (ConnectionClass *) hdbc;
 
            ret = SQL_SUCCESS_WITH_INFO;
-           CC_set_error(conn, CONN_TRUNCATED, "Sql string too large");
+           CC_set_error(conn, CONN_TRUNCATED, "Sql string too large", func);
        }
        if (pcbSqlStr)
            *pcbSqlStr = szcount;
    }
-   LEAVE_CONN_CS((ConnectionClass *) hdbc);
+   LEAVE_CONN_CS(conn);
    free(szOut);
    return ret;
 }
@@ -562,22 +706,29 @@ RETCODE SQL_API SQLPrimaryKeysW(
     SQLWCHAR         *szTableName,
     SQLSMALLINT        cbTableName)
 {
+   CSTR func = "SQLPrimaryKeysW";
    RETCODE ret;
    char    *ctName, *scName, *tbName;
-   UInt4   nmlen1, nmlen2, nmlen3;
+   Int4    nmlen1, nmlen2, nmlen3;
    StatementClass *stmt = (StatementClass *) hstmt;
    ConnectionClass *conn;
-   BOOL    lower_id;
+   BOOL    lower_id; 
 
-   mylog("[SQLPrimaryKeysW]");
+   mylog("[%s]", func);
    conn = SC_get_conn(stmt);
    lower_id = SC_is_lower_case(stmt, conn);
    ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1, lower_id);
    scName = ucs2_to_utf8(szSchemaName, cbSchemaName, &nmlen2, lower_id);
    tbName = ucs2_to_utf8(szTableName, cbTableName, &nmlen3, lower_id);
    ENTER_STMT_CS(stmt);
-   ret = PGAPI_PrimaryKeys(hstmt, ctName, (SWORD) nmlen1,
-       scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+   if (SC_opencheck(stmt, func))
+       ret = SQL_ERROR;
+   else
+       ret = PGAPI_PrimaryKeys(hstmt, ctName, (SQLSMALLINT) nmlen1,
+           scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    if (ctName)
        free(ctName);
@@ -599,14 +750,16 @@ RETCODE SQL_API SQLProcedureColumnsW(
     SQLWCHAR         *szColumnName,
     SQLSMALLINT        cbColumnName)
 {
+   CSTR func = "SQLProcedureColumnsW";
    RETCODE ret;
    char    *ctName, *scName, *prName, *clName;
-   UInt4   nmlen1, nmlen2, nmlen3, nmlen4;
+   Int4    nmlen1, nmlen2, nmlen3, nmlen4;
    StatementClass *stmt = (StatementClass *) hstmt;
    ConnectionClass *conn;
    BOOL    lower_id;
+   UWORD   flag = 0; 
 
-   mylog("[SQLProcedureColumnsW]");
+   mylog("[%s]", func);
    conn = SC_get_conn(stmt);
    lower_id = SC_is_lower_case(stmt, conn);
    ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1, lower_id);
@@ -614,9 +767,19 @@ RETCODE SQL_API SQLProcedureColumnsW(
    prName = ucs2_to_utf8(szProcName, cbProcName, &nmlen3, lower_id);
    clName = ucs2_to_utf8(szColumnName, cbColumnName, &nmlen4, lower_id);
    ENTER_STMT_CS(stmt);
-   ret = PGAPI_ProcedureColumns(hstmt, ctName, (SWORD) nmlen1,
-       scName, (SWORD) nmlen2, prName, (SWORD) nmlen3,
-       clName, (SWORD) nmlen4);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+   if (stmt->options.metadata_id)
+       flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
+   if (SC_opencheck(stmt, func))
+       ret = SQL_ERROR;
+   else
+       ret = PGAPI_ProcedureColumns(hstmt, ctName, (SQLSMALLINT) nmlen1,
+           scName, (SQLSMALLINT) nmlen2, prName, (SQLSMALLINT) nmlen3,
+           clName, (SQLSMALLINT) nmlen4, flag);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    if (ctName)
        free(ctName);
@@ -638,22 +801,29 @@ RETCODE SQL_API SQLProceduresW(
     SQLWCHAR         *szProcName,
     SQLSMALLINT        cbProcName)
 {
+   CSTR func = "SQLProceduresW";
    RETCODE ret;
    char    *ctName, *scName, *prName;
-   UInt4   nmlen1, nmlen2, nmlen3;
+   Int4    nmlen1, nmlen2, nmlen3;
    StatementClass *stmt = (StatementClass *) hstmt;
    ConnectionClass *conn;
-   BOOL    lower_id;
+   BOOL    lower_id; 
 
-   mylog("[SQLProceduresW]");
+   mylog("[%s]", func);
    conn = SC_get_conn(stmt);
    lower_id = SC_is_lower_case(stmt, conn);
    ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1, lower_id);
    scName = ucs2_to_utf8(szSchemaName, cbSchemaName, &nmlen2, lower_id);
    prName = ucs2_to_utf8(szProcName, cbProcName, &nmlen3, lower_id);
    ENTER_STMT_CS(stmt);
-   ret = PGAPI_Procedures(hstmt, ctName, (SWORD) nmlen1,
-       scName, (SWORD) nmlen2, prName, (SWORD) nmlen3);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+   if (SC_opencheck(stmt, func))
+       ret = SQL_ERROR;
+   else
+       ret = PGAPI_Procedures(hstmt, ctName, (SQLSMALLINT) nmlen1,
+           scName, (SQLSMALLINT) nmlen2, prName, (SQLSMALLINT) nmlen3);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);
    if (ctName)
        free(ctName);
@@ -673,22 +843,34 @@ RETCODE SQL_API SQLTablePrivilegesW(
     SQLWCHAR         *szTableName,
     SQLSMALLINT        cbTableName)
 {
+   CSTR func = "SQLTablePrivilegesW";
    RETCODE ret;
    char    *ctName, *scName, *tbName;
-   UInt4   nmlen1, nmlen2, nmlen3;
+   Int4    nmlen1, nmlen2, nmlen3;
    StatementClass *stmt = (StatementClass *) hstmt;
    ConnectionClass *conn;
-   BOOL    lower_id;
+   BOOL    lower_id; 
+   UWORD   flag = 0; 
 
-   mylog("[SQLTablePrivilegesW]");
+   mylog("[%s]", func);
    conn = SC_get_conn(stmt);
    lower_id = SC_is_lower_case(stmt, conn);
    ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1, lower_id);
    scName = ucs2_to_utf8(szSchemaName, cbSchemaName, &nmlen2, lower_id);
    tbName = ucs2_to_utf8(szTableName, cbTableName, &nmlen3, lower_id);
    ENTER_STMT_CS((StatementClass *) hstmt);
-   ret = PGAPI_TablePrivileges(hstmt, ctName, (SWORD) nmlen1,
-       scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3, 0);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+   if (stmt->options.metadata_id)
+       flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
+   if (SC_opencheck(stmt, func))
+       ret = SQL_ERROR;
+   else
+       ret = PGAPI_TablePrivileges(hstmt, ctName, (SQLSMALLINT) nmlen1,
+           scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3, flag);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS((StatementClass *) hstmt);
    if (ctName)
        free(ctName);
@@ -703,11 +885,19 @@ RETCODE SQL_API   SQLGetTypeInfoW(
        SQLHSTMT    StatementHandle,
        SQLSMALLINT DataType)
 {
+   CSTR func = "SQLGetTypeInfoW";
    RETCODE ret;
+   StatementClass * stmt = (StatementClass *) StatementHandle;
 
-   mylog("[SQLGetInfoW]");
-   ENTER_STMT_CS((StatementClass *) StatementHandle);
-   ret = PGAPI_GetTypeInfo(StatementHandle, DataType);
-   LEAVE_STMT_CS((StatementClass *) StatementHandle);
+   mylog("[%s]", func);
+   ENTER_STMT_CS(stmt);
+   SC_clear_error(stmt);
+   StartRollbackState(stmt);
+   if (SC_opencheck(stmt, func))
+       ret = SQL_ERROR;
+   else
+       ret = PGAPI_GetTypeInfo(StatementHandle, DataType);
+   ret = DiscardStatementSvp(stmt, ret, FALSE);
+   LEAVE_STMT_CS(stmt);
    return ret;
 }
index 8ab21589713b7e0e183677a5045396840ccde95f..5146e1163299bd068a13684b996c7521bbebb23a 100644 (file)
--- a/options.c
+++ b/options.c
 
 
 
-RETCODE set_statement_option(ConnectionClass *conn,
-                    StatementClass *stmt,
-                    UWORD fOption,
-                    UDWORD vParam);
-
-
 RETCODE
 set_statement_option(ConnectionClass *conn,
                     StatementClass *stmt,
-                    UWORD fOption,
-                    UDWORD vParam)
+                    SQLUSMALLINT fOption,
+                    SQLULEN vParam)
 {
    CSTR func = "set_statement_option";
    char        changed = FALSE;
@@ -70,7 +64,7 @@ set_statement_option(ConnectionClass *conn,
                ;
            else if (ci->drivers.lie)
                setval = vParam;
-           else if (ci->updatable_cursors)
+           else if (0 != ci->updatable_cursors)
                setval = SQL_CONCUR_ROWVER;
            if (conn)
                conn->stmtOptions.scroll_concurrency = setval;
@@ -78,8 +72,7 @@ set_statement_option(ConnectionClass *conn,
            {
                if (SC_get_Result(stmt))
                {
-                   SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The attr can't be changed because the cursor is open.");
-                   SC_log_error(func, "", stmt);
+                   SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The attr can't be changed because the cursor is open.", func);
                    return SQL_ERROR;
                }
                stmt->options.scroll_concurrency =
@@ -100,29 +93,15 @@ set_statement_option(ConnectionClass *conn,
            setval = SQL_CURSOR_FORWARD_ONLY;
            if (ci->drivers.lie)
                setval = vParam;
-#ifdef DECLAREFETCH_FORWARDONLY
-           else if (ci->drivers.use_declarefetch)
-               ;
-#endif /* DECLAREFETCH_FORWARDONLY */
            else if (SQL_CURSOR_STATIC == vParam)
                setval = vParam;
-           else if (SQL_CURSOR_KEYSET_DRIVEN == vParam)
+           else if (SQL_CURSOR_KEYSET_DRIVEN == vParam ||
+                SQL_CURSOR_DYNAMIC == vParam)
            {
-               if (ci->updatable_cursors)
+               if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS)) 
                    setval = vParam;
                else
-               {
-                   changed = TRUE;
                    setval = SQL_CURSOR_STATIC; /* at least scrollable */
-               }
-           }
-           else if (SQL_CURSOR_DYNAMIC == vParam)
-           {
-               changed = TRUE;
-               if (ci->updatable_cursors)
-                   setval = SQL_CURSOR_KEYSET_DRIVEN;
-               else
-                   setval = SQL_CURSOR_STATIC;
            }
            if (conn)
                conn->stmtOptions.cursor_type = setval;
@@ -130,8 +109,7 @@ set_statement_option(ConnectionClass *conn,
            {
                if (SC_get_Result(stmt))
                {
-                   SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The attr can't be changed because the cursor is open.");
-                   SC_log_error(func, "", stmt);
+                   SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The attr can't be changed because the cursor is open.", func);
                    return SQL_ERROR;
                }
                stmt->options_orig.cursor_type =
@@ -158,19 +136,6 @@ set_statement_option(ConnectionClass *conn,
 
            break;
 
-           /*-------
-            *  if (ci->drivers.lie)
-            *      stmt->keyset_size = vParam;
-            *  else
-            *  {
-            *      stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
-            *      stmt->errormsg = "Driver does not support keyset size option";
-            *      SC_log_error(func, "", stmt);
-            *      return SQL_ERROR;
-            *  }
-            *-------
-            */
-
        case SQL_MAX_LENGTH:    /* ignored, but saved */
            mylog("SetStmtOption(): SQL_MAX_LENGTH, vParam = %d\n", vParam);
            if (conn)
@@ -243,19 +208,23 @@ set_statement_option(ConnectionClass *conn,
        case SQL_SIMULATE_CURSOR:       /* NOT SUPPORTED */
            if (stmt)
            {
-               SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Simulated positioned update/delete not supported.  Use the cursor library.");
-               SC_log_error(func, "", stmt);
+               SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Simulated positioned update/delete not supported.  Use the cursor library.", func);
            }
            if (conn)
            {
-               CC_set_error(conn, STMT_NOT_IMPLEMENTED_ERROR, "Simulated positioned update/delete not supported.  Use the cursor library.");
-               CC_log_error(func, "", conn);
+               CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Simulated positioned update/delete not supported.  Use the cursor library.", func);
            }
            return SQL_ERROR;
 
        case SQL_USE_BOOKMARKS:
            if (stmt)
-               stmt->options.use_bookmarks = vParam;
+           {
+#if (ODBCVER >= 0x0300)
+               mylog("USE_BOOKMARKS %s\n", (vParam == SQL_UB_OFF) ? "off" : ((vParam == SQL_UB_VARIABLE) ? "variable" : "fixed"));
+#endif /* ODBCVER */
+               setval = vParam;
+               stmt->options.use_bookmarks = setval;
+           }
            if (conn)
                conn->stmtOptions.use_bookmarks = vParam;
            break;
@@ -265,11 +234,11 @@ set_statement_option(ConnectionClass *conn,
        case 1228: /* SQL_SOPT_SS_NOBROWSETABLE ? */
            if (stmt)
            {
-               SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "The option may be for MS SQL Server(Set)");
+               SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "The option may be for MS SQL Server(Set)", func);
            }
            else if (conn)
            {
-               CC_set_error(conn, STMT_OPTION_NOT_FOR_THE_DRIVER, "The option may be for MS SQL Server(Set)");
+               CC_set_error(conn, CONN_OPTION_NOT_FOR_THE_DRIVER, "The option may be for MS SQL Server(Set)", func);
            }
            return SQL_ERROR;
        default:
@@ -278,13 +247,13 @@ set_statement_option(ConnectionClass *conn,
 
                if (stmt)
                {
-                   SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Set)");
+                   SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Set)", NULL);
                    sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
                    SC_log_error(func, option, stmt);
                }
                if (conn)
                {
-                   CC_set_error(conn, STMT_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Set)");
+                   CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Set)", func);
                    sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
                    CC_log_error(func, option, conn);
                }
@@ -297,11 +266,11 @@ set_statement_option(ConnectionClass *conn,
    {
        if (stmt)
        {
-           SC_set_error(stmt, STMT_OPTION_VALUE_CHANGED, "Requested value changed.");
+           SC_set_error(stmt, STMT_OPTION_VALUE_CHANGED, "Requested value changed.", func);
        }
        if (conn)
        {
-           CC_set_error(conn, STMT_OPTION_VALUE_CHANGED, "Requested value changed.");
+           CC_set_error(conn, CONN_OPTION_VALUE_CHANGED, "Requested value changed.", func);
        }
        return SQL_SUCCESS_WITH_INFO;
    }
@@ -312,17 +281,17 @@ set_statement_option(ConnectionClass *conn,
 
 /* Implements only SQL_AUTOCOMMIT */
 RETCODE        SQL_API
-PGAPI_SetConnectOption(HDBC hdbc,
-           SQLUSMALLINT fOption, 
-           SQLPOINTER vParam)
+PGAPI_SetConnectOption(
+                      HDBC hdbc,
+                      SQLUSMALLINT fOption,
+                      SQLULEN vParam)
 {
    CSTR func = "PGAPI_SetConnectOption";
    ConnectionClass *conn = (ConnectionClass *) hdbc;
    char        changed = FALSE;
    RETCODE     retval;
-   int         i;
 
-   mylog("%s: entering fOption = %d vParam = %d\n", func, fOption, (unsigned long) vParam);
+   mylog("%s: entering fOption = %d vParam = %d\n", func, fOption, vParam);
    if (!conn)
    {
        CC_log_error(func, "", NULL);
@@ -349,18 +318,23 @@ PGAPI_SetConnectOption(HDBC hdbc,
        case SQL_SIMULATE_CURSOR:
        case SQL_USE_BOOKMARKS:
 
-           /* Affect all current Statements */
-           for (i = 0; i < conn->num_stmts; i++)
+#if (ODBCVER < 0x0300)
            {
-               if (conn->stmts[i])
-                   set_statement_option(NULL, conn->stmts[i], fOption, (UDWORD) ((unsigned long) vParam));
+               int i;
+               /* Affect all current Statements */
+               for (i = 0; i < conn->num_stmts; i++)
+               {
+                   if (conn->stmts[i])
+                       set_statement_option(NULL, conn->stmts[i], fOption, vParam);
+               }
            }
+#endif /* ODBCVER */
 
            /*
             * Become the default for all future statements on this
             * connection
             */
-           retval = set_statement_option(conn, NULL, fOption, (UDWORD) ((unsigned long) vParam));
+           retval = set_statement_option(conn, NULL, fOption, vParam);
 
            if (retval == SQL_SUCCESS_WITH_INFO)
                changed = TRUE;
@@ -377,16 +351,16 @@ PGAPI_SetConnectOption(HDBC hdbc,
            break;
 
        case SQL_AUTOCOMMIT:
-           if (vParam == (SQLPOINTER) SQL_AUTOCOMMIT_ON && CC_is_in_autocommit(conn))
+           if (vParam == SQL_AUTOCOMMIT_ON && CC_is_in_autocommit(conn))
                break;
-           else if (vParam == (SQLPOINTER) SQL_AUTOCOMMIT_OFF && !CC_is_in_autocommit(conn))
+           else if (vParam == SQL_AUTOCOMMIT_OFF && !CC_is_in_autocommit(conn))
                break;
            if (CC_is_in_trans(conn))
                CC_commit(conn);
 
            mylog("PGAPI_SetConnectOption: AUTOCOMMIT: transact_status=%d, vparam=%d\n", conn->transact_status, vParam);
 
-           switch ((unsigned long) vParam)
+           switch (vParam)
            {
                case SQL_AUTOCOMMIT_OFF:
                    CC_set_autocommit_off(conn);
@@ -397,8 +371,7 @@ PGAPI_SetConnectOption(HDBC hdbc,
                    break;
 
                default:
-                   CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "Illegal parameter value for SQL_AUTOCOMMIT");
-                   CC_log_error(func, "", conn);
+                   CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "Illegal parameter value for SQL_AUTOCOMMIT", func);
                    return SQL_ERROR;
            }
            break;
@@ -419,13 +392,12 @@ PGAPI_SetConnectOption(HDBC hdbc,
            retval = SQL_SUCCESS;
                         if (CC_is_in_trans(conn))
            {
-               CC_set_error(conn, CONN_TRANSACT_IN_PROGRES, "Cannot switch isolation level while a transaction is in progress");
-               CC_log_error(func, "", conn);
+               CC_set_error(conn, CONN_TRANSACT_IN_PROGRES, "Cannot switch isolation level while a transaction is in progress", func);
                return SQL_ERROR;
            }
-           if (conn->isolation == (unsigned long) vParam)
+           if (conn->isolation == vParam)
                break; 
-           switch ((unsigned long) vParam)
+           switch (vParam)
            {
                case SQL_TXN_SERIALIZABLE:
                    if (PG_VERSION_GE(conn, 6.5) &&
@@ -441,8 +413,7 @@ PGAPI_SetConnectOption(HDBC hdbc,
            }
            if (SQL_ERROR == retval)
            {
-               CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "Illegal parameter value for SQL_TXN_ISOLATION");
-               CC_log_error(func, "", conn);
+               CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "Illegal parameter value for SQL_TXN_ISOLATION", func);
                return SQL_ERROR;
            }
            else
@@ -450,20 +421,19 @@ PGAPI_SetConnectOption(HDBC hdbc,
                char *query;
                QResultClass *res;
 
-               if (vParam == (SQLPOINTER) SQL_TXN_SERIALIZABLE)
+               if (vParam == SQL_TXN_SERIALIZABLE)
                    query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE";
                else
                    query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED";
-               res = CC_send_query(conn, query, NULL, 0);
-               if (!res || !QR_command_maybe_successful(res))
+               res = CC_send_query(conn, query, NULL, 0, NULL);
+               if (!QR_command_maybe_successful(res))
                    retval = SQL_ERROR;
                else
-                   conn->isolation = (SQLUINTEGER) ((unsigned long) vParam);
-               if (res)
-                   QR_Destructor(res);
+                   conn->isolation = vParam;
+               QR_Destructor(res);
                if (SQL_ERROR == retval)
                {
-                   CC_set_error(conn, STMT_EXEC_ERROR, "ISOLATION change request to the server error");
+                   CC_set_error(conn, CONN_EXEC_ERROR, "ISOLATION change request to the server error", func);
                    return SQL_ERROR;
                }
            }
@@ -482,23 +452,21 @@ PGAPI_SetConnectOption(HDBC hdbc,
            {
                char        option[64];
 
-               CC_set_error(conn, CONN_UNSUPPORTED_OPTION, "Unknown connect option (Set)");
-               sprintf(option, "fOption=%d, vParam=%ld", fOption, (unsigned long) vParam);
+               CC_set_error(conn, CONN_UNSUPPORTED_OPTION, "Unknown connect option (Set)", func);
+               sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
                if (fOption == 30002 && vParam)
                {
                    int cmp;
-#ifdef UNICODE_SUPPORT
-                   char *asPara;
+#ifdef UNICODE_SUPPORT
                    if (conn->unicode)
                    {
-                       asPara = ucs2_to_utf8((SQLWCHAR *) vParam, -1, NULL, FALSE);
+                       char *asPara = ucs2_to_utf8((SQLWCHAR *) vParam, SQL_NTS, NULL, FALSE);
                        cmp = strcmp(asPara, "Microsoft Jet");
                        free(asPara);
                    }
                    else
-#endif
-                       cmp = strncmp((char *) vParam, "Microsoft Jet", 13);
-                   
+#endif /* UNICODE_SUPPORT */
+                   cmp = strncmp((char *) vParam, "Microsoft Jet", 13);
                    if (0 == cmp)
                    {
                        mylog("Microsoft Jet !!!!\n");
@@ -514,7 +482,7 @@ PGAPI_SetConnectOption(HDBC hdbc,
 
    if (changed)
    {
-       CC_set_error(conn, CONN_OPTION_VALUE_CHANGED, "Requested value changed.");
+       CC_set_error(conn, CONN_OPTION_VALUE_CHANGED, "Requested value changed.", func);
        return SQL_SUCCESS_WITH_INFO;
    }
    else
@@ -526,7 +494,7 @@ PGAPI_SetConnectOption(HDBC hdbc,
 RETCODE        SQL_API
 PGAPI_GetConnectOption(
                       HDBC hdbc,
-                      UWORD fOption,
+                      SQLUSMALLINT fOption,
                       PTR pvParam)
 {
    CSTR func = "PGAPI_GetConnectOption";
@@ -584,6 +552,13 @@ PGAPI_GetConnectOption(
            mylog(" val=%d\n", *((SQLUINTEGER *) pvParam));
                         break;
 
+#if (ODBCVER >= 0x0351)
+       case SQL_ATTR_ANSI_APP:
+           *((SQLUINTEGER *) pvParam) = CC_is_in_ansi_app(conn);
+           mylog("ANSI_APP val=%d\n", *((SQLUINTEGER *) pvParam));
+                        break;
+#endif /* ODBCVER */
+
            /* These options should be handled by driver manager */
        case SQL_ODBC_CURSORS:
        case SQL_OPT_TRACE:
@@ -597,7 +572,7 @@ PGAPI_GetConnectOption(
            {
                char        option[64];
 
-               CC_set_error(conn, CONN_UNSUPPORTED_OPTION, "Unknown connect option (Get)");
+               CC_set_error(conn, CONN_UNSUPPORTED_OPTION, "Unknown connect option (Get)", func);
                sprintf(option, "fOption=%d", fOption);
                CC_log_error(func, option, conn);
                return SQL_ERROR;
@@ -610,12 +585,14 @@ PGAPI_GetConnectOption(
 
 
 RETCODE        SQL_API
-PGAPI_SetStmtOption(HSTMT hstmt,
-           SQLUSMALLINT fOption, 
-           SQLUINTEGER vParam)
+PGAPI_SetStmtOption(
+                   HSTMT hstmt,
+                   SQLUSMALLINT fOption,
+                   SQLULEN vParam)
 {
    CSTR func = "PGAPI_SetStmtOption";
    StatementClass *stmt = (StatementClass *) hstmt;
+   RETCODE retval;
 
    mylog("%s: entering...\n", func);
 
@@ -630,19 +607,24 @@ PGAPI_SetStmtOption(HSTMT hstmt,
        return SQL_INVALID_HANDLE;
    }
 
-   return set_statement_option(NULL, stmt, fOption, vParam);
+   /* StartRollbackState(stmt); */
+   retval = set_statement_option(NULL, stmt, fOption, vParam);
+   if (stmt->internal)
+       retval = DiscardStatementSvp(stmt, retval, FALSE);
+   return retval;
 }
 
 
 RETCODE        SQL_API
 PGAPI_GetStmtOption(
                    HSTMT hstmt,
-                   UWORD fOption,
+                   SQLUSMALLINT fOption,
                    PTR pvParam)
 {
    CSTR func = "PGAPI_GetStmtOption";
    StatementClass *stmt = (StatementClass *) hstmt;
    QResultClass *res;
+   ConnInfo   *ci = &(SC_get_conn(stmt)->connInfo);
    int ridx;
 
    mylog("%s: entering...\n", func);
@@ -666,20 +648,18 @@ PGAPI_GetStmtOption(
            res = SC_get_Curres(stmt);
            if (!res)
            {
-               SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The cursor has no result.");
-               SC_log_error(func, "", stmt);
+               SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The cursor has no result.", func);
                return SQL_ERROR;
            }
 
-           ridx = GIdx2ResultIdx(stmt->currTuple, stmt, res);
-           if (stmt->manual_result || !SC_is_fetchcursor(stmt))
+           ridx = GIdx2CacheIdx(stmt->currTuple, stmt, res);
+           if (!SC_is_fetchcursor(stmt))
            {
                /* make sure we're positioned on a valid row */
                if ((ridx < 0) ||
-                   (ridx >= QR_get_num_backend_tuples(res)))
+                   (ridx >= QR_get_num_cached_tuples(res)))
                {
-                   SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row.");
-                   SC_log_error(func, "", stmt);
+                   SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row.", func);
                    return SQL_ERROR;
                }
            }
@@ -687,16 +667,14 @@ PGAPI_GetStmtOption(
            {
                if (stmt->currTuple < 0 || !res->tupleField)
                {
-                   SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row.");
-                   SC_log_error(func, "", stmt);
+                   SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row.", func);
                    return SQL_ERROR;
                }
            }
 
            if (fOption == SQL_GET_BOOKMARK && stmt->options.use_bookmarks == SQL_UB_OFF)
            {
-               SC_set_error(stmt, STMT_OPERATION_INVALID, "Operation invalid because use bookmarks not enabled.");
-               SC_log_error(func, "", stmt);
+               SC_set_error(stmt, STMT_OPERATION_INVALID, "Operation invalid because use bookmarks not enabled.", func);
                return SQL_ERROR;
            }
 
@@ -764,7 +742,7 @@ PGAPI_GetStmtOption(
            {
                char        option[64];
 
-               SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Get)");
+               SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Get)", NULL);
                sprintf(option, "fOption=%d", fOption);
                SC_log_error(func, option, stmt);
                return SQL_ERROR;
diff --git a/parse.c b/parse.c
index 18dea61d8805d91e53a819a35702b0956fca12a8..d21f28f6aa74ffb702cf2274c4c5b6c877d706b0 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -33,6 +33,7 @@
 #include "qresult.h"
 #include "pgtypes.h"
 #include "pgapifunc.h"
+#include "catfunc.h"
 
 #include "multibyte.h"
 
@@ -40,9 +41,9 @@
 #define TAB_INCR   8
 #define COL_INCR   16
 
-char      *getNextToken(int ccsc, char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric);
-void       getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
-char       searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
+static char    *getNextToken(int ccsc, char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric);
+static void    getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
+static char    searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
 
 Int4 FI_precision(const FIELD_INFO *fi)
 {
@@ -74,10 +75,11 @@ getNextToken(
    char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric)
 {
    int         i = 0;
-   int         out = 0;
-   char        qc,
-               in_escape = FALSE;
+   int     out = 0, taglen;
+   char        qc, in_quote, in_dollar_quote, in_escape;
+   const   char    *tag, *tagend;
    encoded_str encstr;
+   char    literal_quote = LITERAL_QUOTE, identifier_quote = IDENTIFIER_QUOTE, escape_in_literal = ESCAPE_IN_LITERAL, dollar_quote = '$';
 
    if (smax <= 1)
        return NULL;
@@ -117,21 +119,38 @@ getNextToken(
        if (isspace((UCHAR) s[i]) || s[i] == ',')
            break;
        /* Handle quoted stuff */
-       if (out == 0 && (s[i] == '\"' || s[i] == '\''))
+       in_quote = in_dollar_quote = FALSE;
+       if (out == 0)
        {
            qc = s[i];
-           if (qc == '\"')
+           if (qc == dollar_quote)
            {
-               if (dquote)
-                   *dquote = TRUE;
+               in_quote = in_dollar_quote = TRUE;
+               tag = s + i;
+               taglen = 1;
+               if (tagend = strchr(s + i + 1, dollar_quote))
+                   taglen = tagend - s - i + 1;
+               i += (taglen - 1);
+               if (quote)
+                   *quote = TRUE;
            }
-           if (qc == '\'')
+           else if (qc == literal_quote)
            {
+               in_quote = TRUE;
                if (quote)
                    *quote = TRUE;
            }
-
+           else if (qc == identifier_quote)
+           {
+               in_quote = TRUE;
+               if (dquote)
+                   *dquote = TRUE;
+           }
+       }
+       if (in_quote)
+       {
            i++;                /* dont return the quote */
+           in_escape = FALSE;
            while (s[i] != '\0' && out != smax)
            {
                encoded_nextchar(&encstr);
@@ -140,13 +159,23 @@ getNextToken(
                    token[out++] = s[i++];
                    continue;
                }
-               if (s[i] == qc && !in_escape)
-                   break;
-               if (s[i] == '\\' && !in_escape)
+               if (in_escape)
+                   in_escape = FALSE;
+               else if (s[i] == qc)
+               {
+                   if (!in_dollar_quote)
+                       break;
+                   if (strncmp(s + i, tag, taglen) == 0)
+                   {
+                       i += (taglen - 1);
+                       break;
+                   }
+                   token[out++] = s[i];
+               }
+               else if (literal_quote == qc && s[i] == escape_in_literal)
                    in_escape = TRUE;
                else
                {
-                   in_escape = FALSE;
                    token[out++] = s[i];
                }
                i++;
@@ -219,46 +248,24 @@ getNextToken(
    return &s[i];
 }
 
-
-#if 0
-QR_set_num_fields(SC_get_Curres(stmt), 14);
-QR_set_field_info(SC_get_Curres(stmt), 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 4, "DATA_TYPE", PG_TYPE_INT2, 2);
-QR_set_field_info(SC_get_Curres(stmt), 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 6, "PRECISION", PG_TYPE_INT4, 4);
-QR_set_field_info(SC_get_Curres(stmt), 7, "LENGTH", PG_TYPE_INT4, 4);
-QR_set_field_info(SC_get_Curres(stmt), 8, "SCALE", PG_TYPE_INT2, 2);
-QR_set_field_info(SC_get_Curres(stmt), 9, "RADIX", PG_TYPE_INT2, 2);
-QR_set_field_info(SC_get_Curres(stmt), 10, "NULLABLE", PG_TYPE_INT2, 2);
-QR_set_field_info(SC_get_Curres(stmt), 11, "REMARKS", PG_TYPE_TEXT, 254);
-/* User defined fields */
-QR_set_field_info(SC_get_Curres(stmt), 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
-QR_set_field_info(SC_get_Curres(stmt), 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
-#endif
-
 void
 getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
 {
    char       *str;
-   Int2    reserved_cols;
-
-   reserved_cols = 18;
 
-   if (fi->name[0] == '\0')
-       strcpy(fi->name, QR_get_value_manual(col_info->result, k, 3));
+inolog("getColInfo non-manual result\n");
+   STR_TO_NAME(fi->column_name, QR_get_value_backend_row(col_info->result, k, COLUMNS_COLUMN_NAME));
 
-   fi->type = atoi(QR_get_value_manual(col_info->result, k, (Int2)(reserved_cols + 1)));
-   fi->column_size = atoi(QR_get_value_manual(col_info->result, k, 6));
-   fi->length = atoi(QR_get_value_manual(col_info->result, k, 7));
-   if (str = QR_get_value_manual(col_info->result, k, 8), str)
+   fi->type = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_FIELD_TYPE));
+   fi->column_size = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_PRECISION));
+   fi->length = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_LENGTH));
+   if (str = QR_get_value_backend_row(col_info->result, k, COLUMNS_SCALE), str)
        fi->decimal_digits = atoi(str);
    else
        fi->decimal_digits = -1;
-   fi->nullable = atoi(QR_get_value_manual(col_info->result, k, 10));
-   fi->display_size = atoi(QR_get_value_manual(col_info->result, k, reserved_cols));
+   fi->nullable = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_NULLABLE));
+   fi->display_size = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_DISPLAY_SIZE));
+   fi->auto_increment = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_AUTO_INCREMENT));
 }
 
 
@@ -269,21 +276,26 @@ searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
                cmp;
    char       *col;
 
-   for (k = 0; k < QR_get_num_backend_tuples(col_info->result); k++)
+inolog("searchColInfo %d\n", QR_get_num_cached_tuples(col_info->result));
+   for (k = 0; k < QR_get_num_cached_tuples(col_info->result); k++)
    {
-       col = QR_get_value_manual(col_info->result, k, 3);
-       if (fi->dquote)
-           cmp = strcmp(col, fi->name);
-       else
-           cmp = stricmp(col, fi->name);
-       if (!cmp)
+       col = QR_get_value_backend_row(col_info->result, k, COLUMNS_COLUMN_NAME);
+inolog("searchColInfo %d col=%s\n", k, col);
+       if (NAME_IS_VALID(fi->column_name))
        {
-           if (!fi->dquote)
-               strcpy(fi->name, col);
-           getColInfo(col_info, fi, k);
+           if (fi->dquote)
+               cmp = strcmp(col, GET_NAME(fi->column_name));
+           else
+               cmp = stricmp(col, GET_NAME(fi->column_name));
+           if (!cmp)
+           {
+               if (!fi->dquote)
+                   STR_TO_NAME(fi->column_name, col);
+               getColInfo(col_info, fi, k);
 
-           mylog("PARSE: searchColInfo: \n");
-           return TRUE;
+               mylog("PARSE: searchColInfo: \n");
+               return TRUE;
+           }
        }
    }
 
@@ -312,8 +324,76 @@ void lower_the_name(char *name, ConnectionClass *conn, BOOL dquote)
    }
 }
 
+static BOOL CheckHasOids(StatementClass * stmt)
+{
+   QResultClass    *res;
+   BOOL        hasoids = TRUE, foundKey = FALSE;
+   char        query[512];
+   ConnectionClass *conn = SC_get_conn(stmt);
+   TABLE_INFO  *ti;
+
+   if (0 != SC_checked_hasoids(stmt))
+       return TRUE;
+   if (!stmt->ti || !stmt->ti[0])
+       return FALSE;
+   ti = stmt->ti[0];
+   sprintf(query, "select relhasoids, c.oid from pg_class c, pg_namespace n where relname = '%s' and nspname = '%s' and c.relnamespace = n.oid", SAFE_NAME(ti->table_name), SAFE_NAME(ti->schema_name));
+   res = CC_send_query(conn, query, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+   if (QR_command_maybe_successful(res))
+   {
+       stmt->num_key_fields = PG_NUM_NORMAL_KEYS;
+       if (1 == QR_get_num_total_tuples(res))
+       {
+           char *value = QR_get_value_backend_row(res, 0, 0);
+           if (value && ('f' == *value || '0' == *value))
+           {
+               hasoids = FALSE;
+               TI_set_has_no_oids(ti);
+           }
+           else
+           {
+               TI_set_hasoids(ti);
+               foundKey = TRUE;
+               STR_TO_NAME(ti->bestitem, OID_NAME);
+               strcpy(query, "\"oid\" = %u");
+               /*strcpy(query, "\"oid\" = %%u");*/
+               STR_TO_NAME(ti->bestqual, query);
+           }
+           TI_set_hasoids_checked(ti);
+           ti->table_oid = strtoul(QR_get_value_backend_row(res, 0, 1), NULL, 10);
+       }
+       QR_Destructor(res);
+       res = NULL;
+       if (!hasoids)
+       {
+           sprintf(query, "select a.attname, a.atttypid from pg_index i, pg_attribute a where indrelid=%u and indnatts=1 and indisunique and indexprs is null and indpred is null and i.indrelid = a.attrelid and a.attnum=i.indkey[0] and attnotnull and atttypid in (%d, %d)", ti->table_oid, PG_TYPE_INT4, PG_TYPE_OID);
+           res = CC_send_query(conn, query, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+           if (QR_command_maybe_successful(res) && QR_get_num_total_tuples(res) > 0)
+           {
+               foundKey = TRUE;
+               STR_TO_NAME(ti->bestitem, QR_get_value_backend_row(res, 0, 0));
+               sprintf(query, "\"%s\" = %%", SAFE_NAME(ti->bestitem));
+               if (PG_TYPE_INT4 == atoi(QR_get_value_backend_row(res, 0, 1)))
+                   strcat(query, "d");
+               else
+                   strcat(query, "u");
+               STR_TO_NAME(ti->bestqual, query);
+           }
+           else
+           {
+               /* stmt->updatable = FALSE; */
+               foundKey = TRUE;
+               stmt->num_key_fields--;
+           }
+       }
+   }
+   QR_Destructor(res);
+   SC_set_checked_hasoids(stmt, foundKey); 
+   return TRUE;
+}
+   
 char
-parse_statement(StatementClass *stmt)
+parse_statement(StatementClass *stmt, BOOL check_hasoids)
 {
    CSTR        func = "parse_statement";
    char        token[256], stoken[256];
@@ -334,16 +414,16 @@ parse_statement(StatementClass *stmt)
    char        in_field = FALSE,
                in_expr = FALSE,
                in_func = FALSE,
-                out_func = FALSE,
                in_dot = FALSE,
                in_as = FALSE;
    int         j,
                i,
                k = 0,
                n,
-               blevel = 0, old_blevel, subqlevel = 0;
-   FIELD_INFO **fi;
-   TABLE_INFO **ti;
+               blevel = 0, old_blevel, subqlevel = 0,
+               nfields_old, allocated_size, new_size;
+   FIELD_INFO **fi, *wfi;
+   TABLE_INFO **ti, *wti;
    char        parse;
    ConnectionClass *conn = stmt->hdbc;
    HSTMT       hcol_stmt;
@@ -352,15 +432,24 @@ parse_statement(StatementClass *stmt)
    RETCODE     result;
    BOOL        updatable = TRUE;
 
-   QResultClass*   resultClass;
-
    mylog("%s: entering...\n", func);
 
+   if (SC_parsed_status(stmt) != STMT_PARSE_NONE)
+   {
+       if (check_hasoids)
+           CheckHasOids(stmt);
+       return TRUE;
+   }
+   stmt->updatable = FALSE;
    ptr = stmt->statement;
    fi = irdflds->fi;
    ti = stmt->ti;
 
+   allocated_size = 0;
+   nfields_old = irdflds->nfields;
    irdflds->nfields = 0;
+   if (nfields_old > 0)
+       allocated_size = ((nfields_old - 1) / FLD_INCR + 1) * FLD_INCR;
    stmt->ntab = 0;
    stmt->from_pos = -1;
    stmt->where_pos = -1;
@@ -389,7 +478,7 @@ parse_statement(StatementClass *stmt)
                    in_select = FALSE;
                    mylog("INTO\n");
                    stmt->statement_type = STMT_TYPE_CREATE;
-                   stmt->parse_status = STMT_PARSE_FATAL;
+                   SC_set_parse_status(stmt, STMT_PARSE_FATAL);
                    return FALSE;
                }
                else if (!stricmp(token, "from"))
@@ -528,58 +617,70 @@ parse_statement(StatementClass *stmt)
 
            if (!in_field)
            {
+               BOOL    fi_reuse = FALSE;
+
                if (!token[0])
                    continue;
 
-               if (!(irdflds->nfields % FLD_INCR))
+               /* if (!(irdflds->nfields % FLD_INCR)) */
+               if (irdflds->nfields >= allocated_size)
                {
                    mylog("reallocing at nfld=%d\n", irdflds->nfields);
-                   fi = (FIELD_INFO **) realloc(fi, (irdflds->nfields + FLD_INCR) * sizeof(FIELD_INFO *));
+                   new_size = (irdflds->nfields / FLD_INCR + 1) * FLD_INCR;
+                   fi = (FIELD_INFO **) realloc(fi, new_size * sizeof(FIELD_INFO *));
                    if (!fi)
                    {
-                       stmt->parse_status = STMT_PARSE_FATAL;
+                       SC_set_parse_status(stmt, STMT_PARSE_FATAL);
                        return FALSE;
                    }
+                   allocated_size = new_size;
                    irdflds->fi = fi;
                }
 
-               fi[irdflds->nfields] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
-               if (fi[irdflds->nfields] == NULL)
+               wfi = NULL;
+               if (irdflds->nfields < nfields_old)
+                   wfi = fi[irdflds->nfields];
+               if (wfi)
+                   fi_reuse = TRUE;
+               else
+                   wfi = fi[irdflds->nfields] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
+               if (wfi == NULL)
                {
-                   stmt->parse_status = STMT_PARSE_FATAL;
+                   SC_set_parse_status(stmt, STMT_PARSE_FATAL);
                    return FALSE;
                }
 
                /* Initialize the field info */
-               memset(fi[irdflds->nfields], 0, sizeof(FIELD_INFO));
+               FI_Constructor(wfi, fi_reuse);
+               wfi->flag = FIELD_PARSING;
 
                /* double quotes are for qualifiers */
                if (dquote)
-                   fi[irdflds->nfields]->dquote = TRUE;
+                   wfi->dquote = TRUE;
 
                if (quote)
                {
-                   fi[irdflds->nfields]->quote = TRUE;
-                   fi[irdflds->nfields]->column_size = strlen(token);
+                   wfi->quote = TRUE;
+                   wfi->column_size = strlen(token);
                }
                else if (numeric)
                {
                    mylog("**** got numeric: nfld = %d\n", irdflds->nfields);
-                   fi[irdflds->nfields]->numeric = TRUE;
+                   wfi->numeric = TRUE;
                }
                else if (0 == old_blevel && blevel > 0)
                {               /* expression */
                    mylog("got EXPRESSION\n");
-                   fi[irdflds->nfields++]->expr = TRUE;
+                   wfi->expr = TRUE;
                    in_expr = TRUE;
                    continue;
                }
                else
                {
-                   strcpy(fi[irdflds->nfields]->name, token);
-                   fi[irdflds->nfields]->dot[0] = '\0';
+                   STR_TO_NAME(wfi->column_name, token);
+                   NULL_THE_NAME(wfi->before_dot);
                }
-               mylog("got field='%s', dot='%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->dot);
+               mylog("got field='%s', dot='%s'\n", PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->before_dot));
 
                if (delim == ',')
                    mylog("comma (1)\n");
@@ -592,16 +693,15 @@ parse_statement(StatementClass *stmt)
            /*
             * We are in a field now
             */
+           wfi = fi[irdflds->nfields - 1];
            if (in_dot)
            {
-               int ifld = irdflds->nfields - 1;
-
-               if (fi[ifld]->dot[0])
+               if (NAME_IS_VALID(wfi->before_dot))
                {
-                   fi[ifld]->schema = strdup(fi[ifld]->dot);
+                   MOVE_NAME(wfi->schema_name, wfi->before_dot);
                }
-               strcpy(fi[ifld]->dot, fi[ifld]->name);
-               strcpy(fi[ifld]->name, token);
+               MOVE_NAME(wfi->before_dot, wfi->column_name);
+               STR_TO_NAME(wfi->column_name, token);
 
                if (delim == ',')
                {
@@ -614,14 +714,11 @@ parse_statement(StatementClass *stmt)
 
            if (in_as)
            {
-               irdflds->nfields--;
-               strcpy(fi[irdflds->nfields]->alias, token);
-               mylog("alias for field '%s' is '%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->alias);
+               STR_TO_NAME(wfi->column_alias, token);
+               mylog("alias for field '%s' is '%s'\n", PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->column_alias));
                in_as = FALSE;
                in_field = FALSE;
 
-               irdflds->nfields++;
-
                if (delim == ',')
                    mylog("comma(2)\n");
                continue;
@@ -632,13 +729,13 @@ parse_statement(StatementClass *stmt)
            {
                in_dot = FALSE;
                in_func = TRUE;
-               fi[irdflds->nfields - 1]->func = TRUE;
+               wfi->func = TRUE;
 
                /*
                 * name will have the function name -- maybe useful some
                 * day
                 */
-               mylog("**** got function = '%s'\n", fi[irdflds->nfields - 1]->name);
+               mylog("**** got function = '%s'\n", PRINT_NAME(wfi->column_name));
                continue;
            }
 
@@ -659,9 +756,9 @@ parse_statement(StatementClass *stmt)
 
            /* otherwise, it's probably an expression */
            in_expr = TRUE;
-           fi[irdflds->nfields - 1]->expr = TRUE;
-           fi[irdflds->nfields - 1]->name[0] = '\0';
-           fi[irdflds->nfields - 1]->column_size = 0;
+           wfi->expr = TRUE;
+           NULL_THE_NAME(wfi->column_name);
+           wfi->column_size = 0;
            mylog("*** setting expression\n");
        } /* in_select end */
 
@@ -680,57 +777,35 @@ parse_statement(StatementClass *stmt)
                    out_table = TRUE; 
                    continue;
            }
-           if (out_table && !in_table && !in_func) /* new table */
+           if (out_table && !in_table) /* new table */
            {
                if (!dquote)
                {
                    if (token[0] == '(' ||
                        token[0] == ')')
                        continue;
-                    
-                   /* 
-                    * Detect a function call that looks like a table, eg.
-                    *   SELECT * FROM version()
-                    * 
-                    * This needs work to properly handle functions found in the from
-                    * clause, but this at least prevents nasty errors for now.
-                    *
-                    * DJP, 2005-01-08
-                    */
-                   if (ptr[0] == '(')
-                   {
-                        in_func = TRUE;
-                       mylog("**** got function = '%s'\n", token);
-                       mylog("FIXME: functions in the FROM clause are currently ignored!!\n");
-                       continue;
-                   }
                }
-                
-            
                if (!(stmt->ntab % TAB_INCR))
                {
                    ti = (TABLE_INFO **) realloc(ti, (stmt->ntab + TAB_INCR) * sizeof(TABLE_INFO *));
                    if (!ti)
                    {
-                       stmt->parse_status = STMT_PARSE_FATAL;
+                       SC_set_parse_status(stmt, STMT_PARSE_FATAL);
                        return FALSE;
                    }
                    stmt->ti = ti;
                }
-               ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
-               if (ti[stmt->ntab] == NULL)
+               wti = ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
+               if (wti == NULL)
                {
-                   stmt->parse_status = STMT_PARSE_FATAL;
+                   SC_set_parse_status(stmt, STMT_PARSE_FATAL);
                    return FALSE;
                }
 
-               ti[stmt->ntab]->schema[0] = '\0';
-               ti[stmt->ntab]->alias[0] = '\0';
-               ti[stmt->ntab]->updatable = 1;
-
-               strcpy(ti[stmt->ntab]->name, token);
-               lower_the_name(ti[stmt->ntab]->name, conn, dquote);
-               mylog("got table = '%s'\n", ti[stmt->ntab]->name);
+               TI_Constructor(wti, conn);
+               STR_TO_NAME(wti->table_name, token);
+               lower_the_name(GET_NAME(wti->table_name), conn, dquote);
+               mylog("got table = '%s'\n", PRINT_NAME(wti->table_name));
 
                if (delim == ',')
                {
@@ -747,64 +822,6 @@ parse_statement(StatementClass *stmt)
                continue;
            }
 
-           if (out_table && !in_table && in_func) /* old function */
-           {
-                /* Just skipped a function alias */
-                if (out_func)
-                {
-                    in_func = FALSE;
-                    out_func = FALSE;
-                    mylog("leaving func (and ignoring alias)\n");
-                    continue;
-                }
-                
-                /* Normal function, no alias */
-                if (token[0] == ')' && (ptr[0] == ',' || strlen(ptr) == 0))
-                {
-                    in_func = FALSE;
-                    
-                    /* 
-                     * TODO: shouldn't we cache the metadata somewhere? 
-                     */
-                    SC_pre_execute(stmt);
-                   resultClass = SC_get_Curres(stmt);
-
-                   mylog("PGAPI_NumResultCols: result = %u, status = %d, numcols = %d\n", resultClass, stmt->status, resultClass!= NULL ? QR_NumResultCols(resultClass) : -1);
-                   if ((!resultClass) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
-                   {
-                       /* no query has been executed on this statement */
-                       SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been executed with that handle");
-                       SC_log_error(func, "", stmt);
-                       return SQL_ERROR;
-                   }
-                   else if (!QR_command_maybe_successful(resultClass))
-                   {
-                       SC_set_errornumber(stmt, STMT_EXEC_ERROR);
-                       SC_log_error(func, "", stmt);
-                       return SQL_ERROR;
-                   }
-                   /* 
-                    * If the parse_statement is called to get the number of 
-                    * result columns throught SQLColAttribute. 
-                    */
-                   irdflds->nfields = QR_NumPublicResultCols(resultClass);                    
-                    
-                    mylog("leaving func.\n");
-                    
-                    stmt->parse_status = STMT_PARSE_FATAL;
-                   return  FALSE;
-                }
-                
-                /* Function with following alias */
-                if (token[0] == ')')
-                {
-                    out_func = TRUE;
-                    continue;
-                }
-                    
-                
-            }
-            
            if (!dquote && stricmp(token, "JOIN") == 0)
            {
                in_table = FALSE;
@@ -813,11 +830,12 @@ parse_statement(StatementClass *stmt)
            }
            if (in_table)
            {
+               wti = ti[stmt->ntab - 1];
                if (in_dot)
                {
-                   strcpy(ti[stmt->ntab - 1]->schema, ti[stmt->ntab - 1]->name);
-                   strcpy(ti[stmt->ntab - 1]->name, token);
-                   lower_the_name(ti[stmt->ntab - 1]->name, conn, dquote);
+                   MOVE_NAME(wti->schema_name, wti->table_name);
+                   STR_TO_NAME(wti->table_name, token);
+                   lower_the_name(GET_NAME(wti->table_name), conn, dquote);
                    in_dot = FALSE;
                    continue;
                }
@@ -840,8 +858,8 @@ parse_statement(StatementClass *stmt)
                            continue;
                        }
                    }
-                   strcpy(ti[stmt->ntab - 1]->alias, token);
-                   mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab - 1]->name, ti[stmt->ntab - 1]->alias);
+                   STR_TO_NAME(wti->table_alias, token);
+                   mylog("alias for table '%s' is '%s'\n", PRINT_NAME(wti->table_name), PRINT_NAME(wti->table_alias));
                    in_table = FALSE;
                    if (delim == ',')
                    {
@@ -862,52 +880,54 @@ parse_statement(StatementClass *stmt)
    /* Resolve field names with tables */
    for (i = 0; i < (int) irdflds->nfields; i++)
    {
-       if (fi[i]->func || fi[i]->expr || fi[i]->numeric)
+       wfi = fi[i];
+       if (wfi->func || wfi->expr || wfi->numeric)
        {
-           fi[i]->ti = NULL;
-           fi[i]->type = -1;
+           wfi->ti = NULL;
+           wfi->type = -1;
            parse = FALSE;
            continue;
        }
-       else if (fi[i]->quote)
+       else if (wfi->quote)
        {                       /* handle as text */
-           fi[i]->ti = NULL;
+           wfi->ti = NULL;
 
            /*
-            * fi[i]->type = PG_TYPE_TEXT; fi[i]->column_size = 0; the
+            * wfi->type = PG_TYPE_TEXT; wfi->column_size = 0; the
             * following may be better
             */
-           fi[i]->type = PG_TYPE_UNKNOWN;
-           if (fi[i]->column_size == 0)
+           wfi->type = PG_TYPE_UNKNOWN;
+           if (wfi->column_size == 0)
            {
-               fi[i]->type = PG_TYPE_VARCHAR;
-               fi[i]->column_size = 254;
+               wfi->type = PG_TYPE_VARCHAR;
+               wfi->column_size = 254;
            }
-           fi[i]->length = fi[i]->column_size;
+           wfi->length = wfi->column_size;
            continue;
        }
        /* field name contains the schema name */
-       else if (fi[i]->schema)
+       else if (NAME_IS_VALID(wfi->schema_name))
        {
            int matchidx = -1;
 
            for (k = 0; k < stmt->ntab; k++)
            {
-               if (!stricmp(ti[k]->name, fi[i]->dot))
+               wti = ti[k];
+               if (!NAMEICMP(wti->table_name, wfi->before_dot))
                {
-                   if (!stricmp(ti[k]->schema, fi[i]->schema))
+                   if (!NAMEICMP(wti->schema_name, wfi->schema_name))
                    {
-                       fi[i]->ti = ti[k];
+                       wfi->ti = wti;
                        break;
                    }
-                   else if (!ti[k]->schema[0])
+                   else if (NAME_IS_NULL(wti->schema_name))
                    {
                        if (matchidx < 0)
                            matchidx = k;
                        else
                        {
-                           stmt->parse_status = STMT_PARSE_FATAL;
-                           SC_set_error(stmt, STMT_EXEC_ERROR, "duplicated Table name");
+                           SC_set_parse_status(stmt, STMT_PARSE_FATAL);
+                           SC_set_error(stmt, STMT_EXEC_ERROR, "duplicated Table name", func);
                            stmt->updatable = FALSE;
                            return FALSE;
                        }
@@ -915,47 +935,51 @@ parse_statement(StatementClass *stmt)
                }
            }
            if (matchidx >= 0)
-               fi[i]->ti = ti[matchidx];
+               wfi->ti = ti[matchidx];
        }
        /* it's a dot, resolve to table or alias */
-       else if (fi[i]->dot[0])
+       else if (NAME_IS_VALID(wfi->before_dot))
        {
            for (k = 0; k < stmt->ntab; k++)
            {
-               if (!stricmp(ti[k]->alias, fi[i]->dot))
+               wti = ti[k];
+               if (!NAMEICMP(wti->table_alias, wfi->before_dot))
                {
-                   fi[i]->ti = ti[k];
+                   wfi->ti = wti;
                    break;
                }
-               else if (!stricmp(ti[k]->name, fi[i]->dot))
+               else if (!NAMEICMP(wti->table_name, wfi->before_dot))
                {
-                   fi[i]->ti = ti[k];
+                   wfi->ti = wti;
                    break;
                }
            }
        }
        else if (stmt->ntab == 1)
-           fi[i]->ti = ti[0];
+           wfi->ti = ti[0];
    }
 
    mylog("--------------------------------------------\n");
    mylog("nfld=%d, ntab=%d\n", irdflds->nfields, stmt->ntab);
    if (0 == stmt->ntab)
    {
-       stmt->parse_status = STMT_PARSE_FATAL;
+       SC_set_parse_status(stmt, STMT_PARSE_FATAL);
        return  FALSE;
    }
 
    for (i = 0; i < (int) irdflds->nfields; i++)
    {
-       mylog("Field %d:  expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n", i, fi[i]->expr, fi[i]->func, fi[i]->quote, fi[i]->dquote, fi[i]->numeric, fi[i]->name, fi[i]->alias, fi[i]->dot);
-       if (fi[i]->ti)
-           mylog("     ----> table_name='%s', table_alias='%s'\n", fi[i]->ti->name, fi[i]->ti->alias);
+       wfi = fi[i];
+       mylog("Field %d:  expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n", i, wfi->expr, wfi->func, wfi->quote, wfi->dquote, wfi->numeric, PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->column_alias), PRINT_NAME(wfi->before_dot));
+       if (wfi->ti)
+           mylog("     ----> table_name='%s', table_alias='%s'\n", PRINT_NAME(wfi->ti->table_name), PRINT_NAME(wfi->ti->table_alias));
    }
 
    for (i = 0; i < stmt->ntab; i++)
-       mylog("Table %d: name='%s', alias='%s'\n", i, ti[i]->name, ti[i]->alias);
-
+   {
+       wti = ti[i];
+       mylog("Table %d: name='%s', alias='%s'\n", i, PRINT_NAME(wti->table_name), PRINT_NAME(wti->table_alias));
+   }
 
    /*
     * Now save the SQLColumns Info for the parse tables
@@ -971,9 +995,10 @@ parse_statement(StatementClass *stmt)
        /* See if already got it */
        char        found = FALSE;
 
+       wti = ti[i];
        if (conn->schema_support)
        {
-           if (!ti[i]->schema[0])
+           if (NAME_IS_NULL(wti->schema_name))
            {
                const char *curschema = CC_get_current_schema(conn);
                /*
@@ -984,12 +1009,12 @@ parse_statement(StatementClass *stmt)
                 */
                for (k = 0; k < conn->ntables; k++)
                {
-                   if (!stricmp(conn->col_info[k]->name, ti[i]->name) &&
-                       !stricmp(conn->col_info[k]->schema, curschema))
+                   if (!NAMEICMP(conn->col_info[k]->table_name, wti->table_name) &&
+                       !stricmp(SAFE_NAME(conn->col_info[k]->schema_name), curschema))
                    {
-                       mylog("FOUND col_info table='%s' current schema='%s'\n", ti[i]->name, curschema);
+                       mylog("FOUND col_info table='%s' current schema='%s'\n", PRINT_NAME(wti->table_name), curschema);
                        found = TRUE;
-                       strcpy(ti[i]->schema, curschema);
+                       STR_TO_NAME(wti->schema_name, curschema);
                        break;
                    }
                }
@@ -1002,36 +1027,34 @@ parse_statement(StatementClass *stmt)
                     * We also have to check as follows.
                     */
                    sprintf(token, "select nspname from pg_namespace n, pg_class c"
-                       " where c.relnamespace=n.oid and c.oid='\"%s\"'::regclass", ti[i]->name);
-                   res = CC_send_query(conn, token, NULL, CLEAR_RESULT_ON_ABORT);
-                   if (res)
+                       " where c.relnamespace=n.oid and c.oid='\"%s\"'::regclass", SAFE_NAME(wti->table_name));
+                   res = CC_send_query(conn, token, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+                   if (QR_command_maybe_successful(res))
                    {
                        if (QR_get_num_total_tuples(res) == 1)
                        {
                            tblFound = TRUE;
-                           strcpy(ti[i]->schema, QR_get_value_backend_row(res, 0, 0));
+                           STR_TO_NAME(wti->schema_name, QR_get_value_backend_row(res, 0, 0));
                        }
-                       QR_Destructor(res);
                    }
-                   else
-                       CC_abort(conn);
+                   QR_Destructor(res);
                    if (!tblFound)
                    {
-                       stmt->parse_status = STMT_PARSE_FATAL;
-                       SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found");
+                       SC_set_parse_status(stmt, STMT_PARSE_FATAL);
+                       SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found", func);
                        stmt->updatable = FALSE;
                        return FALSE;
                    }
                }
            }
-           if (!found && ti[i]->schema[0])
+           if (!found && NAME_IS_VALID(wti->schema_name))
            {
                for (k = 0; k < conn->ntables; k++)
                {
-                   if (!stricmp(conn->col_info[k]->name, ti[i]->name) &&
-                       !stricmp(conn->col_info[k]->schema, ti[i]->schema))
+                   if (!NAMEICMP(conn->col_info[k]->table_name, wti->table_name) &&
+                       !NAMEICMP(conn->col_info[k]->schema_name, wti->schema_name))
                    {
-                       mylog("FOUND col_info table='%s' schema='%s'\n", ti[i]->name, ti[i]->schema);
+                       mylog("FOUND col_info table='%s' schema='%s'\n", PRINT_NAME(wti->table_name), PRINT_NAME(wti->schema_name));
                        found = TRUE;
                        break;
                    }
@@ -1042,9 +1065,9 @@ parse_statement(StatementClass *stmt)
        {
            for (k = 0; k < conn->ntables; k++)
            {
-               if (!stricmp(conn->col_info[k]->name, ti[i]->name))
+               if (!NAMEICMP(conn->col_info[k]->table_name, wti->table_name))
                {
-                   mylog("FOUND col_info table='%s'\n", ti[i]->name);
+                   mylog("FOUND col_info table='%s'\n", wti->table_name);
                    found = TRUE;
                    break;
                }
@@ -1053,67 +1076,76 @@ parse_statement(StatementClass *stmt)
 
        if (!found)
        {
-           mylog("PARSE: Getting PG_Columns for table[%d]='%s'\n", i, ti[i]->name);
+           QResultClass    *res;
+           mylog("PARSE: Getting PG_Columns for table[%d]='%s'\n", i, wti->table_name);
 
            result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
            if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
            {
-               SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.");
-               stmt->parse_status = STMT_PARSE_FATAL;
+               SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.", func);
+               SC_set_parse_status(stmt, STMT_PARSE_FATAL);
                return FALSE;
            }
 
            col_stmt = (StatementClass *) hcol_stmt;
            col_stmt->internal = TRUE;
 
-           result = PGAPI_Columns(hcol_stmt, "", 0, ti[i]->schema,
-                    SQL_NTS, ti[i]->name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN);
+           result = PGAPI_Columns(hcol_stmt, "", 0, SAFE_NAME(wti->schema_name),
+                    SQL_NTS, SAFE_NAME(wti->table_name), SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN, 0, 0);
 
            mylog("        Past PG_Columns\n");
+           res = SC_get_Curres(col_stmt);
            if (result == SQL_SUCCESS)
            {
+               COL_INFO    *coli;
+
                mylog("      Success\n");
                if (!(conn->ntables % COL_INCR))
                {
-                   mylog("PARSE: Allocing col_info at ntables=%d\n", conn->ntables);
+                   mylog("PARSE: Allocating col_info at ntables=%d\n", conn->ntables);
 
                    conn->col_info = (COL_INFO **) realloc(conn->col_info, (conn->ntables + COL_INCR) * sizeof(COL_INFO *));
                    if (!conn->col_info)
                    {
-                       stmt->parse_status = STMT_PARSE_FATAL;
+                       SC_set_parse_status(stmt, STMT_PARSE_FATAL);
                        return FALSE;
                    }
                }
 
                mylog("PARSE: malloc at conn->col_info[%d]\n", conn->ntables);
-               conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
-               if (!conn->col_info[conn->ntables])
+               coli = conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
+               if (!coli)
                {
-                   stmt->parse_status = STMT_PARSE_FATAL;
+                   SC_set_parse_status(stmt, STMT_PARSE_FATAL);
                    return FALSE;
                }
+               col_info_initialize(coli);
 
                /*
                 * Store the table name and the SQLColumns result
                 * structure
                 */
-               if (ti[i]->schema[0])
-                   conn->col_info[conn->ntables]->schema = strdup(ti[i]->schema);
+               if (NAME_IS_VALID(wti->schema_name))
+               {
+                   NAME_TO_NAME(coli->schema_name,  wti->schema_name);
+               }
                else
-                   conn->col_info[conn->ntables]->schema = NULL;
-               strcpy(conn->col_info[conn->ntables]->name, ti[i]->name);
-               conn->col_info[conn->ntables]->result = SC_get_Curres(col_stmt);
+                   NULL_THE_NAME(coli->schema_name);
+               NAME_TO_NAME(coli->table_name, wti->table_name);
+               coli->result = res;
 
                /*
                 * The connection will now free the result structures, so
                 * make sure that the statement doesn't free it
                 */
-               SC_set_Result(col_stmt, NULL);
+               SC_init_Result(col_stmt);
 
                conn->ntables++;
 
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
-               mylog("Created col_info table='%s', ntables=%d\n", ti[i]->name, conn->ntables);
+if (res && QR_get_num_cached_tuples(res) > 0)
+inolog("oid item == %s\n", QR_get_value_backend_row(res, 0, 3));
+               mylog("Created col_info table='%s', ntables=%d\n", PRINT_NAME(wti->table_name), conn->ntables);
            }
            else
            {
@@ -1123,7 +1155,7 @@ parse_statement(StatementClass *stmt)
        }
 
        /* Associate a table from the statement with a SQLColumn info */
-       ti[i]->col_info = conn->col_info[k];
+       wti->col_info = conn->col_info[k];
        mylog("associate col_info: i=%d, k=%d\n", i, k);
    }
 
@@ -1133,25 +1165,24 @@ parse_statement(StatementClass *stmt)
     * Now resolve the fields to point to column info
     */
    if (updatable && 1 == stmt->ntab)
-       updatable = stmt->ti[0]->updatable;
+       updatable = TI_is_updatable(stmt->ti[0]);
    for (i = 0; i < (int) irdflds->nfields;)
    {
-       fi[i]->updatable = updatable;
+       wfi = fi[i];
+       wfi->updatable = updatable;
        /* Dont worry about functions or quotes */
-       if (fi[i]->func || fi[i]->quote || fi[i]->numeric)
+       if (wfi->func || wfi->quote || wfi->numeric)
        {
-           fi[i]->updatable = FALSE;
+           wfi->updatable = FALSE;
            i++;
            continue;
        }
 
        /* Stars get expanded to all fields in the table */
-       else if (fi[i]->name[0] == '*')
+       else if (SAFE_NAME(wfi->column_name)[0] == '*')
        {
            char        do_all_tables;
            int         total_cols,
-                       old_alloc,
-                       new_size,
                        cols;
            int         increased_cols;
 
@@ -1159,26 +1190,25 @@ parse_statement(StatementClass *stmt)
 
            total_cols = 0;
 
-           if (fi[i]->ti)      /* The star represents only the qualified
+           if (wfi->ti)        /* The star represents only the qualified
                                 * table */
-               total_cols = QR_get_num_backend_tuples(fi[i]->ti->col_info->result);
+               total_cols = QR_get_num_cached_tuples(wfi->ti->col_info->result);
 
            else
-           {                   /* The star represents all tables */
-
+           {   /* The star represents all tables */
                /* Calculate the total number of columns after expansion */
                for (k = 0; k < stmt->ntab; k++)
-                   total_cols += QR_get_num_backend_tuples(ti[k]->col_info->result);
+                   total_cols += QR_get_num_cached_tuples(ti[k]->col_info->result);
            }
            increased_cols = total_cols - 1;
 
            /* Allocate some more field pointers if necessary */
-           old_alloc = ((irdflds->nfields - 1) / FLD_INCR + 1) * FLD_INCR;
+           /* allocated_size = ((irdflds->nfields - 1) / FLD_INCR + 1) * FLD_INCR; */
            new_size = irdflds->nfields + increased_cols;
 
-           mylog("k=%d, increased_cols=%d, old_alloc=%d, new_size=%d\n", k, increased_cols, old_alloc, new_size);
+           mylog("k=%d, increased_cols=%d, allocated_size=%d, new_size=%d\n", k, increased_cols, allocated_size, new_size);
 
-           if (new_size > old_alloc)
+           if (new_size > allocated_size)
            {
                int         new_alloc = ((new_size / FLD_INCR) + 1) * FLD_INCR;
 
@@ -1186,9 +1216,10 @@ parse_statement(StatementClass *stmt)
                fi = (FIELD_INFO **) realloc(fi, new_alloc * sizeof(FIELD_INFO *));
                if (!fi)
                {
-                   stmt->parse_status = STMT_PARSE_FATAL;
+                   SC_set_parse_status(stmt, STMT_PARSE_FATAL);
                    return FALSE;
                }
+               allocated_size = new_alloc;
                irdflds->fi = fi;
            }
 
@@ -1209,16 +1240,20 @@ parse_statement(StatementClass *stmt)
 
 
            /* copy the new field info */
-           do_all_tables = (fi[i]->ti ? FALSE : TRUE);
+           do_all_tables = (wfi->ti ? FALSE : TRUE);
+           wfi = NULL;
 
            for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++)
            {
                TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
 
-               cols = QR_get_num_backend_tuples(the_ti->col_info->result);
+               cols = QR_get_num_cached_tuples(the_ti->col_info->result);
 
                for (n = 0; n < cols; n++)
                {
+                   FIELD_INFO  *afi;
+                   BOOL        reuse = TRUE;
+
                    mylog("creating field info: n=%d\n", n);
                    /* skip malloc (already did it for the Star) */
                    if (k > 0 || n > 0)
@@ -1227,18 +1262,20 @@ parse_statement(StatementClass *stmt)
                        fi[n + i] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
                        if (fi[n + i] == NULL)
                        {
-                           stmt->parse_status = STMT_PARSE_FATAL;
+                           SC_set_parse_status(stmt, STMT_PARSE_FATAL);
                            return FALSE;
                        }
+                       reuse = FALSE;
                    }
+                   afi = fi[n + i];
                    /* Initialize the new space (or the * field) */
-                   memset(fi[n + i], 0, sizeof(FIELD_INFO));
-                   fi[n + i]->ti = the_ti;
+                   FI_Constructor(afi, reuse);
+                   afi->ti = the_ti;
 
                    mylog("about to copy at %d\n", n + i);
 
-                   getColInfo(the_ti->col_info, fi[n + i], n);
-                   fi[n + i]->updatable = updatable;
+                   getColInfo(the_ti->col_info, afi, n);
+                   afi->updatable = updatable;
 
                    mylog("done copying\n");
                }
@@ -1253,12 +1290,12 @@ parse_statement(StatementClass *stmt)
         * qualified with a table name or alias -OR- there was only 1
         * table.
         */
-       else if (fi[i]->ti)
+       else if (wfi->ti)
        {
-           if (!searchColInfo(fi[i]->ti->col_info, fi[i]))
+           if (!searchColInfo(fi[i]->ti->col_info, wfi))
            {
                parse = FALSE;
-               fi[i]->updatable = FALSE;
+               wfi->updatable = FALSE;
            }
            i++;
        }
@@ -1268,27 +1305,37 @@ parse_statement(StatementClass *stmt)
        {
            for (k = 0; k < stmt->ntab; k++)
            {
-               if (searchColInfo(ti[k]->col_info, fi[i]))
+               if (searchColInfo(ti[k]->col_info, wfi))
                {
-                   fi[i]->ti = ti[k];  /* now know the table */
+                   wfi->ti = ti[k];    /* now know the table */
                    break;
                }
            }
            if (k >= stmt->ntab)
            {
                parse = FALSE;
-               fi[i]->updatable = FALSE;
+               wfi->updatable = FALSE;
            }
            i++;
        }
    }
 
+   if (check_hasoids && updatable)
+       CheckHasOids(stmt);
    if (!parse)
-       stmt->parse_status = STMT_PARSE_INCOMPLETE;
+       SC_set_parse_status(stmt, STMT_PARSE_INCOMPLETE);
    else
-       stmt->parse_status = STMT_PARSE_COMPLETE;
+   {
+       SC_set_parse_status(stmt,  STMT_PARSE_COMPLETE);
+       for (i = 0; i < (int) irdflds->nfields; i++)
+       {
+           wfi = fi[i];
+           wfi->flag &= ~FIELD_PARSING;
+           wfi->flag |= FIELD_PARSED_OK;
+       }
+   }
 
    stmt->updatable = updatable;
-   mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, stmt->parse_status);
+   mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, SC_parsed_status(stmt));
    return parse;
 }
index 36a6c9be213ba1c3e3243e979adea667038e20ca..8c999bcd573f9a2ec86954ef336a64706b7b19e0 100644 (file)
--- a/pgapi30.c
+++ b/pgapi30.c
@@ -16,6 +16,7 @@
 
 #include "psqlodbc.h"
 
+#if (ODBCVER >= 0x0300)
 #include <stdio.h>
 #include <string.h>
 
 #include "qresult.h"
 #include "pgapifunc.h"
 
+#ifdef WIN32
+#ifdef _HANDLE_ENLIST_IN_DTC_
+RETCODE EnlistInDtc();
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
+#endif /* WIN32 */
+
 /* SQLError -> SQLDiagRec */
 RETCODE        SQL_API
 PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
@@ -36,7 +43,7 @@ PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
    RETCODE     ret;
    CSTR func = "PGAPI_GetDiagRec";
 
-   mylog("%s entering rec=%d", func, RecNumber);
+   mylog("%s entering type=%d rec=%d\n", func, HandleType, RecNumber);
    switch (HandleType)
    {
        case SQL_HANDLE_ENV:
@@ -68,7 +75,7 @@ PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
 }
 
 /*
- * Minimal implementation.
+ * Minimal implementation. 
  *
  */
 RETCODE        SQL_API
@@ -82,9 +89,10 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
    StatementClass  *stmt;
    SDWORD      rc;
    SWORD       pcbErrm;
+   int     rtnlen = -1, rtnctype = SQL_C_CHAR;
    CSTR func = "PGAPI_GetDiagField";
 
-   mylog("%s entering rec=%d, HandleType=%d, DiagIdentifier=%d\n", func, RecNumber, HandleType, DiagIdentifier);
+   mylog("%s entering rec=%d", func, RecNumber);
    switch (HandleType)
    {
        case SQL_HANDLE_ENV:
@@ -94,26 +102,28 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
                case SQL_DIAG_SUBCLASS_ORIGIN:
                case SQL_DIAG_CONNECTION_NAME:
                case SQL_DIAG_SERVER_NAME:
-                   strcpy((char *) DiagInfoPtr, "");
-                   if (StringLengthPtr)
-                       *StringLengthPtr = 0;
-                   ret = SQL_SUCCESS;
+                   rtnlen = 0;
+                   if (DiagInfoPtr && BufferLength > rtnlen)
+                   {
+                       ret = SQL_SUCCESS;
+                       *((char *) DiagInfoPtr) = '\0';
+                   }
+                   else
+                       ret = SQL_SUCCESS_WITH_INFO;
                    break;
                case SQL_DIAG_MESSAGE_TEXT:
                    ret = PGAPI_EnvError(Handle, RecNumber,
                                    NULL, NULL, DiagInfoPtr,
-                       BufferLength, StringLengthPtr, 0);
+                       BufferLength, StringLengthPtr, 0);  
                    break;
                case SQL_DIAG_NATIVE:
+                   rtnctype = SQL_C_LONG;
                    ret = PGAPI_EnvError(Handle, RecNumber,
-                                   NULL, DiagInfoPtr, NULL,
-                       0, NULL, 0);
-                   if (StringLengthPtr)
-                       *StringLengthPtr = sizeof(SQLINTEGER);
-                   if (SQL_SUCCESS_WITH_INFO == ret)
-                       ret = SQL_SUCCESS;
+                                   NULL, (SQLINTEGER *) DiagInfoPtr, NULL,
+                       0, NULL, 0);  
                    break;
                case SQL_DIAG_NUMBER:
+                   rtnctype = SQL_C_LONG;
                    ret = PGAPI_EnvError(Handle, RecNumber,
                                    NULL, NULL, NULL,
                        0, NULL, 0);
@@ -121,18 +131,14 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
                        SQL_SUCCESS_WITH_INFO == ret)
                    {
                        *((SQLINTEGER *) DiagInfoPtr) = 1;
-                       if (StringLengthPtr)
-                           *StringLengthPtr = sizeof(SQLINTEGER);
-                       ret = SQL_SUCCESS;
                    }
                    break;
                case SQL_DIAG_SQLSTATE:
+                   rtnlen = 5;
                    ret = PGAPI_EnvError(Handle, RecNumber,
                                    DiagInfoPtr, NULL, NULL,
                        0, NULL, 0);
-                   if (StringLengthPtr)
-                       *StringLengthPtr = 5;
-                   if (SQL_SUCCESS_WITH_INFO == ret)
+                   if (SQL_SUCCESS_WITH_INFO == ret)  
                        ret = SQL_SUCCESS;
                    break;
                case SQL_DIAG_RETURNCODE: /* driver manager returns */
@@ -152,32 +158,36 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
                case SQL_DIAG_CLASS_ORIGIN:
                case SQL_DIAG_SUBCLASS_ORIGIN:
                case SQL_DIAG_CONNECTION_NAME:
-                   strcpy((char *) DiagInfoPtr, "");
-                   if (StringLengthPtr)
-                       *StringLengthPtr = 0;
-                   ret = SQL_SUCCESS;
+                   rtnlen = 0;
+                   if (DiagInfoPtr && BufferLength > rtnlen)
+                   {
+                       ret = SQL_SUCCESS;
+                       *((char *) DiagInfoPtr) = '\0';
+                   }
+                   else
+                       ret = SQL_SUCCESS_WITH_INFO;
                    break;
                case SQL_DIAG_SERVER_NAME:
-                   strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
-                   if (StringLengthPtr)
-                       *StringLengthPtr = strlen(CC_get_DSN(conn));
-                   ret = SQL_SUCCESS;
+                   rtnlen = strlen(CC_get_DSN(conn));
+                   if (DiagInfoPtr)
+                   {
+                       strncpy_null((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn), BufferLength);
+                       ret = (BufferLength > rtnlen ? SQL_SUCCESS : SQL_SUCCESS_WITH_INFO);
+                   }
                    break;
                case SQL_DIAG_MESSAGE_TEXT:
                    ret = PGAPI_ConnectError(Handle, RecNumber,
                                    NULL, NULL, DiagInfoPtr,
-                       BufferLength, StringLengthPtr, 0);
+                       BufferLength, StringLengthPtr, 0);  
                    break;
                case SQL_DIAG_NATIVE:
+                   rtnctype = SQL_C_LONG;
                    ret = PGAPI_ConnectError(Handle, RecNumber,
-                                   NULL, DiagInfoPtr, NULL,
-                       0, NULL, 0);
-                   if (StringLengthPtr)
-                       *StringLengthPtr = sizeof(SQLINTEGER);
-                   if (SQL_SUCCESS_WITH_INFO == ret)
-                       ret = SQL_SUCCESS;
+                                   NULL, (SQLINTEGER *) DiagInfoPtr, NULL,
+                       0, NULL, 0);  
                    break;
                case SQL_DIAG_NUMBER:
+                   rtnctype = SQL_C_LONG;
                    ret = PGAPI_ConnectError(Handle, RecNumber,
                                    NULL, NULL, NULL,
                        0, NULL, 0);
@@ -185,18 +195,14 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
                        SQL_SUCCESS_WITH_INFO == ret)
                    {
                        *((SQLINTEGER *) DiagInfoPtr) = 1;
-                       if (StringLengthPtr)
-                           *StringLengthPtr = sizeof(SQLINTEGER);
-                       ret = SQL_SUCCESS;
                    }
-                   break;
+                   break;  
                case SQL_DIAG_SQLSTATE:
+                   rtnlen = 5;
                    ret = PGAPI_ConnectError(Handle, RecNumber,
                                    DiagInfoPtr, NULL, NULL,
                        0, NULL, 0);
-                   if (StringLengthPtr)
-                       *StringLengthPtr = 5;
-                   if (SQL_SUCCESS_WITH_INFO == ret)
+                   if (SQL_SUCCESS_WITH_INFO == ret)  
                        ret = SQL_SUCCESS;
                    break;
                case SQL_DIAG_RETURNCODE: /* driver manager returns */
@@ -216,32 +222,36 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
                case SQL_DIAG_CLASS_ORIGIN:
                case SQL_DIAG_SUBCLASS_ORIGIN:
                case SQL_DIAG_CONNECTION_NAME:
-                   strcpy((char *) DiagInfoPtr, "");
-                   if (StringLengthPtr)
-                       *StringLengthPtr = 0;
-                   ret = SQL_SUCCESS;
+                   rtnlen = 0;
+                   if (DiagInfoPtr && BufferLength > rtnlen)
+                   {
+                       ret = SQL_SUCCESS;
+                       *((char *) DiagInfoPtr) = '\0';
+                   }
+                   else
+                       ret = SQL_SUCCESS_WITH_INFO;
                    break;
                case SQL_DIAG_SERVER_NAME:
-                   strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
-                   if (StringLengthPtr)
-                       *StringLengthPtr = strlen(CC_get_DSN(conn));
-                   ret = SQL_SUCCESS;
+                   rtnlen = strlen(CC_get_DSN(conn));
+                   if (DiagInfoPtr)
+                   {
+                       strncpy_null((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn), BufferLength);
+                       ret = (BufferLength > rtnlen ? SQL_SUCCESS : SQL_SUCCESS_WITH_INFO);
+                   }
                    break;
                case SQL_DIAG_MESSAGE_TEXT:
                    ret = PGAPI_StmtError(Handle, RecNumber,
                                    NULL, NULL, DiagInfoPtr,
-                       BufferLength, StringLengthPtr, 0);
+                       BufferLength, StringLengthPtr, 0);  
                    break;
                case SQL_DIAG_NATIVE:
+                   rtnctype = SQL_C_LONG;
                    ret = PGAPI_StmtError(Handle, RecNumber,
-                                   NULL, DiagInfoPtr, NULL,
-                       0, NULL, 0);
-                   if (StringLengthPtr)
-                       *StringLengthPtr = sizeof(SQLINTEGER);
-                   if (SQL_SUCCESS_WITH_INFO == ret)
-                       ret = SQL_SUCCESS;
+                                   NULL, (SQLINTEGER *) DiagInfoPtr, NULL,
+                       0, NULL, 0);  
                    break;
                case SQL_DIAG_NUMBER:
+                   rtnctype = SQL_C_LONG;
                    *((SQLINTEGER *) DiagInfoPtr) = 0;
                    ret = SQL_NO_DATA_FOUND;
                    stmt = (StatementClass *) Handle;
@@ -252,55 +262,55 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
                        case SQL_SUCCESS:
                        case SQL_SUCCESS_WITH_INFO:
                            ret = SQL_SUCCESS;
-                           if (pcbErrm > 0)
-                               *((SQLINTEGER *) DiagInfoPtr) = (pcbErrm  - 1)/ stmt->error_recsize + 1;
+                           if (pcbErrm > 0 && stmt->pgerror)
+                           
+                               *((SQLINTEGER *) DiagInfoPtr) = (pcbErrm  - 1)/ stmt->pgerror->recsize + 1;
                            break;
                        default:
                            break;
                    }
-                   if (StringLengthPtr)
-                       *StringLengthPtr = sizeof(SQLINTEGER);
                    break;
                case SQL_DIAG_SQLSTATE:
+                   rtnlen = 5;
                    ret = PGAPI_StmtError(Handle, RecNumber,
                                    DiagInfoPtr, NULL, NULL,
                        0, NULL, 0);
-                   if (StringLengthPtr)
-                       *StringLengthPtr = 5;
-                   if (SQL_SUCCESS_WITH_INFO == ret)
+                   if (SQL_SUCCESS_WITH_INFO == ret)  
                        ret = SQL_SUCCESS;
                    break;
                case SQL_DIAG_CURSOR_ROW_COUNT:
+                   rtnctype = SQL_C_LONG;
                    stmt = (StatementClass *) Handle;
                    rc = -1;
                    if (stmt->status == STMT_FINISHED)
                    {
                        QResultClass *res = SC_get_Curres(stmt);
-                       if (res && QR_NumResultCols(res) > 0 && !SC_is_fetchcursor(stmt))
+
+                       /*if (!res)
+                           return SQL_ERROR;*/
+                       if (stmt->proc_return > 0)
+                           rc = 0;
+                       else if (res && QR_NumResultCols(res) > 0 && !SC_is_fetchcursor(stmt))
                            rc = QR_get_num_total_tuples(res) - res->dl_count;
-                   }
+                   } 
                    *((SQLINTEGER *) DiagInfoPtr) = rc;
-                   if (StringLengthPtr)
-                       *StringLengthPtr = sizeof(SQLINTEGER);
+inolog("rc=%d\n", rc);
                    ret = SQL_SUCCESS;
                    break;
                case SQL_DIAG_ROW_COUNT:
+                   rtnctype = SQL_C_LONG;
                    stmt = (StatementClass *) Handle;
                    *((SQLINTEGER *) DiagInfoPtr) = stmt->diag_row_count;
-                   if (StringLengthPtr)
-                       *StringLengthPtr = sizeof(SQLINTEGER);
                    ret = SQL_SUCCESS;
                    break;
                                 case SQL_DIAG_ROW_NUMBER:
+                   rtnctype = SQL_C_LONG;
                    *((SQLINTEGER *) DiagInfoPtr) = SQL_ROW_NUMBER_UNKNOWN;
-                   if (StringLengthPtr)
-                       *StringLengthPtr = sizeof(SQLINTEGER);
                    ret = SQL_SUCCESS;
                    break;
                                 case SQL_DIAG_COLUMN_NUMBER:
+                   rtnctype = SQL_C_LONG;
                    *((SQLINTEGER *) DiagInfoPtr) = SQL_COLUMN_NUMBER_UNKNOWN;
-                   if (StringLengthPtr)
-                       *StringLengthPtr = sizeof(SQLINTEGER);
                    ret = SQL_SUCCESS;
                    break;
                case SQL_DIAG_RETURNCODE: /* driver manager returns */
@@ -308,33 +318,39 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
            }
            break;
        case SQL_HANDLE_DESC:
-           conn = DC_get_conn(((DescriptorClass *) Handle));
+           conn = DC_get_conn(((DescriptorClass *) Handle)); 
            switch (DiagIdentifier)
            {
                case SQL_DIAG_CLASS_ORIGIN:
                case SQL_DIAG_SUBCLASS_ORIGIN:
                case SQL_DIAG_CONNECTION_NAME:
-                   strcpy((char *) DiagInfoPtr, "");
-                   if (StringLengthPtr)
-                       *StringLengthPtr = 0;
-                   ret = SQL_SUCCESS;
+                   rtnlen = 0;
+                   if (DiagInfoPtr && BufferLength > rtnlen)
+                   {
+                       ret = SQL_SUCCESS;
+                       *((char *) DiagInfoPtr) = '\0';
+                   }
+                   else
+                       ret = SQL_SUCCESS_WITH_INFO;
                    break;
                case SQL_DIAG_SERVER_NAME:
-                   strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
-                   if (StringLengthPtr)
-                       *StringLengthPtr = strlen(CC_get_DSN(conn));
-                   ret = SQL_SUCCESS;
+                   rtnlen = strlen(CC_get_DSN(conn));
+                   if (DiagInfoPtr)
+                   {
+                       strncpy_null((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn), BufferLength);
+                       ret = (BufferLength > rtnlen ? SQL_SUCCESS : SQL_SUCCESS_WITH_INFO);
+                   }
                    break;
                case SQL_DIAG_MESSAGE_TEXT:
                case SQL_DIAG_NATIVE:
                case SQL_DIAG_NUMBER:
+                   break;
                case SQL_DIAG_SQLSTATE:
+                   rtnlen = 5;
                    ret = PGAPI_DescError(Handle, RecNumber,
                                    DiagInfoPtr, NULL, NULL,
                        0, NULL, 0);
-                   if (StringLengthPtr)
-                       *StringLengthPtr = 5;
-                   if (SQL_SUCCESS_WITH_INFO == ret)
+                   if (SQL_SUCCESS_WITH_INFO == ret)  
                        ret = SQL_SUCCESS;
                    break;
                case SQL_DIAG_RETURNCODE: /* driver manager returns */
@@ -343,6 +359,7 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
                case SQL_DIAG_ROW_COUNT:
                case SQL_DIAG_DYNAMIC_FUNCTION:
                case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
+                   rtnctype = SQL_C_LONG;
                    /* options for statement type only */
                    break;
            }
@@ -350,6 +367,25 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
        default:
            ret = SQL_ERROR;
    }
+   if (SQL_C_LONG == rtnctype)
+   {
+       if (SQL_SUCCESS_WITH_INFO == ret)
+           ret = SQL_SUCCESS;
+       if (StringLengthPtr)  
+           *StringLengthPtr = sizeof(SQLINTEGER);
+   }
+   else if (rtnlen >= 0)
+   {
+       if (rtnlen >= BufferLength)
+       {
+           if (SQL_SUCCESS == ret)
+               ret = SQL_SUCCESS_WITH_INFO;
+           if (BufferLength > 0)
+               ((char *) DiagInfoPtr) [BufferLength - 1] = '\0';
+       }
+       if (StringLengthPtr)  
+           *StringLengthPtr = rtnlen;
+   }
    mylog("%s exiting %d\n", func, ret);
    return ret;
 }
@@ -360,9 +396,10 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
            SQLINTEGER Attribute, PTR Value,
            SQLINTEGER BufferLength, SQLINTEGER *StringLength)
 {
+   CSTR func = "PGAPI_GetConnectAttr";
    ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
    RETCODE ret = SQL_SUCCESS;
-   SQLINTEGER  len = sizeof(SQLUINTEGER);
+   SQLINTEGER  len = 4;
 
    mylog("PGAPI_GetConnectAttr %d\n", Attribute);
    switch (Attribute)
@@ -374,7 +411,6 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
            *((SQLUINTEGER *) Value) = SQL_FALSE;
            break;
        case SQL_ATTR_CONNECTION_DEAD:
-           CC_is_server_alive(conn);
            *((SQLUINTEGER *) Value) = (conn->status == CONN_NOT_CONNECTED || conn->status == CONN_DOWN);
            break;
        case SQL_ATTR_CONNECTION_TIMEOUT:
@@ -385,36 +421,6 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
            break;
        default:
            ret = PGAPI_GetConnectOption(ConnectionHandle, (UWORD) Attribute, Value);
-
-           /* We need to make sure the length is set correct for these... */
-           switch (Attribute)
-           {
-               case SQL_ACCESS_MODE:
-               case SQL_AUTOCOMMIT:
-               case SQL_LOGIN_TIMEOUT:
-               case SQL_PACKET_SIZE:
-               case SQL_QUIET_MODE:
-               case SQL_TXN_ISOLATION:
-                   len = sizeof(UDWORD);
-                   break;
-
-               case SQL_CURRENT_QUALIFIER:
-               case SQL_ODBC_CURSORS:
-               case SQL_OPT_TRACE:
-               case SQL_OPT_TRACEFILE:
-               case SQL_TRANSLATE_DLL:
-               case SQL_TRANSLATE_OPTION:
-                   len = 0;
-                   break;
-
-#ifdef SQL_ATTR_CONNECTION_DEAD
-       case SQL_ATTR_CONNECTION_DEAD:
-#else
-       case 1209:
-#endif /* SQL_ATTR_CONNECTION_DEAD */
-                   len = sizeof(SQLUINTEGER);
-                   break;
-           }
    }
    if (StringLength)
        *StringLength = len;
@@ -422,7 +428,7 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
 }
 
 static SQLHDESC
-descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType)
+descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType) 
 {
    StatementClass  *stmt = (StatementClass *) StatementHandle;
 
@@ -475,8 +481,8 @@ ARDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
    switch (FieldIdentifier)
    {
        case SQL_DESC_ARRAY_SIZE:
-           opts->size_of_rowset = (SQLUINTEGER) ((unsigned long) Value);
-           return ret;
+           opts->size_of_rowset = (SQLUINTEGER) Value;
+           return ret; 
        case SQL_DESC_ARRAY_STATUS_PTR:
            opts->row_operation_ptr = Value;
            return ret;
@@ -484,10 +490,10 @@ ARDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            opts->row_offset_ptr = Value;
            return ret;
        case SQL_DESC_BIND_TYPE:
-           opts->bind_size = (SQLUINTEGER) ((unsigned long) Value);
+           opts->bind_size = (SQLUINTEGER) Value;
            return ret;
        case SQL_DESC_COUNT:
-           column_bindings_set(opts, (SQLUINTEGER) ((unsigned long) Value), FALSE);
+           column_bindings_set(opts, (SQLUINTEGER) Value, FALSE);
            return ret;
 
        case SQL_DESC_TYPE:
@@ -498,7 +504,7 @@ ARDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
    }
    if (RecNumber < 0 || RecNumber > opts->allocated)
    {
-       DC_set_error(desc, STMT_INVALID_COLUMN_NUMBER_ERROR, "invalid column number");
+       DC_set_error(desc, DESC_INVALID_COLUMN_NUMBER_ERROR, "invalid column number");
        return SQL_ERROR;
    }
    if (0 == RecNumber) /* bookmark column */
@@ -514,7 +520,7 @@ ARDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
                tptr = bookmark->used;
                if (Value != tptr)
                {
-                   DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR");
+                   DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); 
                    ret = SQL_ERROR;
                }
                break;
@@ -522,7 +528,7 @@ ARDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
                bookmark->used = Value;
                break;
            default:
-               DC_set_error(desc, STMT_INVALID_COLUMN_NUMBER_ERROR, "invalid column number");
+               DC_set_error(desc, DESC_INVALID_COLUMN_NUMBER_ERROR, "invalid column number");
                ret = SQL_ERROR;
        }
        return ret;
@@ -532,7 +538,7 @@ ARDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
    {
        case SQL_DESC_TYPE:
            reset_a_column_binding(opts, RecNumber);
-           opts->bindings[row_idx].returntype = (Int4) ((long) Value);
+           opts->bindings[row_idx].returntype = (Int4) Value;
            break;
        case SQL_DESC_DATETIME_INTERVAL_CODE:
            switch (opts->bindings[row_idx].returntype)
@@ -541,7 +547,7 @@ ARDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
                case SQL_C_TYPE_DATE:
                case SQL_C_TYPE_TIME:
                case SQL_C_TYPE_TIMESTAMP:
-               switch ((Int4) ((long) Value))
+               switch ((Int4) Value)
                {
                    case SQL_CODE_DATE:
                        opts->bindings[row_idx].returntype = SQL_C_TYPE_DATE;
@@ -557,7 +563,7 @@ ARDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            }
            break;
        case SQL_DESC_CONCISE_TYPE:
-           opts->bindings[row_idx].returntype = (Int4) ((long) Value);
+           opts->bindings[row_idx].returntype = (Int4) Value;
            break;
        case SQL_DESC_DATA_PTR:
            opts->bindings[row_idx].buffer = Value;
@@ -567,28 +573,28 @@ ARDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            if (Value != tptr)
            {
                ret = SQL_ERROR;
-               DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR");
+               DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); 
            }
            break;
        case SQL_DESC_OCTET_LENGTH_PTR:
            opts->bindings[row_idx].used = Value;
            break;
        case SQL_DESC_OCTET_LENGTH:
-           opts->bindings[row_idx].buflen = (Int4) ((long) Value);
+           opts->bindings[row_idx].buflen = (Int4) Value;
            break;
        case SQL_DESC_PRECISION:
-           opts->bindings[row_idx].precision = (Int2)((long) Value);
+           opts->bindings[row_idx].precision = (Int2)((Int4) Value);
            break;
        case SQL_DESC_SCALE:
-           opts->bindings[row_idx].scale = (Int4) ((long) Value);
+           opts->bindings[row_idx].scale = (Int4) Value;
            break;
        case SQL_DESC_ALLOC_TYPE: /* read-only */
        case SQL_DESC_DATETIME_INTERVAL_PRECISION:
        case SQL_DESC_LENGTH:
        case SQL_DESC_NUM_PREC_RADIX:
        default:ret = SQL_ERROR;
-           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
-               "invalid descriptor identifier");
+           DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invalid descriptor identifier"); 
    }
    return ret;
 }
@@ -650,8 +656,8 @@ APDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
    switch (FieldIdentifier)
    {
        case SQL_DESC_ARRAY_SIZE:
-           opts->paramset_size = (SQLUINTEGER) ((unsigned long) Value);
-           return ret;
+           opts->paramset_size = (SQLUINTEGER) Value;
+           return ret; 
        case SQL_DESC_ARRAY_STATUS_PTR:
            opts->param_operation_ptr = Value;
            return ret;
@@ -659,11 +665,11 @@ APDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            opts->param_offset_ptr = Value;
            return ret;
        case SQL_DESC_BIND_TYPE:
-           opts->param_bind_type = (SQLUINTEGER) ((unsigned long) Value);
+           opts->param_bind_type = (SQLUINTEGER) Value;
            return ret;
        case SQL_DESC_COUNT:
-           parameter_bindings_set(opts, (SQLUINTEGER) ((unsigned long) Value), FALSE);
-           return ret;
+           parameter_bindings_set(opts, (SQLUINTEGER) Value, FALSE);
+           return ret; 
 
        case SQL_DESC_TYPE:
        case SQL_DESC_DATETIME_INTERVAL_CODE:
@@ -671,18 +677,27 @@ APDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            parameter_bindings_set(opts, RecNumber, TRUE);
            break;
    }
-   if (RecNumber <=0 || RecNumber > opts->allocated)
+   if (RecNumber <=0)
    {
-       DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR,
+inolog("APDSetField RecN=%d allocated=%d\n", RecNumber, opts->allocated);
+       DC_set_error(desc, DESC_BAD_PARAMETER_NUMBER_ERROR,
                "bad parameter number");
        return SQL_ERROR;
    }
-   para_idx = RecNumber - 1;
+   if (RecNumber > opts->allocated)
+   {
+inolog("APDSetField RecN=%d allocated=%d\n", RecNumber, opts->allocated);
+       parameter_bindings_set(opts, RecNumber, TRUE);
+       /* DC_set_error(desc, DESC_BAD_PARAMETER_NUMBER_ERROR,
+               "bad parameter number");
+       return SQL_ERROR;*/
+   }
+   para_idx = RecNumber - 1; 
    switch (FieldIdentifier)
    {
        case SQL_DESC_TYPE:
            reset_a_parameter_binding(opts, RecNumber);
-           opts->parameters[para_idx].CType = (Int4) ((long) Value);
+           opts->parameters[para_idx].CType = (Int4) Value;
            break;
        case SQL_DESC_DATETIME_INTERVAL_CODE:
            switch (opts->parameters[para_idx].CType)
@@ -691,7 +706,7 @@ APDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
                case SQL_C_TYPE_DATE:
                case SQL_C_TYPE_TIME:
                case SQL_C_TYPE_TIMESTAMP:
-               switch ((Int4) ((long) Value))
+               switch ((Int4) Value)
                {
                    case SQL_CODE_DATE:
                        opts->parameters[para_idx].CType = SQL_C_TYPE_DATE;
@@ -707,7 +722,7 @@ APDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            }
            break;
        case SQL_DESC_CONCISE_TYPE:
-           opts->parameters[para_idx].CType = (Int4) ((long) Value);
+           opts->parameters[para_idx].CType = (Int4) Value;
            break;
        case SQL_DESC_DATA_PTR:
            opts->parameters[para_idx].buffer = Value;
@@ -716,28 +731,28 @@ APDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            if (Value != opts->parameters[para_idx].used)
            {
                ret = SQL_ERROR;
-               DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR");
+               DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); 
            }
            break;
        case SQL_DESC_OCTET_LENGTH:
-           opts->parameters[para_idx].buflen = (Int4) ((long) Value);
+           opts->parameters[para_idx].buflen = (Int4) Value;
            break;
        case SQL_DESC_OCTET_LENGTH_PTR:
            opts->parameters[para_idx].used = Value;
            break;
        case SQL_DESC_PRECISION:
-           opts->parameters[para_idx].precision = (Int2) ((long) Value);
+           opts->parameters[para_idx].precision = (Int2) ((Int4) Value);
            break;
        case SQL_DESC_SCALE:
-           opts->parameters[para_idx].scale = (Int2) ((long) Value);
+           opts->parameters[para_idx].scale = (Int2) ((Int4) Value);
            break;
        case SQL_DESC_ALLOC_TYPE: /* read-only */
        case SQL_DESC_DATETIME_INTERVAL_PRECISION:
        case SQL_DESC_LENGTH:
        case SQL_DESC_NUM_PREC_RADIX:
        default:ret = SQL_ERROR;
-           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
-               "invaid descriptor identifier");
+           DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invaid descriptor identifier"); 
    }
    return ret;
 }
@@ -792,8 +807,8 @@ IRDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        case SQL_DESC_UNSIGNED: /* read-only */
        case SQL_DESC_UPDATABLE: /* read-only */
        default:ret = SQL_ERROR;
-           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
-               "invalid descriptor identifier");
+           DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invalid descriptor identifier"); 
    }
    return ret;
 }
@@ -814,17 +829,18 @@ IPDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        case SQL_DESC_ROWS_PROCESSED_PTR:
            ipdopts->param_processed_ptr = (UInt4 *) Value;
            return ret;
-       case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */
-           if (SQL_UNNAMED !=  (SQLUINTEGER) ((unsigned long) Value))
+       case SQL_DESC_COUNT:
+           parameter_ibindings_set(ipdopts, (SQLUINTEGER) Value, FALSE);
+           return ret;
+       case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */ 
+           if (SQL_UNNAMED !=  (SQLUINTEGER) Value)
            {
                ret = SQL_ERROR;
-               DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
+               DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
                    "invalid descriptor identifier");
+               return ret;
            }
-           return ret;
-       case SQL_DESC_COUNT:
-           parameter_ibindings_set(ipdopts, (SQLUINTEGER) ((unsigned long) Value), FALSE);
-           return ret;
+       case SQL_DESC_NAME:
        case SQL_DESC_TYPE:
        case SQL_DESC_DATETIME_INTERVAL_CODE:
        case SQL_DESC_CONCISE_TYPE:
@@ -833,7 +849,8 @@ IPDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
    }
    if (RecNumber <= 0 || RecNumber > ipdopts->allocated)
    {
-       DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR,
+inolog("IPDSetField RecN=%d allocated=%d\n", RecNumber, ipdopts->allocated);
+       DC_set_error(desc, DESC_BAD_PARAMETER_NUMBER_ERROR,
                "bad parameter number");
        return SQL_ERROR;
    }
@@ -842,7 +859,7 @@ IPDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
    {
        case SQL_DESC_TYPE:
            reset_a_iparameter_binding(ipdopts, RecNumber);
-           ipdopts->parameters[para_idx].SQLType = (Int4) ((long) Value);
+           ipdopts->parameters[para_idx].SQLType = (Int4) Value;
            break;
        case SQL_DESC_DATETIME_INTERVAL_CODE:
            switch (ipdopts->parameters[para_idx].SQLType)
@@ -851,7 +868,7 @@ IPDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
                case SQL_TYPE_DATE:
                case SQL_TYPE_TIME:
                case SQL_TYPE_TIMESTAMP:
-               switch ((Int4) ((long) Value))
+               switch ((Int4) Value)
                {
                    case SQL_CODE_DATE:
                        ipdopts->parameters[para_idx].SQLType = SQL_TYPE_DATE;
@@ -867,21 +884,36 @@ IPDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            }
            break;
        case SQL_DESC_CONCISE_TYPE:
-           ipdopts->parameters[para_idx].SQLType = (Int4) ((long) Value);
+           ipdopts->parameters[para_idx].SQLType = (Int4) Value;
+           break;
+       case SQL_DESC_NAME:
+           if (Value)
+               STR_TO_NAME(ipdopts->parameters[para_idx].paramName, Value);
+           else
+               NULL_THE_NAME(ipdopts->parameters[para_idx].paramName);
            break;
        case SQL_DESC_PARAMETER_TYPE:
-           ipdopts->parameters[para_idx].paramType = (Int2) ((long) Value);
+           ipdopts->parameters[para_idx].paramType = (Int2) ((Int4) Value);
            break;
        case SQL_DESC_SCALE:
-           ipdopts->parameters[para_idx].decimal_digits = (Int2) ((long) Value);
+           ipdopts->parameters[para_idx].decimal_digits = (Int2) ((Int4) Value);
            break;
-       case SQL_DESC_ALLOC_TYPE: /* read-only */
+       case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */ 
+           if (SQL_UNNAMED !=  (SQLUINTEGER) Value)
+           {
+               ret = SQL_ERROR;
+               DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+                   "invalid descriptor identifier");
+           }
+           else
+               NULL_THE_NAME(ipdopts->parameters[para_idx].paramName);
+           break;
+       case SQL_DESC_ALLOC_TYPE: /* read-only */ 
        case SQL_DESC_CASE_SENSITIVE: /* read-only */
        case SQL_DESC_DATETIME_INTERVAL_PRECISION:
        case SQL_DESC_FIXED_PREC_SCALE: /* read-only */
        case SQL_DESC_LENGTH:
        case SQL_DESC_LOCAL_TYPE_NAME: /* read-only */
-       case SQL_DESC_NAME:
        case SQL_DESC_NULLABLE: /* read-only */
        case SQL_DESC_NUM_PREC_RADIX:
        case SQL_DESC_OCTET_LENGTH:
@@ -892,8 +924,8 @@ IPDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        case SQL_DESC_TYPE_NAME: /* read-only */
        case SQL_DESC_UNSIGNED: /* read-only */
        default:ret = SQL_ERROR;
-           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
-               "invalid descriptor identifier");
+           DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invalid descriptor identifier"); 
    }
    return ret;
 }
@@ -948,7 +980,7 @@ ARDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        default:
            if (RecNumber <= 0 || RecNumber > opts->allocated)
            {
-               DC_set_error(desc, STMT_INVALID_COLUMN_NUMBER_ERROR,
+               DC_set_error(desc, DESC_INVALID_COLUMN_NUMBER_ERROR,
                    "invalid column number");
                return SQL_ERROR;
            }
@@ -958,7 +990,7 @@ ARDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
    {
        case SQL_DESC_ARRAY_SIZE:
            ival = opts->size_of_rowset;
-           break;
+           break; 
        case SQL_DESC_ARRAY_STATUS_PTR:
            rettype = SQL_IS_POINTER;
            ptr = opts->row_operation_ptr;
@@ -1038,8 +1070,8 @@ ARDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        case SQL_DESC_DATETIME_INTERVAL_PRECISION:
        case SQL_DESC_LENGTH:
        default:ret = SQL_ERROR;
-           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
-               "invalid descriptor identifier");
+           DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invalid descriptor identifier"); 
    }
    switch (rettype)
    {
@@ -1053,7 +1085,7 @@ ARDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            *((void **) Value) = ptr;
            break;
    }
-
+           
    if (StringLength)
        *StringLength = len;
    return ret;
@@ -1078,13 +1110,14 @@ APDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        case SQL_DESC_BIND_OFFSET_PTR:
        case SQL_DESC_BIND_TYPE:
        case SQL_DESC_COUNT:
-           break;
+           break; 
        default:if (RecNumber <= 0 || RecNumber > opts->allocated)
            {
-               DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR,
+inolog("APDGetField RecN=%d allocated=%d\n", RecNumber, opts->allocated);
+               DC_set_error(desc, DESC_BAD_PARAMETER_NUMBER_ERROR,
                    "bad parameter number");
                return SQL_ERROR;
-           }
+           } 
    }
    para_idx = RecNumber - 1;
    switch (FieldIdentifier)
@@ -1092,7 +1125,7 @@ APDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        case SQL_DESC_ARRAY_SIZE:
            rettype = SQL_IS_POINTER;
            ival = opts->paramset_size;
-           break;
+           break; 
        case SQL_DESC_ARRAY_STATUS_PTR:
            rettype = SQL_IS_POINTER;
            ptr = opts->param_operation_ptr;
@@ -1154,7 +1187,7 @@ APDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            break;
        case SQL_DESC_COUNT:
            ival = opts->allocated;
-           break;
+           break; 
        case SQL_DESC_ALLOC_TYPE: /* read-only */
            if (desc->embedded)
                ival = SQL_DESC_ALLOC_AUTO;
@@ -1173,8 +1206,8 @@ APDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        case SQL_DESC_DATETIME_INTERVAL_PRECISION:
        case SQL_DESC_LENGTH:
        default:ret = SQL_ERROR;
-           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
-                   "invalid descriptor identifer");
+           DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+                   "invalid descriptor identifer"); 
    }
    switch (rettype)
    {
@@ -1188,7 +1221,7 @@ APDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            *((void **) Value) = ptr;
            break;
    }
-
+           
    if (StringLength)
        *StringLength = len;
    return ret;
@@ -1255,10 +1288,10 @@ IRDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        case SQL_DESC_TYPE_NAME: /* read-only */
            rettype = SQL_NTS;
            bCallColAtt = TRUE;
-           break;
+           break; 
        default:ret = SQL_ERROR;
-           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
-               "invalid descriptor identifier");
+           DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invalid descriptor identifier"); 
    }
    if (bCallColAtt)
    {
@@ -1270,7 +1303,7 @@ IRDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            FieldIdentifier, Value, (SQLSMALLINT) BufferLength,
                &pcbL, &ival);
        len = pcbL;
-   }
+   } 
    switch (rettype)
    {
        case 0:
@@ -1287,7 +1320,7 @@ IRDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            *((void **) Value) = ptr;
            break;
    }
-
+           
    if (StringLength)
        *StringLength = len;
    return ret;
@@ -1309,10 +1342,11 @@ IPDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        case SQL_DESC_ARRAY_STATUS_PTR:
        case SQL_DESC_ROWS_PROCESSED_PTR:
        case SQL_DESC_COUNT:
-           break;
+           break; 
        default:if (RecNumber <= 0 || RecNumber > ipdopts->allocated)
            {
-               DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR,
+inolog("IPDGetField RecN=%d allocated=%d\n", RecNumber, ipdopts->allocated);
+               DC_set_error(desc, DESC_BAD_PARAMETER_NUMBER_ERROR,
                    "bad parameter number");
                return SQL_ERROR;
            }
@@ -1328,8 +1362,8 @@ IPDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            rettype = SQL_IS_POINTER;
            ptr = ipdopts->param_processed_ptr;
            break;
-       case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */
-           ival = SQL_UNNAMED;
+       case SQL_DESC_UNNAMED:
+           ival = NAME_IS_NULL(ipdopts->parameters[para_idx].paramName) ? SQL_UNNAMED : SQL_NAMED;
            break;
        case SQL_DESC_TYPE:
            switch (ipdopts->parameters[para_idx].SQLType)
@@ -1363,7 +1397,7 @@ IPDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            break;
        case SQL_DESC_COUNT:
            ival = ipdopts->allocated;
-           break;
+           break; 
        case SQL_DESC_PARAMETER_TYPE:
            ival = ipdopts->parameters[para_idx].paramType;
            break;
@@ -1388,7 +1422,7 @@ IPDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            break;
        case SQL_DESC_ALLOC_TYPE: /* read-only */
            ival = SQL_DESC_ALLOC_AUTO;
-           break;
+           break; 
        case SQL_DESC_CASE_SENSITIVE: /* read-only */
        case SQL_DESC_DATETIME_INTERVAL_PRECISION:
        case SQL_DESC_FIXED_PREC_SCALE: /* read-only */
@@ -1404,8 +1438,8 @@ IPDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
        case SQL_DESC_TYPE_NAME: /* read-only */
        case SQL_DESC_UNSIGNED: /* read-only */
        default:ret = SQL_ERROR;
-           DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
-               "invalid descriptor identifier");
+           DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+               "invalid descriptor identifier"); 
    }
    switch (rettype)
    {
@@ -1419,7 +1453,7 @@ IPDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber,
            *((void **)Value) = ptr;
            break;
    }
-
+           
    if (StringLength)
        *StringLength = len;
    return ret;
@@ -1436,7 +1470,7 @@ PGAPI_GetStmtAttr(HSTMT StatementHandle,
    RETCODE     ret = SQL_SUCCESS;
    int         len = 0;
 
-   mylog("%s Handle=%u %d\n", func, StatementHandle, Attribute);
+   mylog("%s Handle=%x %d\n", func, StatementHandle, Attribute);
    switch (Attribute)
    {
        case SQL_ATTR_FETCH_BOOKMARK_PTR:       /* 16 */
@@ -1492,7 +1526,7 @@ PGAPI_GetStmtAttr(HSTMT StatementHandle,
        case SQL_ATTR_IMP_ROW_DESC:     /* 10012 */
        case SQL_ATTR_IMP_PARAM_DESC:   /* 10013 */
            len = 4;
-           *((HSTMT *) Value) = descHandleFromStatementHandle(StatementHandle, Attribute);
+           *((HSTMT *) Value) = descHandleFromStatementHandle(StatementHandle, Attribute); 
            break;
 
        case SQL_ATTR_CURSOR_SCROLLABLE:        /* -1 */
@@ -1515,8 +1549,7 @@ PGAPI_GetStmtAttr(HSTMT StatementHandle,
        case SQL_ATTR_AUTO_IPD: /* 10001 */
            /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
        case SQL_ATTR_ENABLE_AUTO_IPD:  /* 15 */
-           SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "Unsupported statement option (Get)");
-           SC_log_error(func, "", stmt);
+           SC_set_error(stmt, DESC_INVALID_OPTION_IDENTIFIER, "Unsupported statement option (Get)", func);
            return SQL_ERROR;
        default:
            len = 4;
@@ -1533,30 +1566,46 @@ PGAPI_SetConnectAttr(HDBC ConnectionHandle,
            SQLINTEGER Attribute, PTR Value,
            SQLINTEGER StringLength)
 {
+   CSTR    func = "PGAPI_SetConnectAttr";
    ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
    RETCODE ret = SQL_SUCCESS;
 
-   mylog("PGAPI_SetConnectAttr %d\n", Attribute);
+   mylog("PGAPI_SetConnectAttr %d %x\n", Attribute, Value);
    switch (Attribute)
    {
-#if (ODBCVER >= 0x0351)
-       case SQL_ATTR_ANSI_APP:
-           if (Value == (PTR) SQL_AA_TRUE)
-               conn->unicode = 0;
-           break;
-#endif
        case SQL_ATTR_METADATA_ID:
-           conn->stmtOptions.metadata_id = (SQLUINTEGER) ((unsigned long) Value);
+           conn->stmtOptions.metadata_id = (SQLUINTEGER) Value;
            break;
+#if (ODBCVER >= 0x0351)
+       case SQL_ATTR_ANSI_APP:
+           if (SQL_AA_FALSE != (SQLINTEGER) Value)
+           {
+               mylog("the application is ansi\n");
+               if (CC_is_in_unicode_driver(conn)) /* the driver is unicode */
+                   CC_set_in_ansi_app(conn); /* but the app is ansi */
+           }
+           else
+           {
+               mylog("the application is unicode\n");
+           }
+           /*return SQL_ERROR;*/
+           return SQL_SUCCESS;
+#endif /* ODBCVER */
+       case SQL_ATTR_ENLIST_IN_DTC:
+#ifdef WIN32
+#ifdef _HANDLE_ENLIST_IN_DTC_
+           mylog("SQL_ATTR_ENLIST_IN_DTC %x request received\n", Value);
+           return EnlistInDtc(conn, Value, conn->connInfo.xa_opt); /* telling a lie */
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
+#endif /* WIN32 */
        case SQL_ATTR_ASYNC_ENABLE:
        case SQL_ATTR_AUTO_IPD:
        case SQL_ATTR_CONNECTION_DEAD:
        case SQL_ATTR_CONNECTION_TIMEOUT:
-       case SQL_ATTR_ENLIST_IN_DTC:
-           CC_set_error(conn, STMT_OPTION_NOT_FOR_THE_DRIVER, "Unsupported connect attribute (Set)");
+           CC_set_error(conn, CONN_OPTION_NOT_FOR_THE_DRIVER, "Unsupported connect attribute (Set)", func);
            return SQL_ERROR;
        default:
-           ret = PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, Value);
+           ret = PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value);
    }
    return ret;
 }
@@ -1572,7 +1621,7 @@ PGAPI_GetDescField(SQLHDESC DescriptorHandle,
    RETCODE     ret = SQL_SUCCESS;
    DescriptorClass *desc = (DescriptorClass *) DescriptorHandle;
 
-   mylog("%s h=%u rec=%d field=%d blen=%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, BufferLength);
+   mylog("%s h=%x rec=%d field=%d blen=%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, BufferLength);
    switch (desc->desc_type)
    {
        case SQL_ATTR_APP_ROW_DESC:
@@ -1588,7 +1637,7 @@ PGAPI_GetDescField(SQLHDESC DescriptorHandle,
            ret = IPDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
            break;
        default:ret = SQL_ERROR;
-           DC_set_error(desc, STMT_INTERNAL_ERROR, "Error not implemented");
+           DC_set_error(desc, DESC_INTERNAL_ERROR, "Error not implemented");
    }
    if (ret == SQL_ERROR)
    {
@@ -1596,17 +1645,17 @@ PGAPI_GetDescField(SQLHDESC DescriptorHandle,
        {
            switch (DC_get_errornumber(desc))
            {
-               case STMT_INVALID_DESCRIPTOR_IDENTIFIER:
+               case DESC_INVALID_DESCRIPTOR_IDENTIFIER:
                    DC_set_errormsg(desc, "can't SQLGetDescField for this descriptor identifier");
                    break;
-               case STMT_INVALID_COLUMN_NUMBER_ERROR:
+               case DESC_INVALID_COLUMN_NUMBER_ERROR:
                    DC_set_errormsg(desc, "can't SQLGetDescField for this column number");
                    break;
-               case STMT_BAD_PARAMETER_NUMBER_ERROR:
+               case DESC_BAD_PARAMETER_NUMBER_ERROR:
                    DC_set_errormsg(desc, "can't SQLGetDescField for this parameter number");
                    break;
            }
-       }
+       } 
        DC_log_error(func, "", desc);
    }
    return ret;
@@ -1622,7 +1671,7 @@ PGAPI_SetDescField(SQLHDESC DescriptorHandle,
    RETCODE     ret = SQL_SUCCESS;
    DescriptorClass *desc = (DescriptorClass *) DescriptorHandle;
 
-   mylog("%s h=%u rec=%d field=%d val=%x,%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, Value, BufferLength);
+   mylog("%s h=%x rec=%d field=%d val=%x,%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, Value, BufferLength);
    switch (desc->desc_type)
    {
        case SQL_ATTR_APP_ROW_DESC:
@@ -1638,7 +1687,7 @@ PGAPI_SetDescField(SQLHDESC DescriptorHandle,
            ret = IPDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength);
            break;
        default:ret = SQL_ERROR;
-           DC_set_error(desc, STMT_INTERNAL_ERROR, "Error not implemented");
+           DC_set_error(desc, DESC_INTERNAL_ERROR, "Error not implemented");
    }
    if (ret == SQL_ERROR)
    {
@@ -1646,17 +1695,17 @@ PGAPI_SetDescField(SQLHDESC DescriptorHandle,
        {
            switch (DC_get_errornumber(desc))
            {
-               case STMT_INVALID_DESCRIPTOR_IDENTIFIER:
+               case DESC_INVALID_DESCRIPTOR_IDENTIFIER:
                    DC_set_errormsg(desc, "can't SQLSetDescField for this descriptor identifier");
-               case STMT_INVALID_COLUMN_NUMBER_ERROR:
+               case DESC_INVALID_COLUMN_NUMBER_ERROR:
                    DC_set_errormsg(desc, "can't SQLSetDescField for this column number");
                    break;
-               case STMT_BAD_PARAMETER_NUMBER_ERROR:
+               case DESC_BAD_PARAMETER_NUMBER_ERROR:
                    DC_set_errormsg(desc, "can't SQLSetDescField for this parameter number");
                    break;
                break;
            }
-       }
+       } 
        DC_log_error(func, "", desc);
    }
    return ret;
@@ -1668,10 +1717,11 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle,
        SQLINTEGER Attribute, PTR Value,
        SQLINTEGER StringLength)
 {
+   RETCODE ret = SQL_SUCCESS;
    CSTR func = "PGAPI_SetStmtAttr";
    StatementClass *stmt = (StatementClass *) StatementHandle;
 
-   mylog("%s Handle=%u %d,%u\n", func, StatementHandle, Attribute, Value);
+   mylog("%s Handle=%x %d,%u\n", func, StatementHandle, Attribute, Value);
    switch (Attribute)
    {
        case SQL_ATTR_CURSOR_SCROLLABLE:        /* -1 */
@@ -1680,6 +1730,8 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle,
        case SQL_ATTR_ENABLE_AUTO_IPD:  /* 15 */
 
        case SQL_ATTR_AUTO_IPD: /* 10001 */
+           SC_set_error(stmt, DESC_OPTION_NOT_FOR_THE_DRIVER, "Unsupported statement option (Set)", func);
+           return SQL_ERROR;
        /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
        case SQL_ATTR_IMP_ROW_DESC: /* 10012 (read-only) */
        case SQL_ATTR_IMP_PARAM_DESC:   /* 10013 (read-only) */
@@ -1688,30 +1740,30 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle,
             * case SQL_ATTR_PREDICATE_PTR: case
             * SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR:
             */
-           SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "Unsupported statement option (Set)");
-           SC_log_error(func, "", stmt);
+           SC_set_error(stmt, DESC_INVALID_OPTION_IDENTIFIER, "Unsupported statement option (Set)", func);
            return SQL_ERROR;
 
        case SQL_ATTR_METADATA_ID:      /* 10014 */
-           stmt->options.metadata_id = (SQLUINTEGER) ((unsigned long) Value);
+           stmt->options.metadata_id = (SQLUINTEGER) Value; 
            break;
        case SQL_ATTR_APP_ROW_DESC:     /* 10010 */
-           if ((PTR) SQL_NULL_HDESC == Value)
+           if (SQL_NULL_HDESC == Value)
            {
                stmt->ard = &(stmt->ardi);
            }
            else
-           {
+           { 
                stmt->ard = (ARDClass *) Value;
+inolog("set ard=%x\n", stmt->ard);
            }
            break;
        case SQL_ATTR_APP_PARAM_DESC:   /* 10011 */
-           if ((PTR) SQL_NULL_HDESC == Value)
+           if (SQL_NULL_HDESC == Value)
            {
                stmt->apd = &(stmt->apdi);
            }
            else
-           {
+           { 
                stmt->apd = (APDClass *) Value;
            }
            break;
@@ -1722,7 +1774,7 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle,
            SC_get_APDF(stmt)->param_offset_ptr = (UInt4 *) Value;
            break;
        case SQL_ATTR_PARAM_BIND_TYPE:  /* 18 */
-           SC_get_APDF(stmt)->param_bind_type = (SQLUINTEGER) ((unsigned long) Value);
+           SC_get_APDF(stmt)->param_bind_type = (SQLUINTEGER) Value;
            break;
        case SQL_ATTR_PARAM_OPERATION_PTR:      /* 19 */
            SC_get_APDF(stmt)->param_operation_ptr = Value;
@@ -1734,7 +1786,7 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle,
            SC_get_IPDF(stmt)->param_processed_ptr = (UInt4 *) Value;
            break;
        case SQL_ATTR_PARAMSET_SIZE:    /* 22 */
-           SC_get_APDF(stmt)->paramset_size = (SQLUINTEGER) ((unsigned long) Value);
+           SC_get_APDF(stmt)->paramset_size = (SQLUINTEGER) Value;
            break;
        case SQL_ATTR_ROW_BIND_OFFSET_PTR:      /* 23 */
            SC_get_ARDF(stmt)->row_offset_ptr = (UInt4 *) Value;
@@ -1749,18 +1801,17 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle,
            SC_get_IRDF(stmt)->rowsFetched = (UInt4 *) Value;
            break;
        case SQL_ATTR_ROW_ARRAY_SIZE:   /* 27 */
-           SC_get_ARDF(stmt)->size_of_rowset = (SQLUINTEGER) ((unsigned long) Value);
+           SC_get_ARDF(stmt)->size_of_rowset = (SQLUINTEGER) Value;
            break;
        default:
-           return PGAPI_SetStmtOption(StatementHandle, (UWORD) Attribute, (UDWORD) ((unsigned long) Value));
+           return PGAPI_SetStmtOption(StatementHandle, (UWORD) Attribute, (UDWORD) Value);
    }
    return SQL_SUCCESS;
 }
 
-#ifdef DRIVER_CURSOR_IMPLEMENT
 #define    CALC_BOOKMARK_ADDR(book, offset, bind_size, index) \
    (book->buffer + offset + \
-   (bind_size > 0 ? bind_size : (SQL_C_VARBOOKMARK == book->returntype ? book->buflen : sizeof(UInt4))) * index)
+   (bind_size > 0 ? bind_size : (SQL_C_VARBOOKMARK == book->returntype ? book->buflen : sizeof(UInt4))) * index)       
 
 /* SQL_NEED_DATA callback for PGAPI_BulkOperations */
 typedef struct
@@ -1773,7 +1824,7 @@ typedef struct
    int     idx, processed;
 }  bop_cdata;
 
-static
+static 
 RETCODE    bulk_ope_callback(RETCODE retcode, void *para)
 {
    RETCODE ret = retcode;
@@ -1803,7 +1854,7 @@ RETCODE   bulk_ope_callback(RETCODE retcode, void *para)
        if (SQL_ADD != s->operation)
        {
            memcpy(&global_idx, CALC_BOOKMARK_ADDR(bookmark, offset, bind_size, s->idx), sizeof(UInt4));
-           global_idx--;
+           global_idx = SC_resolve_bookmark(global_idx);
        }
        /* Note opts->row_operation_ptr is ignored */
        switch (s->operation)
@@ -1833,7 +1884,7 @@ RETCODE   bulk_ope_callback(RETCODE retcode, void *para)
    }
    conn = SC_get_conn(s->stmt);
    if (s->auto_commit_needed)
-       PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_ON);
+       PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
    irdflds = SC_get_IRDF(s->stmt);
    if (irdflds->rowsFetched)
        *(irdflds->rowsFetched) = s->processed;
@@ -1857,26 +1908,28 @@ PGAPI_BulkOperations(HSTMT hstmt, SQLSMALLINT operationX)
    s.operation = operationX;
    SC_clear_error(s.stmt);
    s.opts = SC_get_ARDF(s.stmt);
-
+   
    s.auto_commit_needed = FALSE;
    if (SQL_FETCH_BY_BOOKMARK != s.operation)
    {
        conn = SC_get_conn(s.stmt);
        if (s.auto_commit_needed = (char) CC_is_in_autocommit(conn), s.auto_commit_needed)
-           PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_OFF);
+           PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
    }
    if (SQL_ADD != s.operation)
    {
        if (!(bookmark = s.opts->bookmark) || !(bookmark->buffer))
        {
-           SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "bookmark isn't specified");
+           SC_set_error(s.stmt, DESC_INVALID_OPTION_IDENTIFIER, "bookmark isn't specified", func);
            return SQL_ERROR;
        }
    }
 
+   /* StartRollbackState(s.stmt); */
    s.need_data_callback = FALSE;
    ret = bulk_ope_callback(SQL_SUCCESS, &s);
+   if (s.stmt->internal)
+       ret = DiscardStatementSvp(s.stmt, ret, FALSE);
    return ret;
-}
-#endif /* DRIVER_CURSOR_IMPLEMENT */
-
+}  
+#endif /* ODBCVER >= 0x0300 */
index 59b0f9bac9affed734d7ac079aee34807df6dea1..8341de82528011c1b01396684648eca3e761b226 100644 (file)
 /* Internal flags for catalog functions */
 #define    PODBC_NOT_SEARCH_PATTERN    1L
 #define    PODBC_SEARCH_PUBLIC_SCHEMA  (1L << 1)
+#define    PODBC_SEARCH_BY_IDS     (1L << 2)
 /* Internal flags for PGAPI_Exec... functions */
 #define    PODBC_WITH_HOLD         1L
+#define    PODBC_PER_STATEMENT_ROLLBACK    (1L << 1)
 /* Flags for the error handling */
 #define    PODBC_ALLOW_PARTIAL_EXTRACT 1L
 #define    PODBC_ERROR_CLEAR       (1L << 1)
@@ -24,80 +26,63 @@ RETCODE SQL_API PGAPI_AllocConnect(HENV EnvironmentHandle,
 RETCODE SQL_API PGAPI_AllocEnv(HENV FAR * EnvironmentHandle);
 RETCODE SQL_API PGAPI_AllocStmt(HDBC ConnectionHandle,
                HSTMT *StatementHandle);
-RETCODE SQL_API PGAPI_BindCol( 
-           HSTMT hstmt,
-           SQLUSMALLINT icol, 
-           SQLSMALLINT fCType,
-           PTR rgbValue, 
-           SQLINTEGER cbValueMax,
-           SQLINTEGER *pcbValue);
+RETCODE SQL_API PGAPI_BindCol(HSTMT StatementHandle,
+             SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType,
+             PTR TargetValue, SQLLEN BufferLength,
+             SQLLEN *StrLen_or_Ind);
 RETCODE SQL_API PGAPI_Cancel(HSTMT StatementHandle);
 RETCODE SQL_API PGAPI_Columns(HSTMT StatementHandle,
-             SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
-             SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
-             SQLCHAR *TableName, SQLSMALLINT NameLength3,
-             SQLCHAR *ColumnName, SQLSMALLINT NameLength4,
-             UWORD flag);
+             const SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
+             const SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
+             const SQLCHAR *TableName, SQLSMALLINT NameLength3,
+             const SQLCHAR *ColumnName, SQLSMALLINT NameLength4,
+             UWORD flag,
+             UInt4 reloid,
+             Int2 attnum);
 RETCODE SQL_API PGAPI_Connect(HDBC ConnectionHandle,
-             SQLCHAR *ServerName, SQLSMALLINT NameLength1,
-             SQLCHAR *UserName, SQLSMALLINT NameLength2,
-             SQLCHAR *Authentication, SQLSMALLINT NameLength3);
+       const SQLCHAR *ServerName, SQLSMALLINT NameLength1,
+       const SQLCHAR *UserName, SQLSMALLINT NameLength2,
+       const SQLCHAR *Authentication, SQLSMALLINT NameLength3);
 RETCODE SQL_API PGAPI_DriverConnect(HDBC hdbc, HWND hwnd,
-                   UCHAR FAR * szConnStrIn, SWORD cbConnStrIn,
-                   UCHAR FAR * szConnStrOut, SWORD cbConnStrOutMax,
-                   SWORD FAR * pcbConnStrOut, UWORD fDriverCompletion);
+       const SQLCHAR FAR * szConnStrIn, SQLSMALLINT cbConnStrIn,
+       SQLCHAR FAR * szConnStrOut, SQLSMALLINT cbConnStrOutMax,
+       SQLSMALLINT FAR * pcbConnStrOut, SQLUSMALLINT fDriverCompletion);
 RETCODE SQL_API PGAPI_BrowseConnect(HDBC hdbc,
-                   SQLCHAR *szConnStrIn, SQLSMALLINT cbConnStrIn,
+                   const SQLCHAR *szConnStrIn, SQLSMALLINT cbConnStrIn,
                    SQLCHAR *szConnStrOut, SQLSMALLINT cbConnStrOutMax,
                    SQLSMALLINT *pcbConnStrOut);
 RETCODE SQL_API PGAPI_DataSources(HENV EnvironmentHandle,
-                 SQLUSMALLINT Direction, SQLCHAR *ServerName,
+                 SQLUSMALLINT Direction, const SQLCHAR *ServerName,
                  SQLSMALLINT BufferLength1, SQLSMALLINT *NameLength1,
-                 SQLCHAR *Description, SQLSMALLINT BufferLength2,
+                 const SQLCHAR *Description, SQLSMALLINT BufferLength2,
                  SQLSMALLINT *NameLength2);
 RETCODE SQL_API PGAPI_DescribeCol(HSTMT StatementHandle,
                  SQLUSMALLINT ColumnNumber, SQLCHAR *ColumnName,
                  SQLSMALLINT BufferLength, SQLSMALLINT *NameLength,
-                 SQLSMALLINT *DataType, SQLUINTEGER *ColumnSize,
+                 SQLSMALLINT *DataType, SQLULEN *ColumnSize,
                  SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable);
 RETCODE SQL_API PGAPI_Disconnect(HDBC ConnectionHandle);
-RETCODE SQL_API PGAPI_Error(HENV henv,
-           HDBC hdbc, 
-           HSTMT hstmt,
-           SQLCHAR *szSqlState,
-           SQLINTEGER *pfNativeError,
-           SQLCHAR *szErrorMsg, 
-           SQLSMALLINT cbErrorMsgMax,
-           SQLSMALLINT *pcbErrorMsg);
+RETCODE SQL_API PGAPI_Error(HENV EnvironmentHandle,
+           HDBC ConnectionHandle, HSTMT StatementHandle,
+           SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+           SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+           SQLSMALLINT *TextLength);
 /* Helper functions for Error handling */
-RETCODE SQL_API PGAPI_EnvError(HENV henv, 
-           SWORD RecNumber,
-           SQLCHAR *szSqlState, 
-           SQLINTEGER *pfNativeError,
-           SQLCHAR *szErrorMsg, 
-           SQLSMALLINT cbErrorMsgMax,
-           SQLSMALLINT *pcbErrorMsg, 
-           UWORD flag);
-RETCODE SQL_API PGAPI_ConnectError(HDBC hdbc, 
-           SWORD RecNumber,
-           SQLCHAR *szSqlState, 
-           SQLINTEGER *pfNativeError,
-           SQLCHAR *szErrorMsg, 
-           SQLSMALLINT cbErrorMsgMax,
-           SQLSMALLINT *pcbErrorMsg, 
-           UWORD flag);
-RETCODE SQL_API PGAPI_StmtError(HSTMT hstmt, 
-           SWORD RecNumber,
-           SQLCHAR *szSqlState, 
-           SQLINTEGER *pfNativeError,
-           SQLCHAR *szErrorMsg, 
-           SQLSMALLINT cbErrorMsgMax,
-           SQLSMALLINT *pcbErrorMsg, 
-           UWORD flag);
-RETCODE SQL_API PGAPI_ExecDirect(HSTMT hstmt,
-           SQLCHAR *szSqlStr, 
-           SQLINTEGER cbSqlStr, 
-           UWORD flag);
+RETCODE SQL_API PGAPI_EnvError(HENV EnvironmentHandle, SQLSMALLINT RecNumber,
+           SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+           SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+           SQLSMALLINT *TextLength, UWORD flag);
+RETCODE SQL_API PGAPI_ConnectError(HDBC ConnectionHandle, SQLSMALLINT RecNumber,
+           SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+           SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+           SQLSMALLINT *TextLength, UWORD flag);
+RETCODE SQL_API PGAPI_StmtError(HSTMT StatementHandle, SQLSMALLINT RecNumber,
+           SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+           SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+           SQLSMALLINT *TextLength, UWORD flag);
+
+RETCODE SQL_API PGAPI_ExecDirect(HSTMT StatementHandle,
+       const SQLCHAR *StatementText, SQLINTEGER TextLength, UWORD flag);
 RETCODE SQL_API PGAPI_Execute(HSTMT StatementHandle, UWORD flag);
 RETCODE SQL_API PGAPI_Fetch(HSTMT StatementHandle);
 RETCODE SQL_API PGAPI_FreeConnect(HDBC ConnectionHandle);
@@ -109,12 +94,10 @@ RETCODE SQL_API PGAPI_GetConnectOption(HDBC ConnectionHandle,
 RETCODE SQL_API PGAPI_GetCursorName(HSTMT StatementHandle,
                    SQLCHAR *CursorName, SQLSMALLINT BufferLength,
                    SQLSMALLINT *NameLength);
-RETCODE SQL_API PGAPI_GetData(HSTMT hstmt,
-               SQLUSMALLINT icol, 
-               SQLSMALLINT fCType,
-               PTR rgbValue, 
-               SQLINTEGER cbValueMax,
-               SQLINTEGER *pcbValue);
+RETCODE SQL_API PGAPI_GetData(HSTMT StatementHandle,
+             SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType,
+             PTR TargetValue, SQLLEN BufferLength,
+             SQLLEN *StrLen_or_Ind);
 RETCODE SQL_API PGAPI_GetFunctions(HDBC ConnectionHandle,
                   SQLUSMALLINT FunctionId, SQLUSMALLINT *Supported);
 RETCODE SQL_API PGAPI_GetFunctions30(HDBC ConnectionHandle,
@@ -133,43 +116,39 @@ RETCODE SQL_API PGAPI_NumResultCols(HSTMT StatementHandle,
                    SQLSMALLINT *ColumnCount);
 RETCODE SQL_API PGAPI_ParamData(HSTMT StatementHandle,
                PTR *Value);
-RETCODE SQL_API PGAPI_Prepare(HSTMT hstmt,
-               SQLCHAR *szSqlStr, 
-               SQLINTEGER cbSqlStr);
-RETCODE SQL_API PGAPI_PutData(HSTMT hstmt,
-               PTR rgbValue, 
-               SQLINTEGER cbValue);
-RETCODE SQL_API PGAPI_RowCount(HSTMT hstmt,
-               SQLINTEGER *pcrow);
-RETCODE SQL_API PGAPI_SetConnectOption(HDBC hdbc,
-                   SQLUSMALLINT fOption, 
-                   SQLPOINTER vParam);
+RETCODE SQL_API PGAPI_Prepare(HSTMT StatementHandle,
+             const SQLCHAR *StatementText, SQLINTEGER TextLength);
+RETCODE SQL_API PGAPI_PutData(HSTMT StatementHandle,
+             PTR Data, SQLLEN StrLen_or_Ind);
+RETCODE SQL_API PGAPI_RowCount(HSTMT StatementHandle,
+              SQLLEN *RowCount);
+RETCODE SQL_API PGAPI_SetConnectOption(HDBC ConnectionHandle,
+                      SQLUSMALLINT Option, SQLUINTEGER Value);
 RETCODE SQL_API PGAPI_SetCursorName(HSTMT StatementHandle,
-                   SQLCHAR *CursorName, SQLSMALLINT NameLength);
+                   const SQLCHAR *CursorName, SQLSMALLINT NameLength);
 RETCODE SQL_API PGAPI_SetParam(HSTMT StatementHandle,
               SQLUSMALLINT ParameterNumber, SQLSMALLINT ValueType,
-              SQLSMALLINT ParameterType, SQLUINTEGER LengthPrecision,
+              SQLSMALLINT ParameterType, SQLULEN LengthPrecision,
               SQLSMALLINT ParameterScale, PTR ParameterValue,
-              SQLINTEGER *StrLen_or_Ind);
-RETCODE SQL_API PGAPI_SetStmtOption(HSTMT hstmt,
-                   SQLUSMALLINT fOption, 
-                   SQLUINTEGER vParam);
+              SQLLEN *StrLen_or_Ind);
+RETCODE SQL_API PGAPI_SetStmtOption(HSTMT StatementHandle,
+                   SQLUSMALLINT Option, SQLULEN Value);
 RETCODE SQL_API PGAPI_SpecialColumns(HSTMT StatementHandle,
-                    SQLUSMALLINT IdentifierType, SQLCHAR *CatalogName,
-                    SQLSMALLINT NameLength1, SQLCHAR *SchemaName,
-                    SQLSMALLINT NameLength2, SQLCHAR *TableName,
+                    SQLUSMALLINT IdentifierType, const SQLCHAR *CatalogName,
+                    SQLSMALLINT NameLength1, const SQLCHAR *SchemaName,
+                    SQLSMALLINT NameLength2, const SQLCHAR *TableName,
                     SQLSMALLINT NameLength3, SQLUSMALLINT Scope,
                     SQLUSMALLINT Nullable);
 RETCODE SQL_API PGAPI_Statistics(HSTMT StatementHandle,
-                SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
-                SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
-                SQLCHAR *TableName, SQLSMALLINT NameLength3,
+                const SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
+                const SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
+                const SQLCHAR *TableName, SQLSMALLINT NameLength3,
                 SQLUSMALLINT Unique, SQLUSMALLINT Reserved);
 RETCODE SQL_API PGAPI_Tables(HSTMT StatementHandle,
-            SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
-            SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
-            SQLCHAR *TableName, SQLSMALLINT NameLength3,
-            SQLCHAR *TableType, SQLSMALLINT NameLength4);
+            const SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
+            const SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
+            const SQLCHAR *TableName, SQLSMALLINT NameLength3,
+            const SQLCHAR *TableType, SQLSMALLINT NameLength4);
 RETCODE SQL_API PGAPI_Transact(HENV EnvironmentHandle,
               HDBC ConnectionHandle, SQLUSMALLINT CompletionType);
 RETCODE SQL_API PGAPI_ColAttributes(
@@ -179,49 +158,52 @@ RETCODE SQL_API PGAPI_ColAttributes(
                    PTR rgbDesc,
                    SQLSMALLINT cbDescMax,
                    SQLSMALLINT *pcbDesc,
-                   SQLINTEGER *pfDesc);
+                   SQLLEN *pfDesc);
 RETCODE SQL_API PGAPI_ColumnPrivileges(
                       HSTMT hstmt,
-                      SQLCHAR *szCatalogName,
+                      const SQLCHAR *szCatalogName,
                       SQLSMALLINT cbCatalogName,
-                      SQLCHAR *szSchemaName,
+                      const SQLCHAR *szSchemaName,
                       SQLSMALLINT cbSchemaName,
-                      SQLCHAR *szTableName,
+                      const SQLCHAR *szTableName,
                       SQLSMALLINT cbTableName,
-                      SQLCHAR *szColumnName,
-                      SQLSMALLINT cbColumnName);
-RETCODE SQL_API PGAPI_DescribeParam(HSTMT hstmt,
+                      const SQLCHAR *szColumnName,
+                      SQLSMALLINT cbColumnName,
+                      UWORD flag);
+RETCODE SQL_API PGAPI_DescribeParam(
+                   HSTMT hstmt,
                    SQLUSMALLINT ipar,
                    SQLSMALLINT *pfSqlType,
-                   SQLUINTEGER *pcbColDef,
+                   SQLULEN *pcbParamDef,
                    SQLSMALLINT *pibScale,
                    SQLSMALLINT *pfNullable);
-RETCODE SQL_API PGAPI_ExtendedFetch(HSTMT hstmt,
+RETCODE SQL_API PGAPI_ExtendedFetch(
+                   HSTMT hstmt,
                    SQLUSMALLINT fFetchType,
-                   SQLINTEGER irow,
-                   SQLUINTEGER *pcrow,
+                   SQLLEN irow,
+                   SQLULEN *pcrow,
                    SQLUSMALLINT *rgfRowStatus,
-                   SQLINTEGER bookmark_offset,
+                   SQLINTEGER FetchOffset,
                    SQLINTEGER rowsetSize);
 RETCODE SQL_API PGAPI_ForeignKeys(
                  HSTMT hstmt,
-                 SQLCHAR *szPkCatalogName,
+                 const SQLCHAR *szPkCatalogName,
                  SQLSMALLINT cbPkCatalogName,
-                 SQLCHAR *szPkSchemaName,
+                 const SQLCHAR *szPkSchemaName,
                  SQLSMALLINT cbPkSchemaName,
-                 SQLCHAR *szPkTableName,
+                 const SQLCHAR *szPkTableName,
                  SQLSMALLINT cbPkTableName,
-                 SQLCHAR *szFkCatalogName,
+                 const SQLCHAR *szFkCatalogName,
                  SQLSMALLINT cbFkCatalogName,
-                 SQLCHAR *szFkSchemaName,
+                 const SQLCHAR *szFkSchemaName,
                  SQLSMALLINT cbFkSchemaName,
-                 SQLCHAR *szFkTableName,
+                 const SQLCHAR *szFkTableName,
                  SQLSMALLINT cbFkTableName);
 RETCODE SQL_API PGAPI_MoreResults(
                  HSTMT hstmt);
 RETCODE SQL_API PGAPI_NativeSql(
                HDBC hdbc,
-               SQLCHAR *szSqlStrIn,
+               const SQLCHAR *szSqlStrIn,
                SQLINTEGER cbSqlStrIn,
                SQLCHAR *szSqlStr,
                SQLINTEGER cbSqlStrMax,
@@ -229,47 +211,49 @@ RETCODE SQL_API PGAPI_NativeSql(
 RETCODE SQL_API PGAPI_NumParams(
                HSTMT hstmt,
                SQLSMALLINT *pcpar);
-RETCODE SQL_API PGAPI_ParamOptions(HSTMT hstmt,
-                  SQLUINTEGER crow,
-                  SQLUINTEGER *pirow);
+RETCODE SQL_API PGAPI_ParamOptions(
+                  HSTMT hstmt,
+                  SQLULEN crow,
+                  SQLULEN *pirow);
 RETCODE SQL_API PGAPI_PrimaryKeys(
                  HSTMT hstmt,
-                 SQLCHAR *szCatalogName,
+                 const SQLCHAR *szCatalogName,
                  SQLSMALLINT cbCatalogName,
-                 SQLCHAR *szSchemaName,
+                 const SQLCHAR *szSchemaName,
                  SQLSMALLINT cbSchemaName,
-                 SQLCHAR *szTableName,
+                 const SQLCHAR *szTableName,
                  SQLSMALLINT cbTableName);
 RETCODE SQL_API PGAPI_ProcedureColumns(
                       HSTMT hstmt,
-                      SQLCHAR *szCatalogName,
+                      const SQLCHAR *szCatalogName,
                       SQLSMALLINT cbCatalogName,
-                      SQLCHAR *szSchemaName,
+                      const SQLCHAR *szSchemaName,
                       SQLSMALLINT cbSchemaName,
-                      SQLCHAR *szProcName,
+                      const SQLCHAR *szProcName,
                       SQLSMALLINT cbProcName,
-                      SQLCHAR *szColumnName,
-                      SQLSMALLINT cbColumnName);
+                      const SQLCHAR *szColumnName,
+                      SQLSMALLINT cbColumnName,
+                      UWORD flag);
 RETCODE SQL_API PGAPI_Procedures(
                 HSTMT hstmt,
-                SQLCHAR *szCatalogName,
+                const SQLCHAR *szCatalogName,
                 SQLSMALLINT cbCatalogName,
-                SQLCHAR *szSchemaName,
+                const SQLCHAR *szSchemaName,
                 SQLSMALLINT cbSchemaName,
-                SQLCHAR *szProcName,
+                const SQLCHAR *szProcName,
                 SQLSMALLINT cbProcName);
 RETCODE SQL_API PGAPI_SetPos(
             HSTMT hstmt,
-            SQLUSMALLINT irow,
+            SQLSETPOSIROW irow,
             SQLUSMALLINT fOption,
             SQLUSMALLINT fLock);
 RETCODE SQL_API PGAPI_TablePrivileges(
                      HSTMT hstmt,
-                     SQLCHAR *szCatalogName,
+                     const SQLCHAR *szCatalogName,
                      SQLSMALLINT cbCatalogName,
-                     SQLCHAR *szSchemaName,
+                     const SQLCHAR *szSchemaName,
                      SQLSMALLINT cbSchemaName,
-                     SQLCHAR *szTableName,
+                     const SQLCHAR *szTableName,
                      SQLSMALLINT cbTableName,
                      UWORD flag);
 RETCODE SQL_API PGAPI_BindParameter(
@@ -278,17 +262,18 @@ RETCODE SQL_API PGAPI_BindParameter(
                    SQLSMALLINT fParamType,
                    SQLSMALLINT fCType,
                    SQLSMALLINT fSqlType,
-                   SQLUINTEGER cbColDef,
+                   SQLULEN cbColDef,
                    SQLSMALLINT ibScale,
                    PTR rgbValue,
-                   SQLINTEGER cbValueMax,
-                   SQLINTEGER *pcbValue);
+                   SQLLEN cbValueMax,
+                   SQLLEN *pcbValue);
 RETCODE SQL_API PGAPI_SetScrollOptions(
                       HSTMT hstmt,
-                      UWORD fConcurrency,
-                      SDWORD crowKeyset,
-                      UWORD crowRowset);
+                      SQLUSMALLINT fConcurrency,
+                      SQLLEN crowKeyset,
+                      SQLUSMALLINT crowRowset);
 
+#if (ODBCVER >= 0x0300)
 RETCODE SQL_API PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
        SQLSMALLINT RecNumber, SQLCHAR *Sqlstate,
        SQLINTEGER *NativeError, SQLCHAR *MessageText,
@@ -322,13 +307,9 @@ RETCODE SQL_API PGAPI_SetDescField(SQLHDESC DescriptorHandle,
 RETCODE SQL_API PGAPI_GetDescField(SQLHDESC DescriptorHandle,
            SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
            PTR Value, SQLINTEGER BufferLength, SQLINTEGER *StringLength);
-RETCODE SQL_API PGAPI_DescError(SQLHDESC hdesc, 
-               SWORD RecNumber,
-               SQLCHAR *szSqlState, 
-               SQLINTEGER *pfNativeError,
-               SQLCHAR *szErrorMsg, 
-               SQLSMALLINT cbErrorMsgMax,
-               SQLSMALLINT *pcbErrorMsg, 
-               UWORD flag);
-           
+RETCODE SQL_API PGAPI_DescError(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber,
+           SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+           SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+           SQLSMALLINT *TextLength, UWORD flag);
+#endif /* ODBCVER */
 #endif   /* define_PG_API_FUNC_H__ */
index 509acc44c78116aca808f8bba7fefafb0dc5fb54..fbde73aef126ddc17a682828d6857163862b6040 100644 (file)
--- a/pgtypes.c
+++ b/pgtypes.c
@@ -24,6 +24,7 @@
 #include "environ.h"
 #include "qresult.h"
 
+#define    EXPERIMENTAL_CURRENTLY
 
 
 Int4       getCharColumnSize(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
@@ -78,7 +79,9 @@ Int2      sqlTypes[] = {
    /* SQL_BINARY, -- Commented out because VarBinary is more correct. */
    SQL_BIT,
    SQL_CHAR,
+#if (ODBCVER >= 0x0300)
    SQL_TYPE_DATE,
+#endif /* ODBCVER */
    SQL_DATE,
    SQL_DECIMAL,
    SQL_DOUBLE,
@@ -89,27 +92,29 @@ Int2        sqlTypes[] = {
    SQL_NUMERIC,
    SQL_REAL,
    SQL_SMALLINT,
+#if (ODBCVER >= 0x0300)
    SQL_TYPE_TIME,
    SQL_TYPE_TIMESTAMP,
+#endif /* ODBCVER */
    SQL_TIME,
    SQL_TIMESTAMP,
    SQL_TINYINT,
    SQL_VARBINARY,
    SQL_VARCHAR,
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
    SQL_WCHAR,
    SQL_WVARCHAR,
    SQL_WLONGVARCHAR,
-#endif
+#endif /* UNICODE_SUPPORT */
    0
 };
 
-#ifdef ODBCINT64
+#if (ODBCVER >= 0x0300) && defined(ODBCINT64)
 #define    ALLOWED_C_BIGINT    SQL_C_SBIGINT
 /* #define ALLOWED_C_BIGINT    SQL_C_CHAR */ /* Delphi should be either ? */
 #else
 #define    ALLOWED_C_BIGINT    SQL_C_CHAR
-#endif /* ODBCINT64 */
+#endif
 
 Int4
 sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
@@ -128,18 +133,20 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
            pgType = PG_TYPE_BPCHAR;
            break;
 
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
        case SQL_WCHAR:
            pgType = PG_TYPE_BPCHAR;
            break;
-#endif
+#endif /* UNICODE_SUPPORT */
 
        case SQL_BIT:
            pgType = ci->drivers.bools_as_char ? PG_TYPE_CHAR : PG_TYPE_BOOL;
            break;
 
-        case SQL_DATE:
+#if (ODBCVER >= 0x0300)
        case SQL_TYPE_DATE:
+#endif /* ODBCVER */
+       case SQL_DATE:
            pgType = PG_TYPE_DATE;
            break;
 
@@ -172,11 +179,11 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
            pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
            break;
 
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
        case SQL_WLONGVARCHAR:
            pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
            break;
-#endif
+#endif /* UNICODE_SUPPORT */
 
        case SQL_REAL:
            pgType = PG_TYPE_FLOAT4;
@@ -188,12 +195,16 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
            break;
 
        case SQL_TIME:
+#if (ODBCVER >= 0x0300)
        case SQL_TYPE_TIME:
+#endif /* ODBCVER */
            pgType = PG_TYPE_TIME;
            break;
 
        case SQL_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
        case SQL_TYPE_TIMESTAMP:
+#endif /* ODBCVER */
            pgType = PG_TYPE_DATETIME;
            break;
 
@@ -205,11 +216,11 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
            pgType = PG_TYPE_VARCHAR;
            break;
 
-#ifdef  UNICODE_SUPPORT
+#if    UNICODE_SUPPORT
        case SQL_WVARCHAR:
            pgType = PG_TYPE_VARCHAR;
            break;
-#endif
+#endif /* UNICODE_SUPPORT */
 
        default:
            pgType = 0;         /* ??? */
@@ -237,8 +248,9 @@ pgtype_to_concise_type(StatementClass *stmt, Int4 type, int col)
 {
    ConnectionClass *conn = SC_get_conn(stmt);
    ConnInfo    *ci = &(conn->connInfo);
-
+#if (ODBCVER >= 0x0300)
    EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
+#endif /* ODBCVER */
 
    switch (type)
    {
@@ -246,12 +258,11 @@ pgtype_to_concise_type(StatementClass *stmt, Int4 type, int col)
        case PG_TYPE_CHAR2:
        case PG_TYPE_CHAR4:
        case PG_TYPE_CHAR8:
-           return SQL_CHAR;
-
+           return conn->unicode ? SQL_WCHAR : SQL_CHAR;
        case PG_TYPE_NAME:
-           return SQL_VARCHAR;
+           return conn->unicode ? SQL_WVARCHAR : SQL_VARCHAR;
 
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
        case PG_TYPE_BPCHAR:
            if (col >= 0 &&
                getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
@@ -268,21 +279,22 @@ pgtype_to_concise_type(StatementClass *stmt, Int4 type, int col)
            return ci->drivers.text_as_longvarchar ? 
                (conn->unicode ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR) :
                (conn->unicode ? SQL_WVARCHAR : SQL_VARCHAR);
-#else   
-       case PG_TYPE_BPCHAR:     
-           if (col >= 0 && 
-               getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)      
-               return SQL_LONGVARCHAR;      
-           return SQL_CHAR;     
-    
-       case PG_TYPE_VARCHAR:    
-           if (col >= 0 &&      
-               getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)      
-               return SQL_LONGVARCHAR;      
-           return SQL_VARCHAR;      
-    
-       case PG_TYPE_TEXT:   
-           return ci->drivers.text_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;      
+
+#else
+       case PG_TYPE_BPCHAR:
+           if (col >= 0 &&
+               getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
+               return SQL_LONGVARCHAR;
+           return SQL_CHAR;
+
+       case PG_TYPE_VARCHAR:
+           if (col >= 0 &&
+               getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
+               return SQL_LONGVARCHAR;
+           return SQL_VARCHAR;
+
+       case PG_TYPE_TEXT:
+           return ci->drivers.text_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
 #endif /* UNICODE_SUPPORT */
 
        case PG_TYPE_BYTEA:
@@ -307,8 +319,11 @@ pgtype_to_concise_type(StatementClass *stmt, Int4 type, int col)
                return ci->int8_as;
            if (conn->ms_jet) 
                return SQL_NUMERIC; /* maybe a little better than SQL_VARCHAR */
-           
+#if (ODBCVER >= 0x0300)
            return SQL_BIGINT;
+#else
+           return SQL_VARCHAR;
+#endif /* ODBCVER */
 
        case PG_TYPE_NUMERIC:
            return SQL_NUMERIC;
@@ -318,19 +333,25 @@ pgtype_to_concise_type(StatementClass *stmt, Int4 type, int col)
        case PG_TYPE_FLOAT8:
            return SQL_FLOAT;
        case PG_TYPE_DATE:
+#if (ODBCVER >= 0x0300)
            if (EN_is_odbc3(env))
                return SQL_TYPE_DATE;
+#endif /* ODBCVER */
            return SQL_DATE;
        case PG_TYPE_TIME:
+#if (ODBCVER >= 0x0300)
            if (EN_is_odbc3(env))
                return SQL_TYPE_TIME;
+#endif /* ODBCVER */
            return SQL_TIME;
        case PG_TYPE_ABSTIME:
        case PG_TYPE_DATETIME:
        case PG_TYPE_TIMESTAMP_NO_TMZONE:
        case PG_TYPE_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
            if (EN_is_odbc3(env))
                return SQL_TYPE_TIMESTAMP;
+#endif /* ODBCVER */
            return SQL_TIMESTAMP;
        case PG_TYPE_MONEY:
            return SQL_FLOAT;
@@ -348,6 +369,10 @@ pgtype_to_concise_type(StatementClass *stmt, Int4 type, int col)
            if (type == stmt->hdbc->lobj_type)
                return SQL_LONGVARBINARY;
 
+#ifdef EXPERIMENTAL_CURRENTLY
+           if (conn->unicode)
+               return ci->drivers.unknowns_as_longvarchar ? SQL_WLONGVARCHAR : SQL_WVARCHAR;
+#endif /* EXPERIMENTAL_CURRENTLY */
            return ci->drivers.unknowns_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
    }
 }
@@ -359,10 +384,12 @@ pgtype_to_sqldesctype(StatementClass *stmt, Int4 type, int col)
 
    switch (rettype = pgtype_to_concise_type(stmt, type, col))
    {
+#if (ODBCVER >= 0x0300)
        case SQL_TYPE_DATE:
        case SQL_TYPE_TIME:
        case SQL_TYPE_TIMESTAMP:
            return SQL_DATETIME;
+#endif /* ODBCVER */
    }
    return rettype;
 }
@@ -372,12 +399,14 @@ pgtype_to_datetime_sub(StatementClass *stmt, Int4 type)
 {
    switch (pgtype_to_concise_type(stmt, type, PG_STATIC))
    {
+#if (ODBCVER >= 0x0300)
        case SQL_TYPE_DATE:
            return SQL_CODE_DATE;
        case SQL_TYPE_TIME:
            return SQL_CODE_TIME;
        case SQL_TYPE_TIMESTAMP:
            return SQL_CODE_TIMESTAMP;
+#endif /* ODBCVER */
    }
    return -1;
 }
@@ -388,15 +417,17 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
 {
    ConnectionClass *conn = SC_get_conn(stmt);
    ConnInfo    *ci = &(conn->connInfo);
-
+#if (ODBCVER >= 0x0300)
    EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
-
+#endif /* ODBCVER */
 
    switch (type)
    {
        case PG_TYPE_INT8:
+#if (ODBCVER >= 0x0300)
            if (!conn->ms_jet)
                return ALLOWED_C_BIGINT;
+#endif /* ODBCVER */
            return SQL_C_CHAR;
        case PG_TYPE_NUMERIC:
            return SQL_C_CHAR;
@@ -411,19 +442,25 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
        case PG_TYPE_FLOAT8:
            return SQL_C_DOUBLE;
        case PG_TYPE_DATE:
+#if (ODBCVER >= 0x0300)
            if (EN_is_odbc3(env))
                return SQL_C_TYPE_DATE;
+#endif /* ODBCVER */
            return SQL_C_DATE;
        case PG_TYPE_TIME:
+#if (ODBCVER >= 0x0300)
            if (EN_is_odbc3(env))
                return SQL_C_TYPE_TIME;
+#endif /* ODBCVER */
            return SQL_C_TIME;
        case PG_TYPE_ABSTIME:
        case PG_TYPE_DATETIME:
        case PG_TYPE_TIMESTAMP_NO_TMZONE:
        case PG_TYPE_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
            if (EN_is_odbc3(env))
                return SQL_C_TYPE_TIMESTAMP;
+#endif /* ODBCVER */
            return SQL_C_TIMESTAMP;
        case PG_TYPE_MONEY:
            return SQL_C_FLOAT;
@@ -434,20 +471,29 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
            return SQL_C_BINARY;
        case PG_TYPE_LO_UNDEFINED:
            return SQL_C_BINARY;
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
        case PG_TYPE_BPCHAR:
        case PG_TYPE_VARCHAR:
        case PG_TYPE_TEXT:
-           if (conn->unicode && ! conn->ms_jet && ! stmt->manual_result)
+           if (CC_is_in_unicode_driver(conn)
+#ifdef NOT_USED
+               && ! stmt->catalog_result)
+#endif /* NOT USED */
+               )
                return SQL_C_WCHAR;
            return SQL_C_CHAR;
-#endif
+#endif /* UNICODE_SUPPORT */
 
        default:
            /* hack until permanent type is available */
            if (type == stmt->hdbc->lobj_type)
                return SQL_C_BINARY;
 
+           /* Experimental, Does this work ? */
+#ifdef EXPERIMENTAL_CURRENTLY
+           if (conn->unicode)
+               return SQL_C_WCHAR;
+#endif /* EXPERIMENTAL_CURRENTLY */
            return SQL_C_CHAR;
    }
 }
@@ -484,6 +530,7 @@ pgtype_to_name(StatementClass *stmt, Int4 type)
        case PG_TYPE_OID:
            return "oid";
        case PG_TYPE_INT4:
+inolog("pgtype_to_name int4\n");
            return "int4";
        case PG_TYPE_FLOAT4:
            return "float4";
@@ -534,7 +581,7 @@ static Int2
 getNumericDecimalDigits(StatementClass *stmt, Int4 type, int col)
 {
    Int4        atttypmod = -1, default_decimal_digits = 6;
-   QResultClass *result;
+   QResultClass    *result;
    ColumnInfoClass *flds;
 
    mylog("getNumericDecimalDigits: type=%d, col=%d\n", type, col);
@@ -548,22 +595,19 @@ getNumericDecimalDigits(StatementClass *stmt, Int4 type, int col)
     * Manual Result Sets -- use assigned column width (i.e., from
     * set_tuplefield_string)
     */
-   if (stmt->manual_result)
+   atttypmod = QR_get_atttypmod(result, col);
+   if (atttypmod > -1)
+       return (atttypmod & 0xffff);
+   if (stmt->catalog_result)
    {
        flds = result->fields;
        if (flds)
        {
-           atttypmod = flds->atttypmod[col];
-           if (atttypmod < 0 && flds->adtsize[col] > 0)
+           if (flds->adtsize[col] > 0)
                return flds->adtsize[col];
        }
-       if (atttypmod < 0)
-           return default_decimal_digits;
+       return default_decimal_digits;
    }
-   else 
-       atttypmod = QR_get_atttypmod(result, col);
-   if (atttypmod > -1)
-       return (atttypmod & 0xffff);
    else
    {
        Int4 dsp_size = QR_get_display_size(result, col);
@@ -576,11 +620,10 @@ getNumericDecimalDigits(StatementClass *stmt, Int4 type, int col)
 }
 
 
-static Int4
+static SQLLEN
 getNumericColumnSize(StatementClass *stmt, Int4 type, int col)
 {
-   Int4    atttypmod = -1;
-   Int4    default_column_size = 28;
+   Int4    atttypmod = -1, max_column_size = PG_NUMERIC_MAX_PRECISION + PG_NUMERIC_MAX_SCALE, default_column_size = 28;
    QResultClass *result;
    ColumnInfoClass *flds;
 
@@ -595,22 +638,19 @@ getNumericColumnSize(StatementClass *stmt, Int4 type, int col)
     * Manual Result Sets -- use assigned column width (i.e., from
     * set_tuplefield_string)
     */
-   if (stmt->manual_result)
+   atttypmod = QR_get_atttypmod(result, col);
+   if (atttypmod > -1)
+       return (atttypmod >> 16) & 0xffff;
+   if (stmt->catalog_result)
    {
        flds = result->fields;
        if (flds)
        {
-           atttypmod = flds->atttypmod[col];
-           if (atttypmod < 0 && flds->adtsize[col] > 0)
+           if (flds->adtsize[col] > 0)
                return 2 * flds->adtsize[col];
        }
-       if (atttypmod < 0)
-           return default_column_size;
+       return default_column_size;
    }
-   else
-       atttypmod = QR_get_atttypmod(result, col);
-   if (atttypmod > -1)
-       return (atttypmod >> 16) & 0xffff;
    else
    {
        Int4    dsp_size = QR_get_display_size(result, col);
@@ -627,12 +667,10 @@ getNumericColumnSize(StatementClass *stmt, Int4 type, int col)
 Int4
 getCharColumnSize(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
 {
-   int         p = -1, attlen = -1,
-               maxsize;
-   QResultClass *result;
-   ColumnInfoClass *flds;
+   int     p = -1, attlen = -1, adtsize = -1, maxsize;
+   QResultClass    *result;
    ConnectionClass *conn = SC_get_conn(stmt);
-   ConnInfo   *ci = &(conn->connInfo);
+   ConnInfo    *ci = &(conn->connInfo);
 
    mylog("getCharColumnSize: type=%d, col=%d, unknown = %d\n", type, col, handle_unknown_size_as);
 
@@ -677,16 +715,15 @@ getCharColumnSize(StatementClass *stmt, Int4 type, int col, int handle_unknown_s
        return maxsize;
 
    /*
-    * Manual Result Sets -- use assigned column width (i.e., from
+    * Catalog Result Sets -- use assigned column width (i.e., from
     * set_tuplefield_string)
     */
-   if (stmt->manual_result)
+   adtsize = QR_get_fieldsize(result, col);
+   if (adtsize > 0)
+       return adtsize;
+   if (stmt->catalog_result)
    {
-       flds = result->fields;
-       if (flds)
-           return flds->adtsize[col];
-       else
-           return maxsize;
+       return maxsize;
    }
 
    p = QR_get_display_size(result, col); /* longest */
@@ -702,15 +739,33 @@ getCharColumnSize(StatementClass *stmt, Int4 type, int col, int handle_unknown_s
            case PG_TYPE_BPCHAR:
                if (conn->unicode || conn->ms_jet)
                    return attlen;
+#if (ODBCVER >= 0x0300)
                return attlen;
+#endif /* ODBCVER */
+               return p;
        }
    }
 
+   if (maxsize <= 0)
+       return maxsize;
    /* The type is really unknown */
-   if (type == PG_TYPE_BPCHAR || handle_unknown_size_as == UNKNOWNS_AS_LONGEST)
+   if (type == PG_TYPE_BPCHAR)
+   {
+       mylog("getCharColumnSize: BP_CHAR LONGEST: p = %d\n", p);
+       if (p > 0)
+           return p;
+   }
+   switch (type)
+   {
+       case PG_TYPE_BPCHAR:
+       case PG_TYPE_VARCHAR:
+       case PG_TYPE_TEXT:
+           return maxsize;
+   }
+   if (handle_unknown_size_as == UNKNOWNS_AS_LONGEST)
    {
        mylog("getCharColumnSize: LONGEST: p = %d\n", p);
-       if (p >= 0)
+       if (p > 0)
            return p;
    }
 
@@ -738,7 +793,6 @@ getTimestampDecimalDigits(StatementClass *stmt, Int4 type, int col)
    ConnectionClass *conn = SC_get_conn(stmt);
    Int4        atttypmod;
    QResultClass *result;
-   ColumnInfoClass *flds;
 
    mylog("getTimestampDecimalDigits: type=%d, col=%d\n", type, col);
 
@@ -749,20 +803,7 @@ getTimestampDecimalDigits(StatementClass *stmt, Int4 type, int col)
 
    result = SC_get_Curres(stmt);
 
-   /*
-    * Manual Result Sets -- use assigned column width (i.e., from
-    * set_tuplefield_string)
-    */
-   atttypmod = 0;
-   if (stmt->manual_result)
-   {
-       flds = result->fields;
-       if (flds)
-           atttypmod = flds->atttypmod[col];
-       mylog("atttypmod1=%d\n", atttypmod);
-   }
-   else
-       atttypmod = QR_get_atttypmod(result, col);
+   atttypmod = QR_get_atttypmod(result, col);
    mylog("atttypmod2=%d\n", atttypmod);
    return (atttypmod > -1 ? atttypmod : 6);
 }
@@ -807,7 +848,7 @@ getTimestampColumnSize(StatementClass *stmt, Int4 type, int col)
  * If col >= 0, then will attempt to get the info from the result set.
  * This is used for functions SQLDescribeCol and SQLColAttributes.
  */
-Int4
+SQLLEN
 pgtype_column_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
 {
    ConnectionClass *conn = SC_get_conn(stmt);
@@ -827,8 +868,11 @@ pgtype_column_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_
        case PG_TYPE_NAME:
            {
                int value = 0;
+               if (PG_VERSION_GT(conn, 7.4))
+                   value = CC_get_max_idlen(conn);
 #ifdef NAME_FIELD_SIZE
-               value = NAME_FIELD_SIZE;
+               else
+                   value = NAME_FIELD_SIZE;
 #endif /* NAME_FIELD_SIZE */
                if (0 == value)
                {
@@ -1001,13 +1045,16 @@ pgtype_buffer_length(StatementClass *stmt, Int4 type, int col, int handle_unknow
            {
            int coef = 1;
            Int4    prec = pgtype_column_size(stmt, type, col, handle_unknown_size_as), maxvarc;
+           if (SQL_NO_TOTAL == prec)
+               return prec;
+#ifdef UNICODE_SUPPORT
            if (conn->unicode)
-               return prec * 2;
+               return prec * WCLEN;
+#endif /* UNICODE_SUPPORT */
            /* after 7.2 */
            if (PG_VERSION_GE(conn, 7.2))
-               coef = 3;
-           else
-           if ((conn->connInfo).lf_conversion)
+               coef = conn->mb_maxbyte_per_char;
+           if (coef < 2 && (conn->connInfo).lf_conversion)
                /* CR -> CR/LF */
                coef = 2;
            if (coef == 1)
@@ -1078,13 +1125,17 @@ pgtype_transfer_octet_length(StatementClass *stmt, Int4 type, int col, int handl
    {
        case PG_TYPE_VARCHAR:
        case PG_TYPE_BPCHAR:
+       case PG_TYPE_TEXT:
+           if (SQL_NO_TOTAL == prec)
+               return prec;
+#ifdef UNICODE_SUPPORT
            if (conn->unicode)
-               return prec * 2;
+               return prec * WCLEN;
+#endif /* UNICODE_SUPPORT */
            /* after 7.2 */
            if (PG_VERSION_GE(conn, 7.2))
-               coef = 3;
-           else
-           if ((conn->connInfo).lf_conversion)
+               coef =conn->mb_maxbyte_per_char;
+           if (coef < 2 && (conn->connInfo).lf_conversion)
                /* CR -> CR/LF */
                coef = 2;
            if (coef == 1)
@@ -1095,6 +1146,9 @@ pgtype_transfer_octet_length(StatementClass *stmt, Int4 type, int col, int handl
            return coef * prec;
        case PG_TYPE_BYTEA:
            return prec;
+       default:
+           if (type == conn->lobj_type)
+               return prec;
    }
    return -1;
 }
@@ -1149,9 +1203,9 @@ pgtype_max_decimal_digits(StatementClass *stmt, Int4 type)
            return 0;
        case PG_TYPE_DATETIME:
        case PG_TYPE_TIMESTAMP_NO_TMZONE:
-           return getTimestampMaxDecimalDigits(stmt, type);
-       case PG_TYPE_NUMERIC:
            return 38;
+       case PG_TYPE_NUMERIC:
+           return getNumericDecimalDigits(stmt, type, -1);
        default:
            return -1;
    }
@@ -1424,17 +1478,23 @@ sqltype_to_default_ctype(const ConnectionClass *conn, Int2 sqltype)
        case SQL_LONGVARCHAR:
        case SQL_DECIMAL:
        case SQL_NUMERIC:
+#if (ODBCVER < 0x0300)
+       case SQL_BIGINT:
+           return SQL_C_CHAR;
+#else
            return SQL_C_CHAR;
        case SQL_BIGINT:
            return ALLOWED_C_BIGINT;
-#ifdef  UNICODE_SUPPORT
+#endif
+
+#ifdef UNICODE_SUPPORT
        case SQL_WCHAR:
        case SQL_WVARCHAR:
        case SQL_WLONGVARCHAR:
-           if (conn->ms_jet || ! conn->unicode)
+           if (!conn->unicode)
                return SQL_C_CHAR;
            return SQL_C_WCHAR;
-#endif
+#endif /* UNICODE_SUPPORT */
 
        case SQL_BIT:
            return SQL_C_BIT;
@@ -1469,6 +1529,7 @@ sqltype_to_default_ctype(const ConnectionClass *conn, Int2 sqltype)
        case SQL_TIMESTAMP:
            return SQL_C_TIMESTAMP;
 
+#if (ODBCVER >= 0x0300)
        case SQL_TYPE_DATE:
            return SQL_C_TYPE_DATE;
 
@@ -1477,6 +1538,7 @@ sqltype_to_default_ctype(const ConnectionClass *conn, Int2 sqltype)
 
        case SQL_TYPE_TIMESTAMP:
            return SQL_C_TYPE_TIMESTAMP;
+#endif /* ODBCVER */
 
        default:
            /* should never happen */
@@ -1520,22 +1582,28 @@ ctype_length(Int2 ctype)
            return sizeof(UCHAR);
 
        case SQL_C_DATE:
+#if (ODBCVER >= 0x0300)
        case SQL_C_TYPE_DATE:
+#endif /* ODBCVER */
            return sizeof(DATE_STRUCT);
 
        case SQL_C_TIME:
+#if (ODBCVER >= 0x0300)
        case SQL_C_TYPE_TIME:
+#endif /* ODBCVER */
            return sizeof(TIME_STRUCT);
 
        case SQL_C_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
        case SQL_C_TYPE_TIMESTAMP:
+#endif /* ODBCVER */
            return sizeof(TIMESTAMP_STRUCT);
 
        case SQL_C_BINARY:
        case SQL_C_CHAR:
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
        case SQL_C_WCHAR:
-#endif
+#endif /* UNICODE_SUPPORT */
            return 0;
 
        default:                /* should never happen */
index 140d8933ae426b04500494c4998827fff6b83e73..73c0e6fd340439ff1515f5abc969364a06c37aa0 100644 (file)
--- a/pgtypes.h
+++ b/pgtypes.h
@@ -54,6 +54,9 @@
 #define PG_TYPE_OIDINT2            810
 #define PG_TYPE_OIDINT4            910
 #define PG_TYPE_OIDNAME            911
+#define PG_TYPE_TEXTARRAY      1009
+#define PG_TYPE_BPCHARARRAY        1014
+#define PG_TYPE_VARCHARARRAY       1015
 #define PG_TYPE_BPCHAR         1042
 #define PG_TYPE_VARCHAR            1043
 #define PG_TYPE_DATE           1082
@@ -63,6 +66,8 @@
 #define PG_TYPE_TIME_WITH_TMZONE   1266        /* since 7.1 */
 #define PG_TYPE_TIMESTAMP      1296    /* deprecated since 7.0 */
 #define PG_TYPE_NUMERIC            1700
+#define PG_TYPE_RECORD         2249
+#define PG_TYPE_VOID           2278
 #define INTERNAL_ASIS_TYPE     (-9999)
 
 /* extern Int4 pgtypes_defined[]; */
@@ -80,7 +85,7 @@ Int2      pgtype_to_ctype(StatementClass *stmt, Int4 type);
 const char *pgtype_to_name(StatementClass *stmt, Int4 type);
 
 /* These functions can use static numbers or result sets(col parameter) */
-Int4       pgtype_column_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as); /* corresponds to "precision" in ODBC 2.x */
+SQLLEN     pgtype_column_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as); /* corresponds to "precision" in ODBC 2.x */
 Int4       pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as); /* "precsion in ODBC 3.x */ 
 Int4       pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
 Int4       pgtype_buffer_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
index b6fdc5b6b0665e3d8ef4b6628af34c64fc6b6bb7..a001a4f830fe660789d1ddaae696ab2b9588ba0c 100644 (file)
 #include "dlg_specific.h"
 #include "environ.h"
 
+#ifdef WIN32
+#include <winsock.h>
+#endif
+
 GLOBAL_VALUES globals;
 
 RETCODE SQL_API SQLDummyOrdinal(void);
 
 #if defined(WIN_MULTITHREAD_SUPPORT)
-extern CRITICAL_SECTION    qlog_cs, mylog_cs, conns_cs;
+extern CRITICAL_SECTION    qlog_cs, mylog_cs, conns_cs, common_cs;
 #elif defined(POSIX_MULTITHREAD_SUPPORT)
-extern pthread_mutex_t     qlog_cs, mylog_cs, conns_cs;
+extern pthread_mutex_t     qlog_cs, mylog_cs, conns_cs, common_cs;
 
 #ifdef POSIX_THREADMUTEX_SUPPORT
 #ifdef PG_RECURSIVE_MUTEXATTR
@@ -66,12 +70,14 @@ int initialize_global_cs(void)
    INIT_QLOG_CS;
    INIT_MYLOG_CS;
    INIT_CONNS_CS;
+   INIT_COMMON_CS;
 
    return 0;
 }
 
 static void finalize_global_cs(void)
 {
+   DELETE_COMMON_CS;
    DELETE_CONNS_CS;
    DELETE_QLOG_CS;
    DELETE_MYLOG_CS;
@@ -83,10 +89,28 @@ HINSTANCE NEAR s_hModule;       /* Saved module handle. */
 BOOL       WINAPI
 DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
 {
+   WORD        wVersionRequested;
+   WSADATA     wsaData;
+
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
            s_hModule = hInst;  /* Save for dialog boxes */
+
+           /* Load the WinSock Library */
+           wVersionRequested = MAKEWORD(1, 1);
+
+           if (WSAStartup(wVersionRequested, &wsaData))
+               return FALSE;
+
+           /* Verify that this is the minimum version of WinSock */
+           if (LOBYTE(wsaData.wVersion) != 1 ||
+               HIBYTE(wsaData.wVersion) != 1)
+           {
+               WSACleanup();
+               return FALSE;
+           }
+
            initialize_global_cs();
            getCommonDefaults(DBMS_NAME, ODBCINST_INI, NULL);
            break;
@@ -95,7 +119,10 @@ DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
            break;
 
        case DLL_PROCESS_DETACH:
+           mylog("DETACHING PROCESS\n");
+           /* my(q)log is unavailable from here */
            finalize_global_cs();
+           WSACleanup();
            return TRUE;
 
        case DLL_THREAD_DETACH:
@@ -112,13 +139,6 @@ DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
 
 #else                          /* not WIN32 */
 
-#ifndef TRUE
-#define TRUE   (BOOL)1
-#endif
-#ifndef FALSE
-#define FALSE  (BOOL)0
-#endif
-
 #ifdef __GNUC__
 
 /* This function is called at library initialization time. */
index 2ae050b910e646f8a100c13a53bad78eafa8839f..f7dcc88e7f81bf4c888876a2ea00af02429588b7 100644 (file)
@@ -5,13 +5,15 @@
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * $Id: psqlodbc.h,v 1.94 2006/01/26 18:44:28 luf Exp $
+ * $Id: psqlodbc.h,v 1.95 2006/04/08 16:30:02 dpage Exp $
  *
  */
 
 #ifndef __PSQLODBC_H__
 #define __PSQLODBC_H__
 
+/* #define __MS_REPORTS_ANSI_CHAR__ */
+
 #ifndef WIN32
 #include "config.h"
 #else
 
 #include <stdio.h>             /* for FILE* pointers: see GLOBAL_VALUES */
 #ifdef POSIX_MULTITHREAD_SUPPORT
-#define _XOPEN_SOURCE
 #include <pthread.h>
 #endif
 #include "version.h"
 
+#ifdef WIN32
+#include <delayimp.h>
+#endif /* WIN32 */
 /* Must come before sql.h */
 #ifndef ODBCVER
-#define ODBCVER                        0x0300
-#endif   /* ODBCVER */
+#define ODBCVER                        0x0250
+#endif   /* ODBCVER_REP */
 
 #define NAMEDATALEN_V72                    32
 #define NAMEDATALEN_V73                    64
 #ifndef    WIN32
 #undef WIN_MULTITHREAD_SUPPORT
 #endif
-
+#if defined(WIN32) || defined(WITH_UNIXODBC) || defined(WITH_IODBC)
 #include <sql.h>
 #include <sqlext.h>
-#if defined(UNICODE_SUPPORT) && !defined(WIN32)
-# include <sqlucode.h>
+#if defined(WIN32) && (_MSC_VER < 1300) /* In the case of below VC6 */
+#define SQLLEN SQLINTEGER 
+#define SQLULEN SQLUINTEGER
+#define SQLSETPOSIROW SQLUSMALLINT
+#endif
+#else
+#include "iodbc.h"
+#include "isql.h"
+#include "isqlext.h"
 #endif
 
 #if defined(WIN32)
 #elif defined(WITH_IODBC)
 #include <iodbcinst.h>
 #else
-#error "don't know where to get odbcinst.h"
+#include "gpps.h"
 #endif
 
+#include <libpq-fe.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 #ifndef WIN32
+#define Int4 long int
+#define UInt4 unsigned int
+#define Int2 short
+#define UInt2 unsigned short
 
-# if defined(HAVE_INTTYPES_H)
-#  include <inttypes.h>
-# else
-#  if defined(HAVE_STDINT_H)
-#   include <stdint.h>
-#  endif
-# endif
-
-# define Int4 int32_t
-# define UInt4 uint32_t
-# define Int2 int16_t
-# define UInt2 uint16_t
-
-# if !defined(WITH_UNIXODBC) && !defined(WITH_IODBC)
+#if !defined(WITH_UNIXODBC) && !defined(WITH_IODBC)
 typedef float SFLOAT;
 typedef double SDOUBLE;
-# endif
-
-# ifndef CALLBACK
-#  define CALLBACK
-# endif
-
-#else /* WIN32 */
-
-# define Int4 int
-# define UInt4 unsigned int
-# define Int2 short
-# define UInt2 unsigned short
-
 #endif
 
-#ifndef FALSE
-#define FALSE  (BOOL)0
-#endif
-#ifndef TRUE
-#define TRUE   (BOOL)1
+#ifndef CALLBACK
+#define CALLBACK
 #endif
 
+#else
+#define Int4 int
+#define UInt4 unsigned int
+#define Int2 short
+#define UInt2 unsigned short
+#endif
 
 #ifndef WIN32
 #define stricmp strcasecmp
 #define strnicmp strncasecmp
+#ifndef TRUE
+#define    TRUE    (BOOL)1
+#endif /* TRUE */
+#ifndef    FALSE
+#define    FALSE   (BOOL)0
+#endif /* FALSE */
 #else
 #define snprintf _snprintf
 #endif
@@ -120,42 +122,69 @@ typedef double SDOUBLE;
 #endif
 
 /* Driver stuff */
-#define DBMS_NAME              "PostgreSQL"
-#define DRIVER_ODBC_VER                "03.00"
 
-#ifdef  UNICODE_SUPPORT     
-#define DRIVERNAME             "PostgreSQL Unicode"     
+#define DRIVERNAME             "PostgreSQL ODBC"
+#if (ODBCVER >= 0x0300)
+#if (ODBCVER >= 0x0351)
+#define DRIVER_ODBC_VER                "03.51"
 #else
-#define DRIVERNAME             "PostgreSQL ANSI"
+#define DRIVER_ODBC_VER                "03.00"
+#endif /* ODBCVER 0x0351 */
+#ifndef DBMS_NAME
+#ifdef UNICODE_SUPPORT
+#define DBMS_NAME              "PostgreSQL35W"
+#else
+#define DBMS_NAME              "PostgreSQL"
 #endif /* UNICODE_SUPPORT */
+#endif /* DBMS_NAME */
+#else
+#define DRIVER_ODBC_VER                "02.50"
+#define DBMS_NAME              "PostgreSQL Legacy"
+#endif   /* ODBCVER */
 
 #ifdef WIN32
-#ifdef  UNICODE_SUPPORT
-#define DRIVER_FILE_NAME           "PSQLODBCW.DLL"
+#if (ODBCVER >= 0x0300)
+#ifdef UNICODE_SUPPORT
+#if (ODBCVER >= 0x0350)
+#define DRIVER_FILE_NAME           "PSQLODBC35W.DLL"
 #else
-#define DRIVER_FILE_NAME           "PSQLODBCA.DLL"
-#endif
+#define DRIVER_FILE_NAME           "PSQLODBC30W.DLL"
+#endif /* ODBCVER 0x0350 */
+#else
+#define DRIVER_FILE_NAME           "PSQLODBC.DLL"
+#endif   /* UNICODE_SUPPORT */
 #else
-#define DRIVER_FILE_NAME           "libpsqlodbc.so"
+#define DRIVER_FILE_NAME           "PSQLODBC25.DLL"
+#endif   /* ODBCVER 0x0300 */
+#else
+#define DRIVER_FILE_NAME           "psqlodbc30w.so"
 #endif   /* WIN32 */
 
+#define    NULL_CATALOG_NAME               ""
+
+/* ESCAPEs */
+#define    ESCAPE_IN_LITERAL               '\\'
+#define    BYTEA_ESCAPE_CHAR               '\\'
+#define    SEARCH_PATTERN_ESCAPE               '\\'
+#define    LITERAL_QUOTE                   '\''
+#define    IDENTIFIER_QUOTE                '\"'
+
 /* Limits */
 #define BLCKSZ                     4096
 #define MAXPGPATH                  1024
 
-#define MAX_MESSAGE_LEN                65536   /* This puts a limit on
-                            * query size but I don't */
                           /* see an easy way round this - DJP 24-1-2001 */
+#define MAX_MESSAGE_LEN                65536       /* This puts a limit on
+                                                * query size but I don't */
+ /* see an easy way round this - DJP 24-1-2001 */
 #define MAX_CONNECT_STRING         4096
 #define ERROR_MSG_LENGTH           4096
-#define SQLSTATE_LENGTH                8
-#define FETCH_MAX                  100     /* default number of rows to cache
-                            * for declare/fetch */
+#define FETCH_MAX                  100 /* default number of rows to cache
+                                        * for declare/fetch */
 #define TUPLE_MALLOC_INC           100
-#define SOCK_BUFFER_SIZE           8192    /* default socket buffer
-                            * size */
-#define MAX_CONNECTIONS                128     /* conns per environment
-                            * (arbitrary)  */
+#define SOCK_BUFFER_SIZE           4096        /* default socket buffer
+                                                * size */
+#define MAX_CONNECTIONS                128 /* conns per environment
+                                        * (arbitrary)  */
 #define MAX_FIELDS                 512
 #define BYTELEN                        8
 #define VARHDRSZ                   sizeof(Int4)
@@ -178,40 +207,49 @@ typedef double SDOUBLE;
 #define INDEX_KEYS_STORAGE_COUNT       32
 
 /* Registry length limits */
-#define LARGE_REGISTRY_LEN         4096    /* used for special cases */
-#define MEDIUM_REGISTRY_LEN            256     /* normal size for
-                            * user,database,etc. */
+#define LARGE_REGISTRY_LEN         4096        /* used for special cases */
+#define MEDIUM_REGISTRY_LEN            256 /* normal size for
+                                        * user,database,etc. */
 #define SMALL_REGISTRY_LEN         10  /* for 1/0 settings */
 
 
 /* These prefixes denote system tables */
 #define POSTGRES_SYS_PREFIX            "pg_"
-#define KEYS_TABLE             "dd_fkey"
+#define KEYS_TABLE                 "dd_fkey"
 
 /* Info limits */
 #define MAX_INFO_STRING                128
 #define MAX_KEYPARTS               20
-#define MAX_KEYLEN             512         /* max key of the form
-                                * "date+outlet+invoice" */
-#define MAX_ROW_SIZE               0       /* Unlimited rowsize with the
-                                * Tuple Toaster */
-#define MAX_STATEMENT_LEN          0       /* Unlimited statement size with
-                                * 7.0 */
+#define MAX_KEYLEN                 512 /* max key of the form
+                                        * "date+outlet+invoice" */
+#define MAX_ROW_SIZE               0   /* Unlimited rowsize with the
+                                        * Tuple Toaster */
+#define MAX_STATEMENT_LEN          0   /* Unlimited statement size with
+                                        * 7.0 */
 
 /* Previously, numerous query strings were defined of length MAX_STATEMENT_LEN */
 /* Now that's 0, lets use this instead. DJP 24-1-2001 */
 #define STD_STATEMENT_LEN          MAX_MESSAGE_LEN
 
+#define PG62                       "6.2"       /* "Protocol" key setting
+                                                * to force Postgres 6.2 */
+#define PG63                       "6.3"       /* "Protocol" key setting
+                                                * to force postgres 6.3 */
+#define PG64                       "6.4"
+#define PG74REJECTED                   "rejected7.4"
+#define PG74                       "7.4"
+
+typedef int    (*PQFUNC)();
+
 typedef struct ConnectionClass_ ConnectionClass;
 typedef struct StatementClass_ StatementClass;
 typedef struct QResultClass_ QResultClass;
+typedef struct SocketClass_ SocketClass;
 typedef struct BindInfoClass_ BindInfoClass;
 typedef struct ParameterInfoClass_ ParameterInfoClass;
 typedef struct ParameterImplClass_ ParameterImplClass;
 typedef struct ColumnInfoClass_ ColumnInfoClass;
-typedef struct TupleListClass_ TupleListClass;
 typedef struct EnvironmentClass_ EnvironmentClass;
-typedef struct TupleNode_ TupleNode;
 typedef struct TupleField_ TupleField;
 typedef struct KeySet_ KeySet;
 typedef struct Rollback_ Rollback;
@@ -236,7 +274,7 @@ typedef struct GlobalValues_
    char        ksqo;
    char        unique_index;
    char        onlyread;       /* readonly is reserved on Digital C++
-                        * compiler */
+                                * compiler */
    char        use_declarefetch;
    char        text_as_longvarchar;
    char        unknowns_as_longvarchar;
@@ -246,6 +284,7 @@ typedef struct GlobalValues_
    char        cancel_as_freestmt;
    char        extra_systable_prefixes[MEDIUM_REGISTRY_LEN];
    char        conn_settings[LARGE_REGISTRY_LEN];
+   char        protocol[SMALL_REGISTRY_LEN];
 } GLOBAL_VALUES;
 
 typedef struct StatementOptions_
@@ -258,7 +297,9 @@ typedef struct StatementOptions_
    int         retrieve_data;
    int         use_bookmarks;
    void            *bookmark_ptr;
+#if (ODBCVER >= 0x0300)
    int         metadata_id;
+#endif /* ODBCVER */
 } StatementOptions;
 
 /* Used to pass extra query info to send_query */
@@ -266,7 +307,7 @@ typedef struct QueryInfo_
 {
    int     row_size;
    QResultClass    *result_in;
-   char        *cursor;
+   const char  *cursor;
 } QueryInfo;
 
 /* Used to save the error information */
@@ -276,39 +317,37 @@ typedef struct
         SDWORD  errorsize;
         SWORD   recsize;
         SWORD   errorpos;
-        char    sqlstate[SQLSTATE_LENGTH];
+        char    sqlstate[8];
         Int4    diag_row_count;
         char    __error_message[1];
 }       PG_ErrorInfo;
-
 PG_ErrorInfo   *ER_Constructor(SDWORD errornumber, const char *errormsg);
+PG_ErrorInfo   *ER_Dup(const PG_ErrorInfo *from);
 void ER_Destructor(PG_ErrorInfo *);
-RETCODE SQL_API ER_ReturnError(PG_ErrorInfo *, SWORD, UCHAR FAR *,
-           SDWORD FAR *, UCHAR FAR *, SWORD, SWORD FAR *, UWORD);
+RETCODE SQL_API ER_ReturnError(PG_ErrorInfo **, SQLSMALLINT, UCHAR FAR *,
+       SQLINTEGER FAR *, UCHAR FAR *, SQLSMALLINT, SQLSMALLINT FAR *, UWORD);
 
 void       logs_on_off(int cnopen, int, int);
 
-#define PG_TYPE_LO_UNDEFINED       (-999)  /* hack until permanent
-                        * type available */
-#define PG_TYPE_LO_NAME            "lo"
-#define OID_ATTNUM         (-2)    /* the attnum in pg_index
-                        * of the oid */
+#define PG_TYPE_LO_UNDEFINED           (-999)      /* hack until permanent
+                                                * type available */
+#define PG_TYPE_LO_NAME                "lo"
+#define OID_ATTNUM                 (-2)        /* the attnum in pg_index
+                                                * of the oid */
 
 /* sizes */
-#define TEXT_FIELD_SIZE            8190    /* size of text fields
-                        * (not including null
-                        * term) */
-#define MAX_VARCHAR_SIZE       254     /* maximum size of a varchar (not
-                        * including null term) */
+#define TEXT_FIELD_SIZE                8190        /* size of text fields
+                                                * (not including null
+                                                * term) */
+#define MAX_VARCHAR_SIZE           254 /* maximum size of a varchar (not
+                                        * including null term) */
 
 #define PG_NUMERIC_MAX_PRECISION   1000
 #define PG_NUMERIC_MAX_SCALE       1000
 
 #define INFO_INQUIRY_LEN       8192    /* this seems sufficiently big for
-                        * queries used in info.c inoue
-                        * 2001/05/17 */
-
-#include "misc.h"
+                                        * queries used in info.c inoue
+                                        * 2001/05/17 */
 
 int    initialize_global_cs(void);
 #ifdef POSIX_MULTITHREAD_SUPPORT
@@ -320,20 +359,22 @@ int   initialize_global_cs(void);
 #ifdef POSIX_THREADMUTEX_SUPPORT
 const pthread_mutexattr_t *getMutexAttr(void);
 #endif /* POSIX_THREADMUTEX_SUPPORT */
-#ifdef  UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
 #define WCLEN sizeof(SQLWCHAR)
 UInt4  ucs2strlen(const SQLWCHAR *ucs2str);
-char   *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen, BOOL tolower);
+char   *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, Int4 *olen, BOOL tolower);
 UInt4  utf8_to_ucs2_lf(const char * utf8str, Int4 ilen, BOOL lfconv, SQLWCHAR *ucs2str, UInt4 buflen);
 #define    utf8_to_ucs2(utf8str, ilen, ucs2str, buflen) utf8_to_ucs2_lf(utf8str, ilen, FALSE, ucs2str, buflen)
 #endif /* UNICODE_SUPPORT */
 
-/*#define  _MEMORY_DEBUG_ */
 #ifdef _MEMORY_DEBUG_
 void       *debug_alloc(size_t);
 void       *debug_calloc(size_t, size_t);
 void       *debug_realloc(void *, size_t);
 char       *debug_strdup(const char *);
+void       *debug_memcpy(void *, const void *, size_t);
+void       *debug_memset(void *, int c, size_t);
+char       *debug_strcpy(char *, const char *);
 void       debug_free(void *);
 void       debug_memory_check(void);
 
@@ -342,6 +383,18 @@ void       debug_memory_check(void);
 #define calloc debug_calloc
 #define strdup debug_strdup
 #define free   debug_free
+#define strcpy debug_strcpy
+#define memcpy debug_memcpy
+#define memset debug_memset
 #endif   /* _MEMORY_DEBUG_ */
 
+#ifdef __cplusplus
+}
 #endif
+
+#include "misc.h"
+
+CSTR   NULL_STRING = "";
+CSTR   PRINT_NULL = "(null)";
+CSTR   OID_NAME = "oid";
+#endif /* __PSQLODBC_H__ */
index b2b5490702ab727ba6f9ffc52374cb617ac9a4b1..cced03b750e2a8fe9e98846cc37dffdf54f85a45 100644 (file)
@@ -1,4 +1,4 @@
-// Microsoft Visual C++ generated resource script.
+//Microsoft Developer Studio generated resource script.
 //
 #include "resource.h"
 
@@ -14,7 +14,7 @@
 #undef APSTUDIO_READONLY_SYMBOLS
 
 /////////////////////////////////////////////////////////////////////////////
-// Japanese resources
+// \93ú\96{\8cê resources
 
 #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN)
 #ifdef _WIN32
@@ -28,25 +28,23 @@ LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
 //
 
 DLG_CONFIG DIALOGEX 65, 43, 359, 219
-STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | 
-    WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-#ifdef UNICODE_SUPPORT
-CAPTION "PostgreSQL Unicode ODBC \83Z\83b\83g\83A\83b\83v"
-#else
-CAPTION "PostgreSQL ANSI ODBC \83Z\83b\83g\83A\83b\83v"
-#endif
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_VISIBLE | 
+    WS_CAPTION | WS_SYSMENU
+CAPTION "PostgreSQL Japanese ODBC \83Z\83b\83g\83A\83b\83v"
 FONT 9, "\82l\82\83S\83V\83b\83N", 0, 0, 0x1
 BEGIN
     RTEXT           "\83f\81|\83^\83\\81|\83X\96¼:(&N)",IDC_DSNAMETEXT,2,9,63,17,NOT 
                     WS_GROUP,WS_EX_TRANSPARENT | WS_EX_RIGHT
-    EDITTEXT        IDC_DSNAME,72,7,188,13,ES_AUTOHSCROLL | WS_GROUP,
+    EDITTEXT        IDC_DSNAME,72,12,188,13,ES_AUTOHSCROLL | WS_GROUP,
                     WS_EX_TRANSPARENT
-    RTEXT           "\90à\96¾:(&D)",IDC_DESCTEXT,5,27,60,16,SS_CENTERIMAGE | NOT 
+    RTEXT           "\90à\96¾:(&D)",IDC_DESCTEXT,5,31,60,16,SS_CENTERIMAGE | NOT 
                     WS_GROUP,WS_EX_TRANSPARENT | WS_EX_RIGHT
-    EDITTEXT        IDC_DESC,72,28,189,13,ES_AUTOHSCROLL,WS_EX_TRANSPARENT
+    EDITTEXT        IDC_DESC,72,32,188,13,ES_AUTOHSCROLL,WS_EX_TRANSPARENT
     RTEXT           "SSL Mode:(&L)",IDC_STATIC,16,49,49,9,NOT WS_GROUP
     COMBOBOX        IDC_SSLMODE,72,47,90,56,CBS_DROPDOWNLIST | WS_VSCROLL | 
                     WS_TABSTOP
+    LTEXT           "libpq\83\89\83C\83u\83\89\83\8aload\95s\89Â:SSL\90Ú\91±\82Í\8eg\97p\82Å\82«\82Ü\82¹\82ñ",
+                    IDC_NOTICE_USER,165,50,190,10
     RTEXT           "\83T\81|\83o\81|\96¼:(&S)",IDC_STATIC,17,68,48,15,NOT WS_GROUP
     EDITTEXT        IDC_SERVER,72,66,203,14,ES_AUTOHSCROLL
     RTEXT           "\83f\81|\83^\83x\81|\83X\96¼:(&b)",IDC_STATIC,5,91,60,15,NOT WS_GROUP
@@ -64,27 +62,29 @@ BEGIN
     PUSHBUTTON      "\91S\91Ì\90Ý\92è",IDC_DRIVER,269,155,53,15
     PUSHBUTTON      "\83f\81|\83^\83\\81|\83X",IDC_DATASOURCE,269,132,53,15
     GROUPBOX        "\8aù\92è\82Ì\94F\8fØ",IDC_STATIC,11,119,235,59
-    LTEXT           "PostgreSQL Ver8.0  Copyright (C) 1998-2005 PostgreSQL Global Development Group",
+    LTEXT           "PostgreSQL Ver7.3  Copyright (C) 1998-2006; Insight Distribution Systems",
                     IDC_STATIC,36,186,302,9
-    LTEXT           "In the original form, Japanese patch Hiroshi-Saito",
+    LTEXT           "In the original form, Japanese patch Hiroshi-saito",
                     IDC_STATIC,35,198,295,8
+   // CONTROL         "IDB_BANNER",IDC_STATIC,"Static",SS_BITMAP,8,3,16,15,
+   //                 WS_EX_TRANSPARENT | WS_EX_STATICEDGE
     PUSHBUTTON      "\8aÇ\97\9d",IDC_MANAGEDSN,295,10,50,14
 END
 
-DLG_OPTIONS_DRV DIALOGEX 0, 0, 350, 241
-STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | 
-    WS_CAPTION | WS_SYSMENU
+DLG_OPTIONS_DRV DIALOG DISCARDABLE  0, 0, 350, 241
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
 CAPTION "\8d\82\93x\82È\90Ý\92è (\83f\81[\83^\83\\81[\83X\82P)"
-FONT 9, "\82l\82\83S\83V\83b\83N", 0, 0, 0x0
+FONT 9, "\82l\82\83S\83V\83b\83N"
 BEGIN
-    PUSHBUTTON      "\90Ý\92è1",IDPREVPAGE,5,5,40,15,WS_DISABLED
+    PUSHBUTTON      "\90Ý\92è1",IDPREVPAGE,5,5,40,15
     PUSHBUTTON      "\90Ý\92è2",IDNEXTPAGE,49,5,40,15
     CONTROL         "\88â\93`\93I\8dÅ\93K\89»\8f\88\97\9d\82ð\96³\8cø\82É\82·\82é(&O)",DRV_OPTIMIZER,"Button",
                     BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,26,140,10
     CONTROL         "\88ê\94Ê\83\8d\83O\8fo\97Í\82ð\82·\82é(&L) (C:\\psqlodbc.log)",DRV_COMMLOG,
                     "Button",BS_AUTOCHECKBOX | WS_TABSTOP,167,24,170,10
-    CONTROL         "&KSQO (¸´Ø°·°¾¯Ä\8dÅ\93K\89»\83I\83v\83V\83\87\83\93)",DRV_KSQO,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,15,41,145,10
+    CONTROL         "&KSQO (¸´Ø°·°¾¯Ä\8dÅ\93K\89»\83I\83v\83V\83\87\83\93)",DRV_KSQO,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,41,145,10
     CONTROL         "\83\86\83j\81|\83N\83C\83\93\83f\83b\83N\83X\82ð\8eg\82¤(&I)",DRV_UNIQUEINDEX,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,15,56,129,10
     CONTROL         "\83X\83e\81|\83g\83\81\83\93\83g\82Ì\8d\\95\89ð\90Í\82ð\8ds\82È\82¤(&a)",DRV_PARSE,"Button",
@@ -110,11 +110,11 @@ BEGIN
                     "Button",BS_AUTOCHECKBOX | WS_TABSTOP,123,132,117,10
     CONTROL         "Char\82Æ\82µ\82ÄBools\82ð\88µ\82¤",DRV_BOOLS_CHAR,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,243,132,96,10
-    LTEXT           "\83L\83\83\83b\83V\83\85\83T\83C\83Y:",IDC_STATIC,21,189,42,8
+    LTEXT           "·¬¯¼­»²½Þ:",IDC_STATIC,21,189,39,8
     EDITTEXT        DRV_CACHE_SIZE,69,187,35,12,ES_AUTOHSCROLL
     LTEXT           "\8dÅ\91å&Varchar:",IDC_STATIC,13,167,54,8
     EDITTEXT        DRV_VARCHAR_SIZE,70,166,35,12,ES_AUTOHSCROLL
-    LTEXT           "\8dÅ\91åLon&gVarChar:",IDC_STATIC,145,167,67,8
+    LTEXT           "\8dÅ\91åLon&gVarChar:",IDC_STATIC,148,168,66,8
     EDITTEXT        DRV_LONGVARCHAR_SIZE,219,166,35,12,ES_AUTOHSCROLL
     LTEXT           "¼½ÃÑðÌÞÙ ÌßŲ́¸½:",IDC_STATIC,140,189,74,9
     EDITTEXT        DRV_EXTRASYSTABLEPREFIXES,219,187,71,12,ES_AUTOHSCROLL
@@ -125,13 +125,13 @@ BEGIN
     GROUPBOX        "\82»\82Ì\91¼",IDC_STATIC,5,155,340,54
 END
 
-DLG_OPTIONS_DS DIALOGEX 0, 0, 306, 243
-STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | 
-    WS_CAPTION | WS_SYSMENU
+DLG_OPTIONS_DS DIALOG DISCARDABLE  0, 0, 306, 243
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
 CAPTION "\8d\82\93x\82È\90Ý\92è (\83f\81[\83^\83\\81[\83X\82Q)"
-FONT 9, "\82l\82\83S\83V\83b\83N", 0, 0, 0x0
+FONT 9, "\82l\82\83S\83V\83b\83N"
 BEGIN
-    PUSHBUTTON      "\90Ý\92è2",IDNEXTPAGE,49,5,40,15,WS_DISABLED
+    PUSHBUTTON      "\90Ý\92è2",IDNEXTPAGE,49,5,40,15
     PUSHBUTTON      "\90Ý\92è1",IDPREVPAGE,5,5,40,15
     CONTROL         "\83\8a\81|\83h\83I\83\93\83\8a\83B(&R)",DS_READONLY,"Button",
                     BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,26,102,10
@@ -163,14 +163,30 @@ BEGIN
                     WS_TABSTOP,184,108,40,10
     CONTROL         "int4",DS_INT8_AS_INT4,"Button",BS_AUTORADIOBUTTON | 
                     WS_TABSTOP,227,108,29,10
-    GROUPBOX        "OID \83I\83v\83V\83\87\83\93",IDC_STATIC,5,128,296,25
+    GROUPBOX        "\83v\83\8d\83g\83R\83\8b\83o\81|\83W\83\87\83\93",IDC_STATIC,5,128,150,25
+    CONTROL         "7.4+",DS_PG74,"Button",BS_AUTORADIOBUTTON | WS_GROUP,18,
+                    139,30,10
+    CONTROL         "6.4+",DS_PG64,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+                    52,139,30,10
+    CONTROL         "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+                    90,140,26,10
+    CONTROL         "6.2",DS_PG62,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+                    118,140,26,10
+    GROUPBOX        "\83G\83\89\81[\8e\9e\82Ì\83\8d\81[\83\8b\83o\83b\83N\94­\8ds",IDC_STATIC,160,128,130,25
+\81@\81@CONTROL         "\96³\82µ",DS_NO_ROLLBACK,"Button",BS_AUTORADIOBUTTON | 
+                    WS_GROUP,165,139,30,10
+    CONTROL         "\91S·¬Ý¾Ù",DS_TRANSACTION_ROLLBACK,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,195,140,50,10
+    CONTROL         "\95\92P\88Ê",DS_STATEMENT_ROLLBACK,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,250,140,35,10
+    GROUPBOX        "OID \83I\83v\83V\83\87\83\93",IDC_STATIC,5,158,296,25
     CONTROL         "\83J\83\89\83\80\97ñ\95\\8e¦(&C)",DS_SHOWOIDCOLUMN,"Button",
-                    BS_AUTOCHECKBOX | WS_GROUP,16,139,72,10
+                    BS_AUTOCHECKBOX | WS_GROUP,16,169,72,10
     CONTROL         "\83C\83\93\83f\83b\83N\83X\82ð\91\95\82¤(&I)",DS_FAKEOIDINDEX,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,107,139,95,10
-    LTEXT           "\90Ú\91±\8e\9e   \90Ý\92è:(&S)",IDC_STATIC,13,159,69,10,NOT 
+                    BS_AUTOCHECKBOX | WS_TABSTOP,107,169,95,10
+    LTEXT           "\90Ú\91±\8e\9e   \90Ý\92è:(&S)",IDC_STATIC,13,192,69,10,NOT 
                     WS_GROUP
-    EDITTEXT        DS_CONNSETTINGS,90,160,211,58,ES_MULTILINE | 
+    EDITTEXT        DS_CONNSETTINGS,90,191,211,27,ES_MULTILINE | 
                     ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | NOT 
                     WS_TABSTOP
     DEFPUSHBUTTON   "OK",IDOK,5,224,50,14,WS_GROUP
@@ -180,9 +196,9 @@ BEGIN
                     BS_AUTOCHECKBOX | WS_TABSTOP,15,85,87,10
 END
 
-DLG_OPTIONS_GLOBAL DIALOG  0, 0, 306, 87
-STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | 
-    WS_CAPTION | WS_SYSMENU
+DLG_OPTIONS_GLOBAL DIALOG DISCARDABLE  0, 0, 306, 87
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
 CAPTION "\8d\82\93x\82È\90Ý\92è(\91S\91Ì)"
 FONT 9, "\82l\82\83S\83V\83b\83N"
 BEGIN
@@ -198,17 +214,16 @@ BEGIN
                     IDC_STATIC,5,5,296,58
 END
 
-DLG_DRIVER_CHANGE DIALOGEX 0, 0, 306, 87
-STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | 
-    WS_SYSMENU
+DLG_DRIVER_CHANGE DIALOG DISCARDABLE  0, 0, 306, 87
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "\83h\83\89\83C\83o\81@\83A\83b\83v/\83_\83E\83\93"
-FONT 10, "Terminal", 0, 0, 0x0
+FONT 10, "Terminal"
 BEGIN
     DEFPUSHBUTTON   "OK",IDOK,82,68,50,14,WS_GROUP
     PUSHBUTTON      "\83L\83\83\83\93\83Z\83\8b",IDCANCEL,172,67,50,15
     GROUPBOX        "\83h\83\89\83C\83o\83\8a\83X\83g",IDC_STATIC,5,5,296,58
     LTEXT           "\83h\83\89\83C\83o\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢",IDC_STATIC,11,33,105,8
-    LISTBOX         IDC_DRIVER_LIST,117,23,151,32,LBS_SORT | 
+    LISTBOX         IDC_DRIVER_LIST,124,19,170,33,LBS_SORT | 
                     LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
 END
 
@@ -219,11 +234,13 @@ END
 //
 
 #ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO 
+GUIDELINES DESIGNINFO DISCARDABLE 
 BEGIN
     DLG_CONFIG, DIALOG
     BEGIN
         VERTGUIDE, 65
+        VERTGUIDE, 72
+        VERTGUIDE, 260
         BOTTOMMARGIN, 210
     END
 
@@ -268,19 +285,19 @@ END
 // TEXTINCLUDE
 //
 
-1 TEXTINCLUDE 
+1 TEXTINCLUDE DISCARDABLE 
 BEGIN
     "resource.h\0"
 END
 
-2 TEXTINCLUDE 
+2 TEXTINCLUDE DISCARDABLE 
 BEGIN
     "#include ""afxres.h""\r\n"
     "#include ""version.h""\r\n"
     "\0"
 END
 
-3 TEXTINCLUDE 
+3 TEXTINCLUDE DISCARDABLE 
 BEGIN
     "\r\n"
     "\0"
@@ -289,19 +306,20 @@ END
 #endif    // APSTUDIO_INVOKED
 
 
+#ifndef _MAC
 /////////////////////////////////////////////////////////////////////////////
 //
 // Version
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 8,1,2,0
- PRODUCTVERSION 8,1,2,0
+ FILEVERSION PG_DRVFILE_VERSION
+ PRODUCTVERSION PG_DRVFILE_VERSION
  FILEFLAGSMASK 0x3L
 #ifdef _DEBUG
- FILEFLAGS 0x1L
+ FILEFLAGS 0x9L
 #else
- FILEFLAGS 0x0L
+ FILEFLAGS 0x8L
 #endif
  FILEOS 0x4L
  FILETYPE 0x2L
@@ -309,36 +327,37 @@ VS_VERSION_INFO VERSIONINFO
 BEGIN
     BLOCK "StringFileInfo"
     BEGIN
-        BLOCK "040904e4"
+        BLOCK "041104e4"
         BEGIN
-#ifdef UNICODE_SUPPORT
-            VALUE "Comments", "PostgreSQL Unicode ODBC driver"
-#else
-            VALUE "Comments", "PostgreSQL ANSI ODBC driver"
-#endif
-            VALUE "CompanyName", "PostgreSQL Global Development Group"
-            VALUE "FileDescription", "PostgreSQL Driver"
-            VALUE "FileVersion", "08.01.0200"
-            VALUE "InternalName", "psqlodbc"
-            VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation.  Microsoft® is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation."
-            VALUE "OriginalFilename", "psqlodbc.dll"
-            VALUE "ProductName", "Microsoft Open Database Connectivity"
-            VALUE "ProductVersion", "08.01.0200"
+            VALUE "Comments", "PostgreSQL ODBC driver Japanese\0"
+            VALUE "CompanyName", "PostgreSQL Global Development Group\0"
+            VALUE "FileDescription", "PostgreSQL Driver Japanese\0"
+            VALUE "FileVersion", POSTGRES_RESOURCE_VERSION
+            VALUE "InternalName", "psqlodbc35w\0"
+            VALUE "LegalCopyright", "\0"
+            VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation.  Microsoft\83\87 is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
+            VALUE "OriginalFilename", "psqlodbc35w.dll\0"
+            VALUE "PrivateBuild", "for Japanese by Hiroshi Inoue & Hiroshi Saito\0"
+            VALUE "ProductName", "Microsoft Open Database Connectivity\0"
+            VALUE "ProductVersion", POSTGRES_RESOURCE_VERSION
+            VALUE "SpecialBuild", "\0"
         END
     END
     BLOCK "VarFileInfo"
     BEGIN
-        VALUE "Translation", 0x409, 1252
+        VALUE "Translation", 0x411, 1252
     END
 END
 
+#endif    // !_MAC
+
 
 /////////////////////////////////////////////////////////////////////////////
 //
 // String Table
 //
 
-STRINGTABLE 
+STRINGTABLE DISCARDABLE 
 BEGIN
     IDS_BADDSN              "DSN\83G\83\93\83g\83\8a\81|\82ª\95s\90³\82Å\82·\81B\8dÄ\93x\83`\83F\83b\83N\90Ý\92è\82µ\82Ä\82­\82¾\82³\82¢\81B."
     IDS_MSGTITLE            "DSN\95s\90³"
@@ -349,18 +368,22 @@ BEGIN
     IDS_ADVANCE_OPTION_DSN2 "\8d\82\93x\82È\90Ý\92è (%s \90Ý\92è2)"
     IDS_ADVANCE_OPTION_CON2 "\8d\82\93x\82È\90Ý\92è (\83R\83l\83N\83V\83\87\83\93\90Ý\92è2)"
     IDS_ADVANCE_CONNECTION  "\83R\83l\83N\83V\83\87\83\93"
+END
+
+STRINGTABLE DISCARDABLE 
+BEGIN
     IDS_SSLREQUEST_PREFER   "\97D\90æ"
     IDS_SSLREQUEST_ALLOW    "\8dl\97¶"
     IDS_SSLREQUEST_REQUIRE  "\95K\97v"
     IDS_SSLREQUEST_DISABLE  "\96³\8cø"
 END
 
-#endif    // Japanese resources
+#endif    // \93ú\96{\8cê resources
 /////////////////////////////////////////////////////////////////////////////
 
 
 /////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
+// \89p\8cê (\83A\83\81\83\8a\83J) resources
 
 #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
 #ifdef _WIN32
@@ -373,15 +396,11 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 // Dialog
 //
 
-DLG_CONFIG DIALOGEX 65, 43, 305, 130
-STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | 
-    WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-#ifdef UNICODE_SUPPORT
-CAPTION "PostgreSQL Unicode ODBC"
-#else
-CAPTION "PostgreSQL ANSI ODBC"
-#endif
-FONT 8, "MS Sans Serif"
+DLG_CONFIG DIALOG DISCARDABLE  65, 43, 305, 130
+STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "PostgreSQL ODBC Driver (psqlODBC) Setup"
+FONT 10, "Terminal"
 BEGIN
     RTEXT           "&Data Source",IDC_DSNAMETEXT,5,25,50,12,NOT WS_GROUP
     EDITTEXT        IDC_DSNAME,57,24,72,12,ES_AUTOHSCROLL | WS_GROUP
@@ -390,8 +409,10 @@ BEGIN
     RTEXT           "Data&base",IDC_STATIC,16,40,38,12,NOT WS_GROUP
     EDITTEXT        IDC_DATABASE,57,39,72,12,ES_AUTOHSCROLL
     RTEXT           "SS&L Mode",IDC_STATIC,145,40,45,12,NOT WS_GROUP
-    COMBOBOX        IDC_SSLMODE,192,36,104,50,CBS_DROPDOWNLIST | WS_VSCROLL |
+    COMBOBOX        IDC_SSLMODE,192,36,104,50,CBS_DROPDOWNLIST | WS_VSCROLL | 
                     WS_TABSTOP
+    LTEXT           "Couldn't load libpq\r\nSSL Mode is unavailable",
+                    IDC_NOTICE_USER,5,82,150,20
     RTEXT           "&Server",IDC_STATIC,26,55,29,12,NOT WS_GROUP
     EDITTEXT        IDC_SERVER,57,54,72,12,ES_AUTOHSCROLL
     RTEXT           "&Port",IDC_STATIC,168,56,22,12
@@ -410,116 +431,129 @@ BEGIN
     PUSHBUTTON      "Manage DSN",IDC_MANAGEDSN,240,101,52,14
 END
 
-DLG_OPTIONS_DRV DIALOGEX 0, 0, 303, 228
-STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | 
-    WS_SYSMENU
+DLG_OPTIONS_DRV DIALOG DISCARDABLE  0, 0, 287, 231
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "Advanced Options (DataSource)"
-FONT 8, "MS Sans Serif"
+FONT 10, "Terminal"
 BEGIN
-    PUSHBUTTON      "Page 1",IDPREVPAGE,5,5,40,15,WS_DISABLED
+    PUSHBUTTON      "Page 1",IDPREVPAGE,5,5,40,15
     PUSHBUTTON      "Page 2",IDNEXTPAGE,49,5,40,15
     CONTROL         "Disable Genetic &Optimizer",DRV_OPTIMIZER,"Button",
                     BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,26,116,10
     CONTROL         "Comm&Log (C:\\psqlodbc_xxxx.log)",DRV_COMMLOG,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,161,26,133,10
+                    BS_AUTOCHECKBOX | WS_TABSTOP,149,26,131,10
     CONTROL         "&KSQO(Keyset Query Optimization)",DRV_KSQO,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,15,41,132,10
     CONTROL         "Recognize Unique &Indexes",DRV_UNIQUEINDEX,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,15,56,110,10
     CONTROL         "P&arse Statements",DRV_PARSE,"Button",BS_AUTOCHECKBOX | 
-                    WS_TABSTOP,161,41,80,10
+                    WS_TABSTOP,149,41,80,10
     CONTROL         "&Use Declare/Fetch",DRV_USEDECLAREFETCH,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,15,71,83,10
     CONTROL         "Cancel as FreeStmt (Exp)",DRV_CANCELASFREESTMT,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,161,56,114,10
+                    BS_AUTOCHECKBOX | WS_TABSTOP,149,56,114,10
     CONTROL         "MyLog (C:\\mylog_xxxx.log)",DRV_DEBUG,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,161,71,112,10
-    GROUPBOX        "Unknown Sizes",IDC_STATIC,5,85,293,25
+                    BS_AUTOCHECKBOX | WS_TABSTOP,149,71,112,10
+    GROUPBOX        "Unknown Sizes",IDC_STATIC,5,85,277,25
     CONTROL         "Maximum",DRV_UNKNOWN_MAX,"Button",BS_AUTORADIOBUTTON | 
                     WS_GROUP | WS_TABSTOP,15,96,45,10
     CONTROL         "Don't Know",DRV_UNKNOWN_DONTKNOW,"Button",
                     BS_AUTORADIOBUTTON | WS_TABSTOP,105,96,53,10
     CONTROL         "Longest",DRV_UNKNOWN_LONGEST,"Button",
                     BS_AUTORADIOBUTTON | WS_TABSTOP,215,95,50,10
-    GROUPBOX        "Data Type Options",IDC_STATIC,5,115,293,25
+    GROUPBOX        "Data Type Options",IDC_STATIC,5,115,277,25
     CONTROL         "Text as LongVarChar",DRV_TEXT_LONGVARCHAR,"Button",
                     BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,125,90,10
     CONTROL         "Unknowns as LongVarChar",DRV_UNKNOWNS_LONGVARCHAR,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,125,105,10
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,125,105,10
     CONTROL         "Bools as Char",DRV_BOOLS_CHAR,"Button",BS_AUTOCHECKBOX | 
-                    WS_TABSTOP,226,125,67,10
-    LTEXT           "&Cache Size",IDC_STATIC,14,183,52,8
+                    WS_TABSTOP,215,125,67,10
+    LTEXT           "&Cache Size:",IDC_STATIC,14,183,52,8
     EDITTEXT        DRV_CACHE_SIZE,69,181,35,12,ES_AUTOHSCROLL
-    LTEXT           "Max &Varchar",IDC_STATIC,13,161,54,8
+    LTEXT           "Max &Varchar:",IDC_STATIC,13,161,54,8
     EDITTEXT        DRV_VARCHAR_SIZE,70,160,35,12,ES_AUTOHSCROLL
-    LTEXT           "Max Lon&gVarChar",IDC_STATIC,136,161,67,8
-    EDITTEXT        DRV_LONGVARCHAR_SIZE,215,160,35,12,ES_AUTOHSCROLL
-    LTEXT           "SysTable &Prefixes",IDC_STATIC,136,183,80,9
-    EDITTEXT        DRV_EXTRASYSTABLEPREFIXES,215,181,71,12,ES_AUTOHSCROLL
-    DEFPUSHBUTTON   "OK",IDOK,136,208,50,14,WS_GROUP
-    PUSHBUTTON      "Cancel",IDCANCEL,246,207,50,15
-    PUSHBUTTON      "Apply",IDAPPLY,191,208,50,14
-    PUSHBUTTON      "Defaults",IDDEFAULTS,5,207,50,15
-    GROUPBOX        "Miscellaneous",IDC_STATIC,5,145,293,58
+    LTEXT           "Max Lon&gVarChar:",IDC_STATIC,125,161,67,8
+    EDITTEXT        DRV_LONGVARCHAR_SIZE,199,160,35,12,ES_AUTOHSCROLL
+    LTEXT           "SysTable &Prefixes:",IDC_STATIC,126,178,61,18
+    EDITTEXT        DRV_EXTRASYSTABLEPREFIXES,199,181,71,12,ES_AUTOHSCROLL
+    DEFPUSHBUTTON   "OK",IDOK,5,212,50,14,WS_GROUP
+    PUSHBUTTON      "Cancel",IDCANCEL,81,211,50,15
+    PUSHBUTTON      "Apply",IDAPPLY,156,212,50,14
+    PUSHBUTTON      "Defaults",IDDEFAULTS,232,211,50,15
+    GROUPBOX        "Miscellaneous",IDC_STATIC,5,145,277,58
 END
 
-DLG_OPTIONS_DS DIALOGEX 0, 0, 287, 239
-STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | 
-    WS_SYSMENU
+DLG_OPTIONS_DS DIALOG DISCARDABLE  0, 0, 287, 234
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "Advanced Options (DataSource)"
-FONT 8, "MS Sans Serif"
+FONT 10, "Terminal"
 BEGIN
-    PUSHBUTTON      "Page 2",IDNEXTPAGE,49,5,40,15,WS_DISABLED
+    PUSHBUTTON      "Page 2",IDNEXTPAGE,49,5,40,15
     PUSHBUTTON      "Page 1",IDPREVPAGE,5,5,40,15
     CONTROL         "&Read Only",DS_READONLY,"Button",BS_AUTOCHECKBOX | 
                     WS_GROUP | WS_TABSTOP,15,26,102,10
     CONTROL         "Row &Versioning",DS_ROWVERSIONING,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,175,26,85,10
+                    BS_AUTOCHECKBOX | WS_TABSTOP,149,26,85,10
     CONTROL         "Show System &Tables",DS_SHOWSYSTEMTABLES,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,15,41,100,10
     CONTROL         "Disallow &Premature",DS_DISALLOWPREMATURE,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,175,41,85,10
+                    BS_AUTOCHECKBOX | WS_TABSTOP,149,41,85,10
     CONTROL         "LF <-> CR/LF conversion",DS_LFCONVERSION,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,15,56,106,10
     CONTROL         "True is -1",DS_TRUEISMINUS1,"Button",BS_AUTOCHECKBOX | 
-                    WS_TABSTOP,175,56,86,10
-    CONTROL         "Updatable Cursors (Experimental)",DS_UPDATABLECURSORS,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,70,147,10
+                    WS_TABSTOP,149,56,86,10
+    CONTROL         "Updatable Cursors",DS_UPDATABLECURSORS,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,15,71,87,10
     CONTROL         "Server side prepare",DS_SERVERSIDEPREPARE,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,175,71,90,10
+                    BS_AUTOCHECKBOX | WS_TABSTOP,149,71,90,10
     CONTROL         "bytea as LO",DS_BYTEAASLONGVARBINARY,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,16,84,87,10
-    GROUPBOX        "Int8 As",IDC_STATIC,5,97,277,25
+    GROUPBOX        "Int8 As",IDC_STATIC,5,95,277,25
     CONTROL         "default",DS_INT8_AS_DEFAULT,"Button",BS_AUTORADIOBUTTON | 
-                    WS_GROUP,12,108,40,10
+                    WS_GROUP,12,105,40,10
     CONTROL         "bigint",DS_INT8_AS_BIGINT,"Button",BS_AUTORADIOBUTTON | 
-                    WS_TABSTOP,55,108,35,10
+                    WS_TABSTOP,55,105,35,10
     CONTROL         "numeric",DS_INT8_AS_NUMERIC,"Button",BS_AUTORADIOBUTTON | 
-                    WS_TABSTOP,98,108,40,10
+                    WS_TABSTOP,98,105,40,10
     CONTROL         "varchar",DS_INT8_AS_VARCHAR,"Button",BS_AUTORADIOBUTTON | 
-                    WS_TABSTOP,141,108,40,10
+                    WS_TABSTOP,141,105,40,10
     CONTROL         "double",DS_INT8_AS_DOUBLE,"Button",BS_AUTORADIOBUTTON | 
-                    WS_TABSTOP,184,108,40,10
+                    WS_TABSTOP,184,105,40,10
     CONTROL         "int4",DS_INT8_AS_INT4,"Button",BS_AUTORADIOBUTTON | 
-                    WS_TABSTOP,227,108,29,10
-    GROUPBOX        "OID Options",IDC_STATIC,5,127,277,25
+                    WS_TABSTOP,227,105,29,10
+    GROUPBOX        "Protocol",IDC_STATIC,5,124,136,25
+    CONTROL         "7.4+",DS_PG74,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,
+                    136,31,10
+    CONTROL         "6.4+",DS_PG64,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+                    45,136,27,10
+    CONTROL         "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+                    79,136,26,10
+    CONTROL         "6.2",DS_PG62,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+                    110,136,26,10
+    GROUPBOX        "OID Options",IDC_STATIC,5,155,277,25
     CONTROL         "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX | 
-                    WS_GROUP | WS_TABSTOP,53,138,59,10
+                    WS_GROUP | WS_TABSTOP,13,166,67,10
     CONTROL         "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX | 
-                    WS_GROUP | WS_TABSTOP,155,138,51,10
-    LTEXT           "Connect\n&Settings",IDC_STATIC,5,160,62,17
-    EDITTEXT        DS_CONNSETTINGS,47,160,235,55,ES_MULTILINE | 
+                    WS_GROUP | WS_TABSTOP,80,166,59,10
+    LTEXT           "Connect &Settings:",IDC_STATIC,5,192,57,17
+    EDITTEXT        DS_CONNSETTINGS,71,188,211,27,ES_MULTILINE | 
                     ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
-    DEFPUSHBUTTON   "OK",IDOK,121,220,50,14,WS_GROUP
-    PUSHBUTTON      "Cancel",IDCANCEL,231,220,50,14
-    PUSHBUTTON      "Apply",IDAPPLY,176,220,50,14
+    DEFPUSHBUTTON   "OK",IDOK,5,220,50,14,WS_GROUP
+    PUSHBUTTON      "Cancel",IDCANCEL,81,220,50,14
+    PUSHBUTTON      "Apply",IDAPPLY,156,220,50,14
+    GROUPBOX        "Level of rollback on errors",IDC_STATIC,145,124,137,25
+    CONTROL         "Nop",DS_NO_ROLLBACK,"Button",BS_AUTORADIOBUTTON | 
+                    WS_GROUP,147,136,24,9
+    CONTROL         "Transaction",DS_TRANSACTION_ROLLBACK,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,175,136,57,9
+    CONTROL         "Statement",DS_STATEMENT_ROLLBACK,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,233,136,47,9
 END
 
-DLG_OPTIONS_GLOBAL DIALOGEX 0, 0, 306, 87
-STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | 
-    WS_SYSMENU
+DLG_OPTIONS_GLOBAL DIALOG DISCARDABLE  0, 0, 306, 87
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "Global settings"
-FONT 8, "MS Sans Serif"
+FONT 10, "Terminal"
 BEGIN
     CONTROL         "Comm&Log (C:\\psqlodbc_xxxx.log - Communications log)",
                     DRV_COMMLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,24,
@@ -533,17 +567,16 @@ BEGIN
                     296,58
 END
 
-DLG_DRIVER_CHANGE DIALOGEX 0, 0, 306, 87
-STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | 
-    WS_SYSMENU
+DLG_DRIVER_CHANGE DIALOG DISCARDABLE  0, 0, 306, 87
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "Driver up/downgrade"
-FONT 8, "MS Sans Serif"
+FONT 10, "Terminal"
 BEGIN
     DEFPUSHBUTTON   "OK",IDOK,82,68,50,14,WS_GROUP
     PUSHBUTTON      "Cancel",IDCANCEL,172,67,50,15
     GROUPBOX        "Drivers List",IDC_STATIC,5,5,296,58
     LTEXT           "Select the driver",IDC_STATIC,31,33,73,8
-    LISTBOX         IDC_DRIVER_LIST,117,23,151,32,LBS_SORT | 
+    LISTBOX         IDC_DRIVER_LIST,117,18,151,32,LBS_SORT | 
                     LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
 END
 
@@ -554,7 +587,7 @@ END
 //
 
 #ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO 
+GUIDELINES DESIGNINFO DISCARDABLE 
 BEGIN
     DLG_CONFIG, DIALOG
     BEGIN
@@ -564,9 +597,9 @@ BEGIN
     DLG_OPTIONS_DRV, DIALOG
     BEGIN
         LEFTMARGIN, 5
-        RIGHTMARGIN, 298
+        RIGHTMARGIN, 282
         TOPMARGIN, 5
-        BOTTOMMARGIN, 222
+        BOTTOMMARGIN, 226
     END
 
     DLG_OPTIONS_DS, DIALOG
@@ -574,7 +607,8 @@ BEGIN
         LEFTMARGIN, 5
         RIGHTMARGIN, 282
         TOPMARGIN, 5
-        BOTTOMMARGIN, 236
+        BOTTOMMARGIN, 231
+        HORZGUIDE, 136
     END
 
     DLG_OPTIONS_GLOBAL, DIALOG
@@ -596,19 +630,20 @@ END
 #endif    // APSTUDIO_INVOKED
 
 
+#ifndef _MAC
 /////////////////////////////////////////////////////////////////////////////
 //
 // Version
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 8,1,2,0
- PRODUCTVERSION 8,1,2,0
+ FILEVERSION PG_DRVFILE_VERSION
+ PRODUCTVERSION PG_DRVFILE_VERSION
  FILEFLAGSMASK 0x3L
 #ifdef _DEBUG
- FILEFLAGS 0x1L
+ FILEFLAGS 0x9L
 #else
- FILEFLAGS 0x0L
+ FILEFLAGS 0x8L
 #endif
  FILEOS 0x4L
  FILETYPE 0x2L
@@ -618,19 +653,18 @@ BEGIN
     BEGIN
         BLOCK "040904e4"
         BEGIN
-#ifdef UNICODE_SUPPORT
-            VALUE "Comments", "PostgreSQL Unicode ODBC driver"
-#else
-            VALUE "Comments", "PostgreSQL ANSI ODBC driver"
-#endif
-            VALUE "CompanyName", "PostgreSQL Global Development Group"
-            VALUE "FileDescription", "PostgreSQL Driver"
-            VALUE "FileVersion", "08.01.0200"
-            VALUE "InternalName", "psqlodbc"
-            VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation.  Microsoft® is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation."
-            VALUE "OriginalFilename", "psqlodbc.dll"
-            VALUE "ProductName", "Microsoft Open Database Connectivity"
-            VALUE "ProductVersion", "08.01.0200"
+            VALUE "Comments", "PostgreSQL ODBC driver\0"
+            VALUE "CompanyName", "Insight Distribution Systems\0"
+            VALUE "FileDescription", "PostgreSQL Driver English\0"
+            VALUE "FileVersion", POSTGRES_RESOURCE_VERSION
+            VALUE "InternalName", "psqlodbc35w\0"
+            VALUE "LegalCopyright", "\0"
+            VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation.  Microsoft? is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
+            VALUE "OriginalFilename", "psqlodbc35w.dll\0"
+            VALUE "PrivateBuild", "for Japanese by Hiroshi Inoue & Hiroshi Saito\0"
+            VALUE "ProductName", "Microsoft Open Database Connectivity\0"
+            VALUE "ProductVersion", POSTGRES_RESOURCE_VERSION
+            VALUE "SpecialBuild", "\0"
         END
     END
     BLOCK "VarFileInfo"
@@ -639,13 +673,15 @@ BEGIN
     END
 END
 
+#endif    // !_MAC
+
 
 /////////////////////////////////////////////////////////////////////////////
 //
 // String Table
 //
 
-STRINGTABLE 
+STRINGTABLE DISCARDABLE 
 BEGIN
     IDS_BADDSN              "Invalid DSN entry, please recheck."
     IDS_MSGTITLE            "Invalid DSN"
@@ -656,13 +692,17 @@ BEGIN
     IDS_ADVANCE_OPTION_DSN2 "Advanced Options (%s) 2/2"
     IDS_ADVANCE_OPTION_CON2 "Advanced Options (Connection 2/2)"
     IDS_ADVANCE_CONNECTION  "Connection"
+END
+
+STRINGTABLE DISCARDABLE 
+BEGIN
     IDS_SSLREQUEST_PREFER   "prefer"
     IDS_SSLREQUEST_ALLOW    "allow"
     IDS_SSLREQUEST_REQUIRE  "require"
     IDS_SSLREQUEST_DISABLE  "disable"
 END
 
-#endif    // English (U.S.) resources
+#endif    // \89p\8cê (\83A\83\81\83\8a\83J) resources
 /////////////////////////////////////////////////////////////////////////////
 
 
diff --git a/psqlodbc35w.dsp b/psqlodbc35w.dsp
new file mode 100644 (file)
index 0000000..844e03d
--- /dev/null
@@ -0,0 +1,350 @@
+# Microsoft Developer Studio Project File - Name="psqlodbc35w" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** \95Ò\8fW\82µ\82È\82¢\82Å\82­\82¾\82³\82¢ **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=psqlodbc35w - Win32 Release
+!MESSAGE \82±\82ê\82Í\97L\8cø\82ÈÒ²¸Ì§²Ù\82Å\82Í\82 \82è\82Ü\82¹\82ñ\81\82±\82ÌÌßÛ¼Þª¸Ä\82ðËÞÙÄÞ\82·\82é\82½\82ß\82É\82Í NMAKE \82ð\8eg\97p\82µ\82Ä\82­\82¾\82³\82¢\81B
+!MESSAGE [Ò²¸Ì§²Ù\82Ì´¸½Îß°Ä] ºÏÝÄÞ\82ð\8eg\97p\82µ\82Ä\8eÀ\8ds\82µ\82Ä\82­\82¾\82³\82¢
+!MESSAGE 
+!MESSAGE NMAKE /f "psqlodbc35w.mak".
+!MESSAGE 
+!MESSAGE NMAKE \82Ì\8eÀ\8ds\8e\9e\82É\8d\\90¬\82ð\8ew\92è\82Å\82«\82Ü\82·
+!MESSAGE ºÏÝÄޠײÝ\8fã\82ÅϸÛ\82Ì\90Ý\92è\82ð\92è\8b`\82µ\82Ü\82·\81B\97á:
+!MESSAGE 
+!MESSAGE NMAKE /f "psqlodbc35w.mak" CFG="psqlodbc35w - Win32 Release"
+!MESSAGE 
+!MESSAGE \91I\91ð\89Â\94\\82ÈËÞÙÄÞ Ó°ÄÞ:
+!MESSAGE 
+!MESSAGE "psqlodbc35w - Win32 Release" ("Win32 (x86) Console Application" \97p)
+!MESSAGE "psqlodbc35w - Win32 Debug" ("Win32 (x86) Console Application" \97p)
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "psqlodbc35w - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "USE_LIBPQ" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D ODBCVER=0x0350 /D "DRIVER_CURSOR_IMPLEMENT" /D "WIN_MULTITHREAD_SUPPORT" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /Fp"psqlodbc.pch" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "F:\postgresql-8.1.3\src\include" /I "F:\postgresql-8.1.3\src\interfaces\libpq" /I "F:\openssl-0.9.7i\inc32" /D "NDEBUG" /D "USE_LIBPQ" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D ODBCVER=0x0350 /D "DRIVER_CURSOR_IMPLEMENT" /D "WIN_MULTITHREAD_SUPPORT" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /D "USE_SSL" /Fp"psqlodbc.pch" /YX /FD /c
+# ADD BASE RSC /l 0x411 /d "NDEBUG"
+# ADD RSC /l 0x411 /i "." /i "japanese" /d "NDEBUG"
+# SUBTRACT RSC /x
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 wsock32.lib shfolder.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libpq.lib F:\openssl-0.9.7i\out32\ssleay32.lib F:\openssl-0.9.7i\out32\libeay32.lib /nologo /subsystem:windows /dll /pdb:"psqlodbc35w.pdb" /machine:I386 /out:"psqlodbc35w.dll" /implib:"psqlodbc35w.lib" /libpath:"F:\postgresql-8.1.3\src\interfaces\libpq\Release"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "psqlodbc35w - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /Gm /GX /ZI /Od /D "USE_LIBPQ" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D ODBCVER=0x0350 /D "DRIVER_CURSOR_IMPLEMENT" /D "WIN_MULTITHREAD_SUPPORT" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /Gm /GX /ZI /I "F:\postgresql-8.1.3\src\include" /I "F:\postgresql-8.1.3\src\interfaces\libpq" /I "F:\openssl-0.9.7i\inc32" /D "_DEBUG" /D "USE_LIBPQ" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D ODBCVER=0x0350 /D "DRIVER_CURSOR_IMPLEMENT" /D "WIN_MULTITHREAD_SUPPORT" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /D "USE_SSL" /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x411 /d "_DEBUG"
+# ADD RSC /l 0x411 /i "." /i "japanese" /d "_DEBUG"
+# SUBTRACT RSC /x
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:windows /debug /machine:I386
+# ADD LINK32 wsock32.lib shfolder.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libpq.lib F:\openssl-0.9.7i\out32\ssleay32.lib F:\openssl-0.9.7i\out32\libeay32.lib /nologo /subsystem:windows /dll /pdb:"psqlodbc35w.pdb" /debug /machine:I386 /out:"psqlodbc35w.dll" /implib:"psqlodbc35w.lib" /libpath:"F:\postgresql-8.1.3\src\interfaces\libpq\Debug"
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF 
+
+# Begin Target
+
+# Name "psqlodbc35w - Win32 Release"
+# Name "psqlodbc35w - Win32 Debug"
+# Begin Group "source"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=bind.c
+# End Source File
+# Begin Source File
+
+SOURCE=columninfo.c
+# End Source File
+# Begin Source File
+
+SOURCE=connection.c
+# End Source File
+# Begin Source File
+
+SOURCE=convert.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\descriptor.c
+# End Source File
+# Begin Source File
+
+SOURCE=dlg_specific.c
+# End Source File
+# Begin Source File
+
+SOURCE=dlg_wingui.c
+# End Source File
+# Begin Source File
+
+SOURCE=drvconn.c
+# End Source File
+# Begin Source File
+
+SOURCE=environ.c
+# End Source File
+# Begin Source File
+
+SOURCE=execute.c
+# End Source File
+# Begin Source File
+
+SOURCE=info.c
+# End Source File
+# Begin Source File
+
+SOURCE=info30.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\inouealc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\loadlib.c
+# End Source File
+# Begin Source File
+
+SOURCE=lobj.c
+# End Source File
+# Begin Source File
+
+SOURCE=misc.c
+# End Source File
+# Begin Source File
+
+SOURCE=multibyte.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mylog.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\odbcapi.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\odbcapi30.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\odbcapi30w.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\odbcapiw.c
+# End Source File
+# Begin Source File
+
+SOURCE=options.c
+# End Source File
+# Begin Source File
+
+SOURCE=parse.c
+# End Source File
+# Begin Source File
+
+SOURCE=pgapi30.c
+# End Source File
+# Begin Source File
+
+SOURCE=pgtypes.c
+# End Source File
+# Begin Source File
+
+SOURCE=psqlodbc.c
+# End Source File
+# Begin Source File
+
+SOURCE=qresult.c
+# End Source File
+# Begin Source File
+
+SOURCE=results.c
+# End Source File
+# Begin Source File
+
+SOURCE=setup.c
+# End Source File
+# Begin Source File
+
+SOURCE=socket.c
+# End Source File
+# Begin Source File
+
+SOURCE=statement.c
+# End Source File
+# Begin Source File
+
+SOURCE=tuple.c
+# End Source File
+# Begin Source File
+
+SOURCE=win_md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\win_unicode.c
+# End Source File
+# End Group
+# Begin Group "include"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=bind.h
+# End Source File
+# Begin Source File
+
+SOURCE=columninfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=connection.h
+# End Source File
+# Begin Source File
+
+SOURCE=convert.h
+# End Source File
+# Begin Source File
+
+SOURCE=descriptor.h
+# End Source File
+# Begin Source File
+
+SOURCE=dlg_specific.h
+# End Source File
+# Begin Source File
+
+SOURCE=environ.h
+# End Source File
+# Begin Source File
+
+SOURCE=iodbc.h
+# End Source File
+# Begin Source File
+
+SOURCE=isql.h
+# End Source File
+# Begin Source File
+
+SOURCE=isqlext.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\loadlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=lobj.h
+# End Source File
+# Begin Source File
+
+SOURCE=md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=misc.h
+# End Source File
+# Begin Source File
+
+SOURCE=multibyte.h
+# End Source File
+# Begin Source File
+
+SOURCE=pgapifunc.h
+# End Source File
+# Begin Source File
+
+SOURCE=pgtypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=psqlodbc.h
+# End Source File
+# Begin Source File
+
+SOURCE=qresult.h
+# End Source File
+# Begin Source File
+
+SOURCE=socket.h
+# End Source File
+# Begin Source File
+
+SOURCE=statement.h
+# End Source File
+# Begin Source File
+
+SOURCE=tuple.h
+# End Source File
+# Begin Source File
+
+SOURCE=tuplelist.h
+# End Source File
+# Begin Source File
+
+SOURCE=win_setup.h
+# End Source File
+# End Group
+# Begin Group "resource"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\psqlodbc.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\psqlodbc_api30w.def
+# End Source File
+# Begin Source File
+
+SOURCE=resource.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/psqlodbc_api30w.def b/psqlodbc_api30w.def
new file mode 100644 (file)
index 0000000..ac1d374
--- /dev/null
@@ -0,0 +1,108 @@
+LIBRARY psqlodbc35w
+EXPORTS
+;SQLAllocConnect @1
+;SQLAllocEnv @2
+;SQLAllocStmt @3
+SQLBindCol @4
+SQLCancel @5
+; SQLColAttributes @6
+SQLConnect @7
+SQLDescribeCol @8
+SQLDisconnect @9
+;SQLError @10
+SQLExecDirect @11
+SQLExecute @12
+SQLFetch @13
+;SQLFreeConnect @14
+;SQLFreeEnv @15
+SQLFreeStmt @16
+SQLGetCursorName @17
+SQLNumResultCols @18
+SQLPrepare @19
+SQLRowCount @20
+SQLSetCursorName @21
+;SQLTransact @23
+SQLColumns @40
+SQLDriverConnect @41
+SQLGetData @43
+SQLGetFunctions @44
+SQLGetInfo @45
+;SQLGetStmtOption @46
+SQLGetTypeInfo @47
+SQLParamData @48
+SQLPutData @49
+SQLSpecialColumns @52
+SQLStatistics @53
+SQLTables @54
+SQLBrowseConnect @55
+SQLColumnPrivileges @56
+SQLDescribeParam @58
+SQLExtendedFetch @59
+SQLForeignKeys @60
+SQLMoreResults @61
+SQLNativeSql @62
+SQLNumParams @63
+SQLParamOptions @64
+SQLPrimaryKeys @65
+SQLProcedureColumns @66
+SQLProcedures @67
+SQLSetPos @68
+SQLSetScrollOptions @69
+SQLTablePrivileges @70
+SQLBindParameter @72
+
+SQLAllocHandle @80
+SQLBindParam @81
+SQLCloseCursor @82
+SQLColAttribute @83
+SQLCopyDesc @84
+SQLEndTran @85
+SQLFetchScroll @86
+SQLFreeHandle @87
+SQLGetDescField @88
+SQLGetDescRec @89
+SQLGetDiagField @90
+SQLGetDiagRec @91
+SQLGetEnvAttr @92
+SQLGetConnectAttr @93
+SQLGetStmtAttr @94
+SQLSetConnectAttr @95
+SQLSetDescField @96
+SQLSetDescRec @97
+SQLSetEnvAttr @98
+SQLSetStmtAttr @99
+SQLBulkOperations @100
+
+SQLDummyOrdinal @199
+dconn_FDriverConnectProc @200
+DllMain @201
+ConfigDSN @202
+
+SQLColAttributeW   @101
+SQLColumnPrivilegesW   @102
+SQLColumnsW        @103
+SQLConnectW        @104
+SQLDescribeColW        @106
+SQLExecDirectW     @107
+SQLForeignKeysW        @108
+SQLGetConnectAttrW @109
+SQLGetCursorNameW  @110
+SQLGetInfoW        @111
+SQLNativeSqlW      @112
+SQLPrepareW        @113
+SQLPrimaryKeysW        @114
+SQLProcedureColumnsW   @115
+SQLProceduresW     @116
+SQLSetConnectAttrW @117
+SQLSetCursorNameW  @118
+SQLSpecialColumnsW @119
+SQLStatisticsW     @120
+SQLTablesW     @121
+SQLTablePrivilegesW    @122
+SQLDriverConnectW  @123
+SQLGetDiagRecW     @124
+SQLGetStmtAttrW        @125
+SQLSetStmtAttrW        @126
+SQLSetDescFieldW   @127
+SQLGetTypeInfoW        @128
+SQLGetDiagFieldW   @129
index 18f1b67f746a47a6d49a4a5929847710bbe9f084..6117ae8061e1eab63d881e1df5508decfd6777e6 100644 (file)
--- a/qresult.c
+++ b/qresult.c
@@ -2,17 +2,13 @@
  * Module:         qresult.c
  *
  * Description:        This module contains functions related to
- *                 managing result information (i.e, fetching rows
- *                 from the backend, managing the tuple cache, etc.)
- *                 and retrieving it.  Depending on the situation, a
- *                 QResultClass will hold either data from the backend
- *                 or a manually built result (see "qresult.h" to
- *                 see which functions/macros are for manual or backend
- *                 results.  For manually built results, the
- *                 QResultClass simply points to TupleList and
- *                 ColumnInfo structures, which actually hold the data.
+ *         managing result information (i.e, fetching rows
+ *         from the backend, managing the tuple cache, etc.)
+ *         and retrieving it.  Depending on the situation, a
+ *         QResultClass will hold either data from the backend
+ *         or a manually built result.
  *
- * Classes:            QResultClass (Functions prefix: "QR_")
+ * Classes:        QResultClass (Functions prefix: "QR_")
  *
  * API functions:  none
  *
  */
 
 #include "qresult.h"
+#include "statement.h"
 
 #include "misc.h"
 #include <stdio.h>
 #include <string.h>
+#include <limits.h>
 
-#ifndef TRUE
-#define TRUE   (BOOL)1
-#endif
-#ifndef FALSE
-#define FALSE  (BOOL)0
-#endif
-
+static char QR_read_a_tuple_from_db(QResultClass *, char);
 
 /*
  * Used for building a Manual Result only
 void
 QR_set_num_fields(QResultClass *self, int new_num_fields)
 {
+   BOOL    allocrelatt = FALSE;
+
    if (!self)  return;
    mylog("in QR_set_num_fields\n");
 
-   CI_set_num_fields(self->fields, new_num_fields);
-   if (self->manual_tuples)
-       TL_Destructor(self->manual_tuples);
-
-   self->manual_tuples = TL_Constructor(new_num_fields);
+   CI_set_num_fields(self->fields, new_num_fields, allocrelatt);
 
    mylog("exit QR_set_num_fields\n");
 }
@@ -57,7 +47,7 @@ QR_set_num_fields(QResultClass *self, int new_num_fields)
 void
 QR_set_position(QResultClass *self, int pos)
 {
-   self->tupleField = self->backend_tuples + ((self->base + pos) * self->num_fields);
+   self->tupleField = self->backend_tuples + ((QR_get_rowstart_in_cache(self) + pos) * self->num_fields);
 }
 
 
@@ -71,14 +61,60 @@ QR_set_cache_size(QResultClass *self, int cache_size)
 void
 QR_set_rowset_size(QResultClass *self, int rowset_size)
 {
-   self->rowset_size = rowset_size;
+   self->rowset_size_include_ommitted = rowset_size;
+}
+
+void
+QR_set_cursor(QResultClass *self, const char *name)
+{
+   ConnectionClass *conn = QR_get_conn(self);
+
+   if (self->cursor_name)
+   {
+       free(self->cursor_name);
+       if (conn)
+           conn->ncursors--;
+       self->cursTuple = -1;
+       self->pstatus = 0;
+   }
+   if (name)
+   {
+       self->cursor_name = strdup(name);
+       if (conn)
+           conn->ncursors++;
+   }
+   else
+   {
+       self->cursor_name = NULL;
+       QR_set_no_cursor(self);
+   }
+}
+
+
+void
+QR_set_num_cached_rows(QResultClass *self, int num_rows)
+{
+   self->num_cached_rows = num_rows;
+   if (QR_synchronize_keys(self))
+       self->num_cached_keys = self->num_cached_rows;
 }
 
+void
+QR_set_rowstart_in_cache(QResultClass *self, int start)
+{
+   if (QR_synchronize_keys(self))
+       self->key_base = start;
+   self->base = start;
+}
 
 void
-QR_inc_base(QResultClass *self, int base_inc)
+QR_inc_rowstart_in_cache(QResultClass *self, int base_inc)
 {
+   if (!QR_has_valid_base(self))
+       mylog("QR_inc_rowstart_in_cache called while the cache is not ready\n");
    self->base += base_inc;
+   if (QR_synchronize_keys(self))
+       self->key_base = self->base;
 }
 
 
@@ -95,7 +131,8 @@ QR_Constructor()
 
    if (rv != NULL)
    {
-       rv->status = PGRES_EMPTY_QUERY;
+       rv->rstatus = PGRES_EMPTY_QUERY;
+       rv->pstatus = 0;
 
        /* construct the column info */
        if (!(rv->fields = CI_Constructor()))
@@ -103,38 +140,53 @@ QR_Constructor()
            free(rv);
            return NULL;
        }
-       rv->manual_tuples = NULL;
        rv->backend_tuples = NULL;
+       rv->sqlstate[0] = '\0';
        rv->message = NULL;
        rv->command = NULL;
        rv->notice = NULL;
        rv->conn = NULL;
        rv->next = NULL;
-       rv->inTuples = FALSE;
+       rv->pstatus = 0;
        rv->count_backend_allocated = 0;
        rv->count_keyset_allocated = 0;
-       rv->num_total_rows = 0;
-       rv->num_backend_rows = 0;
-       rv->fetch_count = 0;
-       rv->base = 0;
+       rv->num_total_read = 0;
+       rv->num_cached_rows = 0;
+       rv->num_cached_keys = 0;
+       rv->fetch_number = 0;
+       QR_set_rowstart_in_cache(rv, -1);
+       rv->key_base = -1;
        rv->recent_processed_row_count = -1;
-       rv->currTuple = -1;
+       rv->cursTuple = -1;
+       rv->move_offset = 0;
        rv->num_fields = 0;
+       rv->num_key_fields = PG_NUM_NORMAL_KEYS; /* CTID + OID */
        rv->tupleField = NULL;
-       rv->cursor = NULL;
+       rv->cursor_name = NULL;
        rv->aborted = FALSE;
 
        rv->cache_size = 0;
-       rv->rowset_size = 1;
-       rv->haskeyset = 0;
+       rv->rowset_size_include_ommitted = 1;
+       rv->flags = 0;
+       rv->move_direction = 0;
        rv->keyset = NULL;
        rv->reload_count = 0;
        rv->rb_alloc = 0;
        rv->rb_count = 0;
        rv->rollback = NULL;
+       rv->ad_alloc = 0;
+       rv->ad_count = 0;
+       rv->added_keyset = NULL;
+       rv->added_tuples = NULL;
+       rv->up_alloc = 0;
+       rv->up_count = 0;
+       rv->updated = NULL;
+       rv->updated_keyset = NULL;
+       rv->updated_tuples = NULL;
        rv->dl_alloc = 0;
        rv->dl_count = 0;
        rv->deleted = NULL;
+       rv->deleted_keyset = NULL;
    }
 
    mylog("exit QR_Constructor\n");
@@ -143,55 +195,35 @@ QR_Constructor()
 
 
 void
-QR_Destructor(QResultClass *self)
-{\r
-    ConnectionClass    *conn;\r
-\r
-   if (!self)  return;\r
-\r
-    conn = self->conn;
-   mylog("QResult: in DESTRUCTOR\n");
+QR_close_result(QResultClass *self, BOOL destroy)
+{
+   ConnectionClass *conn;
+
+   if (!self)  return;
+   mylog("QResult: in QR_close_result\n");
 
-   /* manual result set tuples */
-   if (self->manual_tuples)
-   {
-       TL_Destructor(self->manual_tuples);
-       self->manual_tuples = NULL;
-   }
-    
    /*
     * If conn is defined, then we may have used "backend_tuples", so in
     * case we need to, free it up.  Also, close the cursor.
     */
-    /*
-     * FIXME!!!
-     * This is *very wrong*, however, without it we get crashes when 
-     * freeing backend_tuples as we should in QR_free_memory. We don't 
-     * appear to leak here though thankfully!! DJP - 2005-08-02
-     */
-   if (self->backend_tuples)
+   if ((conn = QR_get_conn(self)) && conn->sock)
    {
-       free(self->backend_tuples);
-       self->backend_tuples = NULL;
-   }
-   if (conn && conn->pgconn && CC_is_in_trans(conn))
-   {
-       if (!QR_close(self))    /* close the cursor if there is one */
+       if (CC_is_in_trans(conn) ||
+           QR_is_withhold(self))
        {
+           if (!QR_close(self))    /* close the cursor if there is one */
+           {
+           }
        }
    }
 
    QR_free_memory(self);       /* safe to call anyway */
 
    /* Should have been freed in the close() but just in case... */
-   if (self->cursor)
-   {
-       free(self->cursor);
-       self->cursor = NULL;
-   }
+   QR_set_cursor(self, NULL);
 
    /* Free up column info */
-   if (self->fields)
+   if (destroy && self->fields)
    {
        CI_Destructor(self->fields);
        self->fields = NULL;
@@ -218,13 +250,22 @@ QR_Destructor(QResultClass *self)
        self->notice = NULL;
    }
    /* Destruct the result object in the chain */
-   if (self->next)
+   QR_Destructor(self->next);
+   self->next = NULL;
+
+   mylog("QResult: exit close_result\n");
+   if (destroy)
    {
-       QR_Destructor(self->next);
-       self->next = NULL;
+       free(self);
    }
+}
 
-   free(self);
+void
+QR_Destructor(QResultClass *self)
+{
+   mylog("QResult: enter DESTRUCTOR\n");
+   if (!self)  return;
+   QR_close_result(self, TRUE);
 
    mylog("QResult: exit DESTRUCTOR\n");
 }
@@ -249,6 +290,31 @@ QR_set_message(QResultClass *self, const char *msg)
    self->message = msg ? strdup(msg) : NULL;
 }
 
+void
+QR_add_message(QResultClass *self, const char *msg)
+{
+   char    *message = self->message;
+   Int4    alsize, pos;
+
+   if (!msg || !msg[0])
+       return;
+   if (message)
+   {
+       pos = strlen(message) + 1;
+       alsize = pos + strlen(msg) + 1;
+   }
+   else
+   {
+       pos = 0;
+       alsize = strlen(msg) + 1;
+   }
+   message = realloc(message, alsize);
+   if (pos > 0)
+       message[pos - 1] = ';';
+   strcpy(message + pos, msg);
+   self->message = message;
+}
+
 
 void
 QR_set_notice(QResultClass *self, const char *msg)
@@ -259,53 +325,98 @@ QR_set_notice(QResultClass *self, const char *msg)
    self->notice = msg ? strdup(msg) : NULL;
 }
 
+void
+QR_add_notice(QResultClass *self, const char *msg)
+{
+   char    *message = self->notice;
+   Int4    alsize, pos;
+
+   if (!msg || !msg[0])
+       return;
+   if (message)
+   {
+       pos = strlen(message) + 1;
+       alsize = pos + strlen(msg) + 1;
+   }
+   else
+   {
+       pos = 0;
+       alsize = strlen(msg) + 1;
+   }
+   message = realloc(message, alsize);
+   if (pos > 0)
+       message[pos - 1] = ';';
+   strcpy(message + pos, msg);
+   self->notice = message;
+}
+
+
+TupleField *QR_AddNew(QResultClass *self)
+{
+   UInt4   alloc, num_fields;
+
+   if (!self)  return  NULL;
+inolog("QR_AddNew %dth row(%d fields) alloc=%d\n", self->num_cached_rows, QR_NumResultCols(self), self->count_backend_allocated);
+   if (num_fields = QR_NumResultCols(self), !num_fields)   return  NULL;
+   if (self->num_fields <= 0)
+   {
+       self->num_fields = num_fields;
+       QR_set_reached_eof(self);
+   }
+   alloc = self->count_backend_allocated;
+   if (!self->backend_tuples)
+   {
+       self->num_cached_rows = 0;
+       alloc = TUPLE_MALLOC_INC;
+       self->backend_tuples = malloc(alloc * sizeof(TupleField) * num_fields);
+   }
+   else if (self->num_cached_rows >= self->count_backend_allocated)
+   {
+       alloc = self->count_backend_allocated * 2;
+       self->backend_tuples = realloc(self->backend_tuples, alloc * sizeof(TupleField) * num_fields);
+   }
+   self->count_backend_allocated = alloc;
+
+   if (self->backend_tuples)
+   {
+       memset(self->backend_tuples + num_fields * self->num_cached_rows, 0, num_fields * sizeof(TupleField));
+       self->num_cached_rows++;
+       self->ad_count++;
+   }
+   return self->backend_tuples + num_fields * (self->num_cached_rows - 1);
+}
 
 void
 QR_free_memory(QResultClass *self)
 {
-   int     lf, row;
    TupleField  *tuple = self->backend_tuples;
-   int     num_backend_rows = self->num_backend_rows;
+   int     num_backend_rows = self->num_cached_rows;
    int     num_fields = self->num_fields;
 
    mylog("QResult: free memory in, fcount=%d\n", num_backend_rows);
 
    if (self->backend_tuples)
    {
-       for (row = 0; row < num_backend_rows; row++)
-       {
-           mylog("row = %d, num_fields = %d\n", row, num_fields);
-           for (lf = 0; lf < num_fields; lf++)
-           {
-               if (tuple[lf].value != NULL)
-               {
-                   mylog("free [lf=%d] %u\n", lf, tuple[lf].value);
-                   free(tuple[lf].value);
-               }
-           }
-           tuple += num_fields;    /* next row */
-       }
-
+       ClearCachedRows(self->backend_tuples, num_fields, num_backend_rows);
        free(self->backend_tuples);
        self->count_backend_allocated = 0;
        self->backend_tuples = NULL;
    }
    if (self->keyset)
    {
-       ConnectionClass *conn = self->conn;
+       ConnectionClass *conn = QR_get_conn(self);
 
        free(self->keyset);
        self->keyset = NULL;
        self->count_keyset_allocated = 0;
-
-       if (self->reload_count > 0 && conn && conn->pgconn)
+       if (self->reload_count > 0 && conn && conn->sock)
        {
            char    plannm[32];
 
-           sprintf(plannm, "_KEYSET_%p", self);
+           sprintf(plannm, "_KEYSET_%x", self);
            if (CC_is_in_error_trans(conn))
            {
-               CC_mark_a_plan_to_discard(conn, plannm);
+               CC_mark_a_object_to_discard(conn, 's',plannm);
            }
            else
            {
@@ -313,9 +424,8 @@ QR_free_memory(QResultClass *self)
                char        cmd[64];
 
                sprintf(cmd, "DEALLOCATE \"%s\"", plannm);
-               res = CC_send_query(conn, cmd, NULL, CLEAR_RESULT_ON_ABORT);
-               if (res)
-                   QR_Destructor(res);
+               res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL);
+               QR_Destructor(res);
            }
        }
        self->reload_count = 0;
@@ -330,13 +440,54 @@ QR_free_memory(QResultClass *self)
    if (self->deleted)
    {
        free(self->deleted);
-       self->dl_alloc = 0;
-       self->dl_count = 0;
        self->deleted = NULL;
    }
+   if (self->deleted_keyset)
+   {
+       free(self->deleted_keyset);
+       self->deleted_keyset = NULL;
+   }
+   self->dl_alloc = 0;
+   self->dl_count = 0;
+   /* clear added info */
+   if (self->added_keyset)
+   {
+       free(self->added_keyset);
+       self->added_keyset = NULL;
+   }
+   if (self->added_tuples)
+   {
+       ClearCachedRows(self->added_tuples, num_fields, self->ad_count);
+       free(self->added_tuples);
+       self->added_tuples = NULL;
+   }
+   self->ad_alloc = 0;
+   self->ad_count = 0;
+   /* clear updated info */
+   if (self->updated)
+   {
+       free(self->updated);
+       self->updated = NULL;
+   }
+   if (self->updated_keyset)
+   {
+       free(self->updated_keyset);
+       self->updated_keyset = NULL;
+   }
+   if (self->updated_tuples)
+   {
+       ClearCachedRows(self->updated_tuples, num_fields, self->up_count);
+       free(self->updated_tuples);
+       self->updated_tuples = NULL;
+   }
+   self->up_alloc = 0;
+   self->up_count = 0;
 
-   self->num_total_rows = 0;
-   self->num_backend_rows = 0;
+   self->num_total_read = 0;
+   self->num_cached_rows = 0;
+   self->num_cached_keys = 0;
+   self->cursTuple = -1;
+   self->pstatus = 0;
 
    mylog("QResult: free memory out\n");
 }
@@ -344,8 +495,9 @@ QR_free_memory(QResultClass *self)
 
 /* This function is called by send_query() */
 char
-QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
+QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, const char *cursor)
 {
+   CSTR        func = "QR_fetch_tuples";
    int         tuple_size;
 
    /*
@@ -357,36 +509,45 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
    if (conn != NULL)
    {
        ConnInfo   *ci = &(conn->connInfo);
-       BOOL        fetch_cursor = (ci->drivers.use_declarefetch && cursor && cursor[0]);
-
-       self->conn = conn;
+       BOOL        fetch_cursor = (cursor && cursor[0]);
 
-       mylog("QR_fetch_tuples: cursor = '%s', self->cursor=%u\n", (cursor == NULL) ? "" : cursor, self->cursor);
+       QR_set_conn(self, conn);
 
-       if (self->cursor)
-           free(self->cursor);
-       self->cursor = NULL;
+       mylog("%s: cursor = '%s', self->cursor=%x\n", func, (cursor == NULL) ? "" : cursor, QR_get_cursor(self));
 
+       if (cursor && !cursor[0])
+           cursor = NULL;
        if (fetch_cursor)
        {
-           if (!cursor || cursor[0] == '\0')
+           if (!cursor)
            {
+               QR_set_rstatus(self, PGRES_INTERNAL_ERROR);
                QR_set_message(self, "Internal Error -- no cursor for fetch");
                return FALSE;
            }
-           self->cursor = strdup(cursor);
        }
+       QR_set_cursor(self, cursor);
 
        /*
         * Read the field attributes.
         *
         * $$$$ Should do some error control HERE! $$$$
         */
+       if (CI_read_fields(self->fields, QR_get_conn(self)))
+       {
+           QR_set_rstatus(self, PGRES_FIELDS_OK);
            self->num_fields = CI_get_num_fields(self->fields);
-           if (self->haskeyset)
-               self->num_fields -= 2;
+           if (QR_haskeyset(self))
+               self->num_fields -= self->num_key_fields;
+       }
+       else
+       {
+           QR_set_rstatus(self, PGRES_BAD_RESPONSE);
+           QR_set_message(self, "Error reading field information");
+           return FALSE;
+       }
 
-       mylog("QR_fetch_tuples: past CI_read_fields: num_fields = %d\n", self->num_fields);
+       mylog("%s: past CI_read_fields: num_fields = %d\n", func, self->num_fields);
 
        if (fetch_cursor)
        {
@@ -402,36 +563,43 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
        self->count_backend_allocated = self->count_keyset_allocated = 0;
        if (self->num_fields > 0)
        {
-           QR_MALLOC_return_with_error(self->backend_tuples,
-               TupleField,
-               (self->num_fields * sizeof(TupleField) * tuple_size),
-               self, PGRES_FATAL_ERROR,
-               "Could not get memory for tuple cache.",
-               FALSE)
+           QR_MALLOC_return_with_error(self->backend_tuples, TupleField, self->num_fields * sizeof(TupleField) * tuple_size, self, "Could not get memory for tuple cache.", FALSE);
            self->count_backend_allocated = tuple_size;
        }
-       if (self->haskeyset)
+       if (QR_haskeyset(self))
        {
            if (self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size), !self->keyset)
            {
-               self->status = PGRES_FATAL_ERROR;
+               QR_set_rstatus(self, PGRES_FATAL_ERROR);
                QR_set_message(self, "Could not get memory for tuple cache.");
                return FALSE;
            }
            self->count_keyset_allocated = tuple_size;
        }
 
-       self->inTuples = TRUE;
+       QR_set_fetching_tuples(self);
 
        /* Force a read to occur in next_tuple */
-       self->num_total_rows = 0;
-       self->num_backend_rows = tuple_size + 1;
-       self->fetch_count = tuple_size + 1;
-       self->base = 0;
-       return TRUE;
+       QR_set_num_cached_rows(self, 0);
+       QR_set_next_in_cache(self, 0);
+       QR_set_rowstart_in_cache(self, 0);
+       self->key_base = 0;
+
+       return QR_next_tuple(self, NULL);
    }
    else
    {
+       /*
+        * Always have to read the field attributes. But we dont have to
+        * reallocate memory for them!
+        */
+
+       if (!CI_read_fields(NULL, QR_get_conn(self)))
+       {
+           QR_set_rstatus(self, PGRES_BAD_RESPONSE);
+           QR_set_message(self, "Error reading field information");
+           return FALSE;
+       }
        return TRUE;
    }
 }
@@ -439,50 +607,49 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
 
 /*
  * Close the cursor and end the transaction (if no cursors left)
- * We only close cursor/end the transaction if a cursor was used.
+ * We only close the cursor if other cursors are used.
  */
 int
 QR_close(QResultClass *self)
 {
+   ConnectionClass *conn;
    QResultClass *res;
-   ConnectionClass *conn = self->conn;
    int ret = TRUE;
 
-   if (conn && self->cursor && conn->connInfo.drivers.use_declarefetch)
+   conn = QR_get_conn(self);
+   if (self && QR_get_cursor(self))
    {
-       if (!CC_is_in_error_trans(conn))
+       if (CC_is_in_error_trans(conn))
+       {
+           if (QR_is_withhold(self))
+               CC_mark_a_object_to_discard(conn, 'p', QR_get_cursor(self));
+       }
+       else
        {
            char        buf[64];
 
-           sprintf(buf, "close %s", self->cursor);
+           sprintf(buf, "close \"%s\"", QR_get_cursor(self));
            mylog("QResult: closing cursor: '%s'\n", buf);
 
-           res = CC_send_query(conn, buf, NULL, CLEAR_RESULT_ON_ABORT);
-           if (NULL == res)
-           {
-               QR_set_status(self, PGRES_FATAL_ERROR);
-               QR_set_message(self, "Error closing cursor.");
-               ret = FALSE;
-           }
+           res = CC_send_query(conn, buf, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
            QR_Destructor(res);
        }
 
-       self->inTuples = FALSE;
-       self->currTuple = -1;
+       QR_set_no_fetching_tuples(self);
+       self->cursTuple = -1;
 
-       free(self->cursor);
-       self->cursor = NULL;
+       QR_set_cursor(self, NULL);
        if (!ret)
            return ret;
 
        /* End the transaction if there are no cursors left on this conn */
-       if (CC_is_in_autocommit(self->conn) && CC_cursor_count(self->conn) == 0)
+       if (CC_is_in_autocommit(conn) && CC_cursor_count(conn) == 0)
        {
-           mylog("QResult: END transaction on conn=%u\n", self->conn);
+           mylog("QResult: END transaction on conn=%x\n", conn);
 
-           if (!CC_commit(self->conn))
+           if (!CC_commit(conn))
            {
-               self->status = PGRES_FATAL_ERROR;
+               QR_set_rstatus(self, PGRES_FATAL_ERROR);
                QR_set_message(self, "Error ending transaction.");
                ret = FALSE;
            }
@@ -493,244 +660,734 @@ QR_close(QResultClass *self)
 }
 
 
-/* This function is called by fetch_tuples() AND SQLFetch() */
+BOOL
+QR_get_tupledata(QResultClass *self, BOOL binary)
+{
+   BOOL    haskeyset = QR_haskeyset(self);
+   UInt4   num_total_rows = QR_get_num_total_tuples(self);
+
+inolog("QR_get_tupledata num_fields=%d\n", self->num_fields);
+   if (!QR_get_cursor(self))
+   {
+       if (self->num_fields > 0 &&
+           num_total_rows >= self->count_backend_allocated)
+       {
+           int tuple_size = self->count_backend_allocated;
+
+           mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
+           if (tuple_size < 1)
+               tuple_size = TUPLE_MALLOC_INC;
+           else
+               tuple_size *= 2;
+           QR_REALLOC_return_with_error(self->backend_tuples, TupleField, tuple_size * self->num_fields * sizeof(TupleField), self, "Out of memory while reading tuples.", FALSE);
+           self->count_backend_allocated = tuple_size;
+       }
+       if (haskeyset &&
+           self->num_cached_keys >= self->count_keyset_allocated)
+       {
+           int tuple_size = self->count_keyset_allocated;
+
+           if (tuple_size < 1)
+               tuple_size = TUPLE_MALLOC_INC;
+           else
+               tuple_size *= 2;
+           QR_REALLOC_return_with_error(self->keyset, KeySet, sizeof(KeySet) * tuple_size, self, "Out of mwmory while allocating keyset", FALSE);
+           self->count_keyset_allocated = tuple_size;
+       }
+   }
+
+   if (!QR_read_a_tuple_from_db(self, (char) binary))
+   {
+       QR_set_rstatus(self, PGRES_BAD_RESPONSE);
+       QR_set_message(self, "Error reading the tuple");
+       return FALSE;
+   }
+inolog("!!%x->cursTup=%d total_read=%d\n", self, self->cursTuple, self->num_total_read);
+   if (!QR_once_reached_eof(self) && self->cursTuple >= (Int4) self->num_total_read)
+       self->num_total_read = self->cursTuple + 1;
+inolog("!!cursTup=%d total_read=%d\n", self->cursTuple, self->num_total_read);
+   if (self->num_fields > 0)
+   {
+       QR_inc_num_cache(self);
+   }
+   else if (haskeyset)
+       self->num_cached_keys++;
 
+   return TRUE;
+}
+
+static int enlargeKeyCache(QResultClass *self, Int4 add_size, const char *message)
+{
+   Int4    alloc, alloc_req, num_fields = self->num_fields;
+   BOOL    curs = (NULL != QR_get_cursor(self));
+
+   if (add_size <= 0)
+       return self->count_keyset_allocated;
+   alloc = self->count_backend_allocated;
+   if (num_fields > 0 && ((alloc_req = (Int4)self->num_cached_rows + add_size) > alloc || !self->backend_tuples))
+   {
+       if (1 > alloc)
+       {
+           if (curs)
+               alloc = alloc_req;
+           else
+               alloc = (alloc_req > TUPLE_MALLOC_INC ? alloc_req : TUPLE_MALLOC_INC);
+       }
+       else
+       {
+           do
+           { 
+               alloc *= 2;
+           } while (alloc < alloc_req);
+       }
+       self->count_backend_allocated = 0;
+       QR_REALLOC_return_with_error(self->backend_tuples, TupleField, num_fields * sizeof(TupleField) * alloc, self, message, -1);
+       self->count_backend_allocated = alloc;
+   }
+   alloc = self->count_keyset_allocated;
+   if (QR_haskeyset(self) && ((alloc_req = (Int4)self->num_cached_keys + add_size) > alloc || !self->keyset))
+   {
+       if (1 > alloc)
+       {
+           if (curs)
+               alloc = alloc_req;
+           else
+               alloc = (alloc_req > TUPLE_MALLOC_INC ? alloc_req : TUPLE_MALLOC_INC);
+       }
+       else
+       {
+           do
+           { 
+               alloc *= 2;
+           } while (alloc < alloc_req);
+       }
+       self->count_keyset_allocated = 0;
+       QR_REALLOC_return_with_error(self->keyset, KeySet, sizeof(KeySet) * alloc, self, message, -1); 
+       self->count_keyset_allocated = alloc;
+   }
+   return alloc;
+}
+
+/* This function is called by fetch_tuples() AND SQLFetch() */
 int
-QR_next_tuple(QResultClass *self)
+QR_next_tuple(QResultClass *self, StatementClass *stmt)
 {
-   int         id;
-   QResultClass *res;
-   ConnectionClass *conn;
+   CSTR    func = "QR_next_tuple";
+   int         id, ret = TRUE;
+   SocketClass *sock;
 
    /* Speed up access */
-   int         fetch_count = self->fetch_count;
-   int         num_backend_rows = self->num_backend_rows;
-   int         fetch_size,
-               offset = 0;
-   int         end_tuple = self->rowset_size + self->base;
-   char        corrected = FALSE;
+   int     fetch_number = self->fetch_number, cur_fetch;
+   Int4        num_total_rows;
+   Int4        num_backend_rows = self->num_cached_rows,
+           num_fields = self->num_fields, num_rows_in;
+   Int4        req_size, fetch_size, offset = 0,   end_tuple;
+   char        boundary_adjusted = FALSE;
    TupleField *the_tuples = self->backend_tuples;
 
+   /* ERROR_MSG_LENGTH is sufficient */
+   char msgbuffer[ERROR_MSG_LENGTH + 1];
+
+   /* QR_set_command() dups this string so doesn't need static */
+   char        cmdbuffer[ERROR_MSG_LENGTH + 1];
    char        fetch[128];
    QueryInfo   qi;
+   ConnectionClass *conn;
    ConnInfo   *ci = NULL;
-
-   if (fetch_count < num_backend_rows)
+   BOOL        msg_truncated, rcvend, internally_invoked = FALSE;
+   BOOL        reached_eof_now = FALSE, curr_eof; /* detecting EOF is pretty important */
+   Int4        response_length;
+
+inolog("Oh %x->fetch_number=%d\n", self, self->fetch_number);
+inolog("in total_read=%d cursT=%d currT=%d ad=%d total=%d rowsetSize=%d\n", self->num_total_read, self->cursTuple, stmt ? stmt->currTuple : -1, self->ad_count, QR_get_num_total_tuples(self), self->rowset_size_include_ommitted);
+
+   num_total_rows = QR_get_num_total_tuples(self);
+   conn = QR_get_conn(self);
+   req_size = self->rowset_size_include_ommitted;
+   if (QR_once_reached_eof(self) && self->cursTuple >= (Int4) QR_get_num_total_read(self))
+       curr_eof = TRUE;
+   if (0 != self->move_offset)
    {
-       /* return a row from cache */
-       mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, num_backend_rows);
-       self->tupleField = the_tuples + (fetch_count * self->num_fields);       /* next row */
-       self->fetch_count++;
-       return TRUE;
-   }
-   else if (self->num_backend_rows < self->cache_size)
-   {
-       /* last row from cache */
-       /* We are done because we didn't even get CACHE_SIZE tuples */
-       mylog("next_tuple: fcount < CACHE_SIZE: fcount = %d, fetch_count = %d\n", num_backend_rows, fetch_count);
-       self->tupleField = NULL;
-       /* self->status = PGRES_END_TUPLES;*/
-       /* end of tuples */
-       return -1;
-   }
-   else
-   {
-       /*
-        * See if we need to fetch another group of rows. We may be being
-        * called from send_query(), and if so, don't send another fetch,
-        * just fall through and read the tuples.
-        */
-       self->tupleField = NULL;
-       if (!self->inTuples)
+       char        movecmd[256];
+       QResultClass    *mres;
+       UInt4       movement, moved;
+
+       movement = self->move_offset;
+       if (QR_is_moving_backward(self))
        {
-           ci = &(self->conn->connInfo);
-           if (!self->cursor || !ci->drivers.use_declarefetch)
+           if (self->cache_size > req_size)
            {
-               mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", self->num_total_rows, fetch_count);
-               self->tupleField = NULL;
-               /* self->status = PGRES_END_TUPLES;*/
-               return -1;      /* end of tuples */
+               int incr_move = self->cache_size - (req_size < 0 ? 1 : req_size);
+               
+               movement += incr_move;
+               if (movement > (UInt4)(self->cursTuple + 1))
+                   movement = self->cursTuple + 1;
            }
-
-           if (self->base == num_backend_rows)
+           else
+               self->cache_size = req_size;
+inolog("cache=%d rowset=%d movement=%d\n", self->cache_size, req_size, movement);
+           sprintf(movecmd, "move backward %u in \"%s\"", movement, QR_get_cursor(self));
+       }
+       else if (QR_is_moving_forward(self))
+           sprintf(movecmd, "move %u in \"%s\"", movement, QR_get_cursor(self));
+       else
+       {
+           sprintf(movecmd, "move all in \"%s\"", QR_get_cursor(self));
+           movement = INT_MAX;
+       }
+       mres = CC_send_query(conn, movecmd, NULL, 0, stmt);
+       if (!QR_command_maybe_successful(mres))
+       {
+           QR_Destructor(mres);
+           if (stmt)
+               SC_set_error(stmt, STMT_EXEC_ERROR, "move error occured", func);
+           return -1;
+       }
+       moved = movement;
+       if (sscanf(mres->command, "MOVE %u", &moved) > 0)
+       {
+inolog("moved=%d ? %d\n", moved, movement);
+               if (moved < movement)
            {
-               int row, lf;
-               TupleField *tuple = self->backend_tuples;
-
-               /* not a correction */
-               /* Determine the optimum cache size.  */
-               if (ci->drivers.fetch_max % self->rowset_size == 0)
-                   fetch_size = ci->drivers.fetch_max;
-               else if (self->rowset_size < ci->drivers.fetch_max)
-                   fetch_size = (ci->drivers.fetch_max / self->rowset_size) * self->rowset_size;
+               if (0 <  moved)
+                   moved++;
+               else if (QR_is_moving_backward(self) && self->cursTuple < 0)
+                   ;
+               else if (QR_is_moving_not_backward(self) && curr_eof)
+                   ;
                else
-                   fetch_size = self->rowset_size;
-
-               self->cache_size = fetch_size;
-               /* clear obsolete tuples */
-inolog("clear obsolete %d tuples\n", num_backend_rows);
-               for (row = 0; row < num_backend_rows; row++)
+                   moved++;
+               if (QR_is_moving_not_backward(self))
+               {
+                   curr_eof = TRUE;
+                   if (!QR_once_reached_eof(self))
+                   {
+                       self->num_total_read = self->cursTuple + moved;
+                       QR_set_reached_eof(self);
+                   }
+               }
+               if (QR_is_moving_from_the_last(self))  /* in case of FETCH LAST */
                {
-                   for (lf = 0; lf < self->num_fields; lf++)
+                   UInt4   bmovement, mback;
+                   Int4    rowset_start = self->cursTuple + 1, back_offset = self->move_offset, backpt;
+inolog("FETCH LAST case\n");
+                   if (getNthValid(self, QR_get_num_total_tuples(self) - 1, SQL_FETCH_PRIOR, self->move_offset, &backpt) < 0)
+                   {
+                       /* the rowset_start is on BOF */
+                       self->tupleField = NULL;
+                       SC_set_rowset_start(stmt, -1, TRUE);
+                       stmt->currTuple = -1;
+                       return -1;
+                   }
+                   back_offset = QR_get_num_total_tuples(self) - backpt;
+inolog("back_offset=%d and move_offset=%d\n", back_offset, self->move_offset);
+                   if (back_offset + 1 > (Int4) self->ad_count)
                    {
-                       if (tuple[lf].value != NULL)
+                       bmovement = back_offset + 1 - self->ad_count;
+                       sprintf(movecmd, "move backward %u in \"%s\"", bmovement, QR_get_cursor(self));
+                       QR_Destructor(mres);
+                       mres = CC_send_query(conn, movecmd, NULL, 0, stmt);
+                       if (!QR_command_maybe_successful(mres))
+                       {
+                           QR_Destructor(mres);
+                           if (stmt)
+                               SC_set_error(stmt, STMT_EXEC_ERROR, "move error occured", func);
+                           return -1;
+                       }
+
+                       if (sscanf(mres->command, "MOVE %u", &mback) > 0)
                        {
-                           free(tuple[lf].value);
-                           tuple[lf].value = NULL;
+                           if (mback < bmovement)
+                               mback++;
+                           if (moved < mback)
+                           {
+                               QR_set_move_backward(self);
+                               mback -= moved;
+                               moved = mback;
+                               self->move_offset = moved;
+                               rowset_start = self->cursTuple - moved + 1;
+                           }
+                           else
+                           {
+                               QR_set_move_forward(self);
+                               moved-= mback;
+                               self->move_offset = moved;
+                               rowset_start = self->cursTuple + moved + 1;
+                           }
                        }
                    }
-                   tuple += self->num_fields;
+                   else
+                   {
+                       QR_set_move_forward(self);
+                       self->move_offset = moved + self->ad_count - back_offset - 1;
+                       rowset_start = self->cursTuple +self->move_offset + 1;
+                       /* adjust move_offset */
+                       /*** self->move_offset++; ***/
+                   }
+                   if (stmt)
+                   {
+                       SC_set_rowset_start(stmt, rowset_start, TRUE); /* affects the result's rowset_start but it is reset immediately ... */
+                       stmt->currTuple = RowIdx2GIdx(-1, stmt);
+                   }
                }
-               self->fetch_count = 1;
            }
-           else
-           {
-               /* need to correct */
-               corrected = TRUE;
+       }
+       /* ... by the following call */ 
+       QR_set_rowstart_in_cache(self, -1);
+       if (QR_is_moving_backward(self))
+       {
+           self->cursTuple -= moved;
+           offset = moved - self->move_offset;
+       }
+       else
+       {
+           self->cursTuple += moved;
+           offset = self->move_offset - moved;
+       }
+       QR_Destructor(mres);
 
-               fetch_size = end_tuple - num_backend_rows;
+       self->move_offset = 0;
+       num_backend_rows = self->num_cached_rows;
+   }
+   else if (fetch_number < num_backend_rows)
+   {
+       /* return a row from cache */
+       mylog("%s: fetch_number < fcount: returning tuple %d, fcount = %d\n", func, fetch_number, num_backend_rows);
+       self->tupleField = the_tuples + (fetch_number * num_fields);
+inolog("tupleField=%x\n", self->tupleField);
+       /* move to next row */
+       QR_inc_next_in_cache(self);
+       return TRUE;
+   }
+   else if (QR_once_reached_eof(self))
+   {
+       BOOL    reached_eod = FALSE;
+       UInt4   num_total_read = self->num_total_read;
 
-               self->cache_size += fetch_size;
+       if (stmt)
+       {
+           if (stmt->currTuple + 1 >= num_total_rows)
+               reached_eod = TRUE;
+       }
+       else if (self->cursTuple + 1 >= (Int4)num_total_read)
+       {
+           if (self->ad_count == 0)
+               reached_eod = TRUE;
+       }
+       if (reached_eod)
+       {
+           mylog("next_tuple: fetch end\n");
+           self->tupleField = NULL;
+           /* end of tuples */
+           return -1;
+       }
+   }
 
-               offset = self->fetch_count;
-               self->fetch_count++;
-           }
+   end_tuple = req_size + QR_get_rowstart_in_cache(self);
+   /*
+    * See if we need to fetch another group of rows. We may be being
+    * called from send_query(), and if so, don't send another fetch,
+    * just fall through and read the tuples.
+    */
+   self->tupleField = NULL;
 
-           if (!self->backend_tuples || self->cache_size > self->count_backend_allocated)
-           {
-               self->count_backend_allocated = 0;
-               if (self->num_fields > 0)
-               {
-                   QR_REALLOC_return_with_error(self->backend_tuples, TupleField,
-                       (self->num_fields * sizeof(TupleField) * self->cache_size),
-                       self, "Out of memory while reading tuples.", FALSE)
-                   self->count_backend_allocated = self->cache_size;
-               }
-           }
-           if (self->haskeyset && (!self->keyset || self->cache_size > self->count_keyset_allocated))
+   if (!QR_is_fetching_tuples(self))
+   {
+       ci = &(conn->connInfo);
+       if (!QR_get_cursor(self))
+       {
+           mylog("%s: ALL_ROWS: done, fcount = %d, fetch_number = %d\n", func, QR_get_num_total_tuples(self), fetch_number);
+           self->tupleField = NULL;
+           QR_set_reached_eof(self);
+           return -1;      /* end of tuples */
+       }
+
+       if (QR_get_rowstart_in_cache(self) >= num_backend_rows ||
+           QR_is_moving(self))
+       {
+           TupleField *tuple = self->backend_tuples;
+
+           /* not a correction */
+           /* Determine the optimum cache size.  */
+           if (ci->drivers.fetch_max % req_size == 0)
+               fetch_size = ci->drivers.fetch_max;
+           else if ((Int4)req_size < ci->drivers.fetch_max)
+               /*fetch_size = (ci->drivers.fetch_max / req_size + 1) * req_size;*/
+               fetch_size = (ci->drivers.fetch_max / req_size) * req_size;
+           else
+               fetch_size = req_size;
+
+           self->cache_size = fetch_size;
+           /* clear obsolete tuples */
+inolog("clear obsolete %d tuples\n", num_backend_rows);
+           ClearCachedRows(tuple, num_fields, num_backend_rows);
+           QR_stop_movement(self);
+           self->move_offset = 0;
+           QR_set_next_in_cache(self, offset + 1);
+       }
+       else
+       {
+           /* 
+            *  The rowset boundary doesn't match that of
+            *  the inner resultset. Enlarge the resultset
+            *  and fetch the rest of the rowset.
+            */
+           /* The next fetch size is */
+           fetch_size = end_tuple - num_backend_rows;
+           if (fetch_size <= 0)
            {
-               self->count_keyset_allocated = 0;
-               QR_REALLOC_return_with_error(self->keyset, KeySet,
-                   (sizeof(KeySet) * self->cache_size),
-                   self, "Out of memory while reading tuples.", FALSE)
-               self->count_keyset_allocated = self->cache_size;
+               mylog("corrupted fetch_size end_tuple=%d <= cached_rows=%d\n", end_tuple, num_backend_rows);
+               return -1;
            }
-           sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor);
+           /* and enlarge the cache size */
+           self->cache_size += fetch_size;
+           offset = self->fetch_number;
+           QR_inc_next_in_cache(self);
+           boundary_adjusted = TRUE;
+       }
 
-           mylog("next_tuple: sending actual fetch (%d) query '%s'\n", fetch_size, fetch);
+       if (enlargeKeyCache(self, self->cache_size - num_backend_rows, "Out of memory while reading tuples") < 0)
+           return FALSE;
+       if (PROTOCOL_74(ci))
+       {
+           if (!SendExecuteRequest(stmt, QR_get_cursor(self),
+               fetch_size))
+               return FALSE;
+           if (!SendSyncRequest(conn))
+               return FALSE;
+       }
+       else
+       {
+           QResultClass    *res;
+           sprintf(fetch, "fetch %d in \"%s\"", fetch_size, QR_get_cursor(self));
+
+           mylog("%s: sending actual fetch (%d) query '%s'\n", func, fetch_size, fetch);
 
            /* don't read ahead for the next tuple (self) ! */
            qi.row_size = self->cache_size;
            qi.result_in = self;
            qi.cursor = NULL;
-           res = CC_send_query(self->conn, fetch, &qi, CLEAR_RESULT_ON_ABORT);
-           if (res == NULL)
+           res = CC_send_query(conn, fetch, &qi, 0, stmt);
+           if (!QR_command_maybe_successful(res))
            {
-               self->status = PGRES_FATAL_ERROR;
+               QR_set_rstatus(self, PGRES_FATAL_ERROR);
                QR_set_message(self, "Error fetching next group.");
                return FALSE;
            }
-           self->inTuples = TRUE;
        }
-       else
-       {
-           mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->num_backend_rows, self->fetch_count);
+       internally_invoked = TRUE;
+       cur_fetch = 0;
+       QR_set_fetching_tuples(self);
+   }
+   else
+   {
+       mylog("%s: inTuples = true, falling through: fcount = %d, fetch_number = %d\n", func, self->num_cached_rows, self->fetch_number);
 
-           /*
-            * This is a pre-fetch (fetching rows right after query but
-            * before any real SQLFetch() calls.  This is done so the
-            * field attributes are available.
-            */
-           self->fetch_count = 0;
-       }
+       /*
+        * This is a pre-fetch (fetching rows right after query but
+        * before any real SQLFetch() calls.  This is done so the
+        * field attributes are available.
+        */
+       QR_set_next_in_cache(self, 0);
    }
-   if (!corrected)
+
+   if (!boundary_adjusted)
    {
-       self->base = 0;
-       self->num_backend_rows = 0;
+       QR_set_rowstart_in_cache(self, offset);
+       QR_set_num_cached_rows(self, 0);
    }
 
-   conn = self->conn;
+   sock = CC_get_socket(conn);
    self->tupleField = NULL;
-   ci = &(self->conn->connInfo);
+   ci = &(conn->connInfo);
+   num_rows_in = self->num_cached_rows;
 
-   for (;;)
+   curr_eof = reached_eof_now = (QR_once_reached_eof(self) && self->cursTuple >= (Int4)self->num_total_read);
+inolog("reached_eof_now=%d\n", reached_eof_now);
+   for (rcvend = FALSE; !rcvend;)
    {
-       if (!self->cursor || !ci->drivers.use_declarefetch)
+       id = SOCK_get_id(sock);
+       response_length = SOCK_get_response_length(sock);
+inolog("id='%c' response_length=%d\n", id, response_length);
+       switch (id)
        {
-           if (self->num_fields > 0 &&
-           self->num_total_rows >= self->count_backend_allocated)
-           {
-               int tuple_size = self->count_backend_allocated;
-               mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
-               tuple_size *= 2;
-               QR_REALLOC_return_with_error(self->backend_tuples, TupleField,
-                       (tuple_size * self->num_fields * sizeof(TupleField)),
-                           self, "Out of memory while reading tuples.", FALSE)
-               self->count_backend_allocated = tuple_size;
-           }
-           if (self->haskeyset && self->num_total_rows >= self->count_keyset_allocated)
-           {
-               int tuple_size = self->count_keyset_allocated;
-               tuple_size *= 2;
-               QR_REALLOC_return_with_error(self->keyset, KeySet,
-                           (sizeof(KeySet) * tuple_size),
-                           self, "Out of memory while reading tuples.", FALSE)
-               self->count_keyset_allocated = tuple_size;
-           }
+
+           case 'P':
+               mylog("Portal name within tuples ?? just ignore\n");
+               SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
+               break;
+           case 'T':
+               mylog("Tuples within tuples ?? OK try to handle them\n");
+               QR_set_no_fetching_tuples(self);
+               if (self->num_total_read > 0)
+               {
+                   mylog("fetched %d rows\n", self->num_total_read);
+                   /* set to first row */
+                   self->tupleField = self->backend_tuples + (offset * num_fields);
+               }
+               else
+               {
+                   mylog("    [ fetched 0 rows ]\n");
+               }
+               /* add new Result class */
+               self->next = QR_Constructor();
+               if (!self->next)
+               {
+                   CC_set_error(conn, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.", func);
+                   CC_on_abort(conn, CONN_DEAD);
+                   return FALSE;
+               }
+               QR_set_cache_size(self->next, self->cache_size);
+               self = self->next;
+               if (!QR_fetch_tuples(self, conn, NULL))
+               {
+                   CC_set_error(conn, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(self), func);
+                   return FALSE;
+               }
+
+               rcvend = TRUE;
+               break;
+
+           case 'B':           /* Tuples in binary format */
+           case 'D':           /* Tuples in ASCII format  */
+
+               if (!QR_get_tupledata(self, id == 'B'))
+               {
+                   ret = FALSE;
+                   rcvend = TRUE;
+               }
+               cur_fetch++;
+               break;          /* continue reading */
+
+           case 'C':           /* End of tuple list */
+               SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
+               QR_set_command(self, cmdbuffer);
+
+               mylog("end of tuple list -- setting inUse to false: this = %x %s\n", self, cmdbuffer);
+
+               qlog("    [ fetched %d rows ]\n", self->num_total_read);
+               mylog("_%s: 'C' fetch_total = %d & this_fetch = %d\n", func, self->num_total_read, self->num_cached_rows);
+               if (QR_is_fetching_tuples(self))
+               {
+                   QR_set_no_fetching_tuples(self);
+                   if (internally_invoked)
+                   {
+                       if (PROTOCOL_74(ci)) /* Execute completed without accepting Portal Suspend */
+                           reached_eof_now = TRUE;
+                       else if (cur_fetch < fetch_size)
+                           reached_eof_now = TRUE;
+                   }
+                   else if (self->num_cached_rows < self->cache_size)
+                       reached_eof_now = TRUE;
+                   else if (!QR_get_cursor(self))
+                       reached_eof_now = TRUE;
+               }
+               if (reached_eof_now)
+               {
+                   /* last row from cache */
+                   /* We are done because we didn't even get CACHE_SIZE tuples */
+                   mylog("%s: backend_rows < CACHE_SIZE: brows = %d, cache_size = %d\n", func, num_backend_rows, self->cache_size);
+               }
+               if (!internally_invoked ||
+                   PG_VERSION_LE(conn, 6.3))
+                   rcvend = TRUE;
+               break;
+
+           case 'E':           /* Error */
+               msg_truncated = handle_error_message(conn, msgbuffer, sizeof(msgbuffer), self->sqlstate, "next_tuple", self);
+
+               mylog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
+               qlog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
+
+               rcvend = TRUE;
+               ret = FALSE;
+               break;
+
+           case 'N':           /* Notice */
+               msg_truncated = handle_notice_message(conn, cmdbuffer, sizeof(cmdbuffer), self->sqlstate, "next_tuple", self);
+               qlog("NOTICE from backend in next_tuple: '%s'\n", msgbuffer);
+               continue;
+
+           case 'Z':   /* Ready for query */
+               EatReadyForQuery(conn);
+               if (QR_is_fetching_tuples(self))
+               {
+                   reached_eof_now = TRUE;
+                   QR_set_no_fetching_tuples(self);
+               }
+               rcvend = TRUE;
+               break;
+           case 's':   /* portal suspend */
+               mylog("portal suspend");
+               QR_set_no_fetching_tuples(self);
+               break;
+           default:
+               /* skip the unexpected response if possible */
+               if (response_length >= 0)
+                   break;
+               /* this should only happen if the backend
+                   * dumped core ??? */
+               mylog("%s: Unexpected result from backend: id = '%c' (%d)\n", func, id, id);
+               qlog("%s: Unexpected result from backend: id = '%c' (%d)\n", func, id, id);
+               QR_set_message(self, "Unexpected result from backend. It probably crashed");
+               QR_set_rstatus(self, PGRES_FATAL_ERROR);
+               CC_on_abort(conn, CONN_DEAD);
+               ret = FALSE;
+               rcvend = TRUE;
        }
-       id = 67;
-       if (!QR_read_tuple(self, (char) (id==0)))
+   }
+
+   if (!QR_is_fetching_tuples(self))
+   {
+       Int4    start_idx = 0;
+
+       num_backend_rows = self->num_cached_rows;
+       if (reached_eof_now)
        {
-           self->status = PGRES_BAD_RESPONSE;
-           QR_set_message(self, "Error reading the tuple");
-           return FALSE;
+           mylog("%s: reached eof now\n", func);
+           QR_set_reached_eof(self);
+           if (!curr_eof)
+               self->cursTuple++;
+           if (self->ad_count > 0 &&
+               cur_fetch < fetch_size)
+           {
+               /* We have to append the tuples(keys) info from the added tuples(keys) here */
+               Int4 add_size;
+               TupleField  *tuple, *added_tuple;
+
+               if (curr_eof)
+               {
+                   start_idx = CacheIdx2GIdx(offset, stmt, self) - self->num_total_read;
+                   add_size = self->ad_count - start_idx;
+                   if (0 == num_backend_rows)
+                   {
+                       offset = 0;
+                       QR_set_rowstart_in_cache(self, offset);
+                       QR_set_next_in_cache(self, offset);
+                   }
+               }
+               else
+               {
+                   start_idx = 0;
+                   add_size = self->ad_count;
+               }
+               if (add_size > fetch_size - cur_fetch)
+                   add_size = fetch_size - cur_fetch;
+inolog("will add %d added_tuples from %d and select the %dth added tuple\n", add_size, start_idx, offset - num_backend_rows + start_idx);
+               if (add_size > fetch_size - cur_fetch)
+                   add_size = fetch_size - cur_fetch;
+               else if (add_size < 0)
+                   add_size = 0;
+               if (enlargeKeyCache(self, add_size, "Out of memory while adding tuples") < 0)
+                   return FALSE;
+               /* append the KeySet info first */
+               memcpy(self->keyset + num_backend_rows, (void *)(self->added_keyset + start_idx), sizeof(KeySet) * add_size);
+               /* and append the tuples info */
+               tuple = self->backend_tuples + num_fields * num_backend_rows;
+               memset(tuple, 0, sizeof(TupleField) * num_fields * add_size);
+               added_tuple = self->added_tuples + num_fields * start_idx;
+               ReplaceCachedRows(tuple, added_tuple, num_fields, add_size);
+               self->num_cached_rows += add_size;
+               self->num_cached_keys += add_size;
+               num_backend_rows = self->num_cached_rows;
+           }
        }
-       self->num_total_rows++;
-       if (self->num_fields > 0)
-           self->num_backend_rows++;
-       if (self->num_backend_rows > 0)
+       if (offset < num_backend_rows)
        {
-       /* set to first row */
-           self->tupleField = self->backend_tuples + (offset * self->num_fields);
-           return TRUE;
+           /* set to first row */
+           self->tupleField = self->backend_tuples + (offset * num_fields);
        }
        else
        {
-       /* We are surely done here (we read 0 tuples) */
-           mylog("_next_tuple: 'C': DONE (fcount == 0)\n");
-           return -1;  /* end of tuples */
+           /* We are surely done here (we read 0 tuples) */
+           mylog("_%s: 'C': DONE (fcount == %d)\n", func, num_backend_rows);
+           ret = -1;   /* end of tuples */
        }
-          /* continue reading */
    }
 
-   mylog("end of tuple list -- setting inUse to false: this = %u\n", self);
+   /*
+    If the cursor operation was invoked inside this function,
+    we have to set the status bits here.
+   */
+   if (internally_invoked && self->keyset && (self->dl_count > 0 || self->up_count > 0))
+   {
+       int i, lf;
+       Int4    lidx, hidx;
+       UInt4   *deleted = self->deleted, *updated = self->updated;
+       num_backend_rows = QR_get_num_cached_tuples(self);
+       /* For simplicty, use CURS_NEEDS_REREAD bit to mark the row */
+       for (i = num_rows_in; i < num_backend_rows; i++)
+           self->keyset[i].status |= CURS_NEEDS_REREAD;
+       hidx = RowIdx2GIdx(num_backend_rows, stmt);
+       lidx = hidx - num_backend_rows;
+       /* deleted info */
+       for (i = 0; i < self->dl_count && hidx > (Int4)deleted[i]; i++)
+       {
+           if (lidx <= (Int4)deleted[i])
+           {
+               lf = num_backend_rows - hidx + deleted[i];
+               self->keyset[lf].status = self->deleted_keyset[i].status;
+               /* mark the row off */
+               self->keyset[lf].status &= (~CURS_NEEDS_REREAD);
+           }
+       } 
+       for (i = self->up_count - 1; i >= 0; i--)
+       {
+           if (hidx > (Int4)updated[i] &&
+               lidx <= (Int4)updated[i])
+           {
+               lf = num_backend_rows - hidx + updated[i];
+               /* in case the row is marked off */
+               if (0 == (self->keyset[lf].status & CURS_NEEDS_REREAD))
+                   continue;
+               self->keyset[lf] = self->updated_keyset[i];
+               ReplaceCachedRows(self->backend_tuples + lf * num_fields, self->updated_tuples + i * num_fields, num_fields, 1);
+               self->keyset[lf].status &= (~CURS_NEEDS_REREAD); 
+           }
+       } 
+       /* reset CURS_NEEDS_REREAD bit */
+       for (i = 0; i < num_backend_rows; i++)
+       {
+           self->keyset[i].status &= (~CURS_NEEDS_REREAD);
+/*inolog("keyset[%d].status=%x\n", i, self->keyset[i].status);*/
+       }
+   }
 
-   return TRUE;
+inolog("%s returning %d offset=%d\n", func, ret, offset);
+   return ret;
 }
 
 
-char
-QR_read_tuple(QResultClass *self, char binary)
+static char
+QR_read_a_tuple_from_db(QResultClass *self, char binary)
 {
    Int2        field_lf;
    TupleField *this_tuplefield;
    KeySet  *this_keyset = NULL;
+   char        bmp,
+               bitmap[MAX_FIELDS];     /* Max. len of the bitmap */
    Int2        bitmaplen;      /* len of the bitmap in bytes */
-   Int4        len=0;
+   Int2        bitmap_pos;
+   Int2        bitcnt;
+   Int4        len;
    char       *buffer;
    int     ci_num_fields = QR_NumResultCols(self); /* speed up access */
    int     num_fields = self->num_fields;  /* speed up access */
+   SocketClass *sock = CC_get_socket(QR_get_conn(self));
    ColumnInfoClass *flds;
    int     effective_cols;
    char        tidoidbuf[32];
+   ConnInfo    *ci = &(QR_get_conn(self)->connInfo);
 
    /* set the current row to read the fields into */
    effective_cols = QR_NumPublicResultCols(self);
-   this_tuplefield = self->backend_tuples + (self->num_backend_rows * num_fields);
-   if (self->haskeyset)
+   this_tuplefield = self->backend_tuples + (self->num_cached_rows * num_fields);
+   if (QR_haskeyset(self))
    {
-       this_keyset = self->keyset + self->num_total_rows;
+       /* this_keyset = self->keyset + self->cursTuple + 1; */
+       this_keyset = self->keyset + self->num_cached_keys;
        this_keyset->status = 0;
    }
 
@@ -742,49 +1399,103 @@ QR_read_tuple(QResultClass *self, char binary)
     * At first the server sends a bitmap that indicates which database
     * fields are null
     */
+   if (PROTOCOL_74(ci))
+   {
+       int numf = SOCK_get_int(sock, sizeof(Int2));
+if (effective_cols > 0)
+inolog("%dth record in cache numf=%d\n", self->num_cached_rows, numf);
+else
+inolog("%dth record in key numf=%d\n", self->num_cached_keys, numf);
+   }
+   else
+       SOCK_get_n_char(sock, bitmap, bitmaplen);
+
+
+   bitmap_pos = 0;
+   bitcnt = 0;
+   bmp = bitmap[bitmap_pos];
    flds = self->fields;
+
    for (field_lf = 0; field_lf < ci_num_fields; field_lf++)
    {
-       /*
-        * NO, the field is not null. so get at first the length of
-        * the field (four bytes)
-        */
-       if (!binary)
-           len -= VARHDRSZ;
-
-       if (field_lf >= effective_cols)
-           buffer = tidoidbuf;
-       else
-           QR_MALLOC_return_with_error(buffer, char,
-               (len + 1), self,
-               PGRES_FATAL_ERROR,
-               "Couldn't allocate buffer",
-               FALSE);
-       if (field_lf >= effective_cols)
-       {
-           if (field_lf == effective_cols)
-               sscanf(buffer, "(%lu,%hu)",
-                   &this_keyset->blocknum, &this_keyset->offset);
-           else
-               this_keyset->oid = strtoul(buffer, NULL, 10);
+       /* Check if the current field is NULL */
+       if (!PROTOCOL_74(ci) && (!(bmp & 0200)))
+       {
+           /* YES, it is NULL ! */
+           this_tuplefield[field_lf].len = 0;
+           this_tuplefield[field_lf].value = 0;
        }
        else
        {
-           this_tuplefield[field_lf].len = len;
-           this_tuplefield[field_lf].value = buffer;
+           /*
+            * NO, the field is not null. so get at first the length of
+            * the field (four bytes)
+            */
+           len = SOCK_get_int(sock, VARHDRSZ);
+inolog("QR_read_a_tuple_from_db len=%d\n", len);
+           if (PROTOCOL_74(ci))
+           {
+               if (len < 0)
+               {
+                   /* YES, it is NULL ! */
+                   this_tuplefield[field_lf].len = 0;
+                   this_tuplefield[field_lf].value = 0;
+                   continue;
+               }
+           }
+           else
+           if (!binary)
+               len -= VARHDRSZ;
+
+           if (field_lf >= effective_cols)
+               buffer = tidoidbuf;
+           else
+               buffer = (char *) malloc(len + 1);
+           SOCK_get_n_char(sock, buffer, len);
+           buffer[len] = '\0';
+
+           mylog("qresult: len=%d, buffer='%s'\n", len, buffer);
+
+           if (field_lf >= effective_cols)
+           {
+               if (field_lf == effective_cols)
+                   sscanf(buffer, "(%lu,%hu)",
+                       &this_keyset->blocknum, &this_keyset->offset);
+               else
+                   this_keyset->oid = strtoul(buffer, NULL, 10);
+           }
+           else
+           {
+               this_tuplefield[field_lf].len = len;
+               this_tuplefield[field_lf].value = buffer;
+
+           /*
+            * This can be used to set the longest length of the column
+            * for any row in the tuple cache.  It would not be accurate
+            * for varchar and text fields to use this since a tuple cache
+            * is only 100 rows. Bpchar can be handled since the strlen of
+            * all rows is fixed, assuming there are not 100 nulls in a
+            * row!
+            */
+
+               if (flds && flds->display_size && flds->display_size[field_lf] < len)
+                   flds->display_size[field_lf] = len;
+           }
+       }
+
        /*
-        * This can be used to set the longest length of the column
-        * for any row in the tuple cache.  It would not be accurate
-        * for varchar and text fields to use this since a tuple cache
-        * is only 100 rows. Bpchar can be handled since the strlen of
-        * all rows is fixed, assuming there are not 100 nulls in a
-        * row!
+        * Now adjust for the next bit to be scanned in the next loop.
         */
-           if (flds && flds->display_size && flds->display_size[field_lf] < len)
-               flds->display_size[field_lf] = len;
+       bitcnt++;
+       if (BYTELEN == bitcnt)
+       {
+           bitmap_pos++;
+           bmp = bitmap[bitmap_pos];
+           bitcnt = 0;
        }
+       else
+           bmp <<= 1;
    }
-
-   self->currTuple++;
+   self->cursTuple++;
    return TRUE;
 }
index 2db7d998fcc03ec84e6307f2981d36842fd38cf0..09f110fb37922aa097fabf73ed77a727870af3b6 100644 (file)
--- a/qresult.h
+++ b/qresult.h
 #define __QRESULT_H__
 
 #include "psqlodbc.h"
+
 #include "connection.h"
+#include "socket.h"
 #include "columninfo.h"
-#include "tuplelist.h"
 #include "tuple.h"
 
+#include   <libpq-fe.h>
+typedef ExecStatusType QueryResultCode;
+#define    PGRES_FIELDS_OK     100
+#define    PGRES_INTERNAL_ERROR    (PGRES_FIELDS_OK + 1)
+
+enum
+{
+   FQR_FETCHING_TUPLES = 1L    /* is fetching tuples from db */
+   ,FQR_REACHED_EOF = (1L << 1)    /* reached eof */
+   ,FQR_HAS_VALID_BASE = (1L << 2)
+};
 
 struct QResultClass_
 {
    ColumnInfoClass *fields;    /* the Column information */
-   TupleListClass *manual_tuples;      /* manual result tuple list */
    ConnectionClass *conn;      /* the connection this result is using
                                 * (backend) */
    QResultClass    *next;      /* the following result class */
 
    /* Stuff for declare/fetch tuples */
-   int         num_total_rows; /* total count of rows read in */
-   int         count_backend_allocated;/* m(re)alloced count */
-   int         count_keyset_allocated; /* m(re)alloced count */
-   int         num_backend_rows;   /* count of tuples kept in backend_tuples member */
-   int         fetch_count;    /* logical rows read so far */
-   int         currTuple;
-   int         base;
-
-   int         num_fields;     /* number of fields in the result */
-   int         cache_size;
-   int         rowset_size;
-   Int4            recent_processed_row_count;
-
-   ExecStatusType status;
-
-   char       *message;
-   char       *cursor;         /* The name of the cursor for select
-                                * statements */
-   char       *command;
-   char       *notice;
-
-   TupleField *backend_tuples; /* data from the backend (the tuple cache) */
+   UInt4       num_total_read; /* the highest absolute postion ever read in + 1 */
+   UInt4       count_backend_allocated;/* m(re)alloced count */
+   UInt4       num_cached_rows;    /* count of tuples kept in backend_tuples member */
+   Int4        fetch_number;   /* 0-based index to the tuple to read next */
+   Int4        cursTuple;  /* absolute current position in the servr's cursor used to retrieve tuples from the DB */
+   UInt4       move_offset;
+   Int4        base;       /* relative position of rowset start in the current data cache(backend_tuples) */
+
+   UInt2       num_fields; /* number of fields in the result */
+   UInt2       num_key_fields; /* number of key fields in the result */
+   UInt4       cache_size;
+   UInt4       rowset_size_include_ommitted;
+   Int4        recent_processed_row_count;
+
+   QueryResultCode rstatus;    /* result status */
+
+   char    sqlstate[8];
+   char    *message;
+   char *cursor_name;  /* The name of the cursor for select
+                    * statements */
+   char    *command;
+   char    *notice;
+
+   TupleField *backend_tuples; /* data from the backend (the tuple cache) */
    TupleField *tupleField;     /* current backend tuple being retrieved */
 
-   char        inTuples;   /* is a fetch of rows from the backend
-                       in  progress ? */
-   char        aborted;    /* was aborted ? */
-   char        haskeyset;  /* this result contains keyset ? */
+   char    pstatus;        /* processing status */
+   char    aborted;        /* was aborted ? */
+   char    flags;          /* this result contains keyset etc ? */
+   char    move_direction;     /* must move before fetching this
+                       result set */
+   UInt4       count_keyset_allocated; /* m(re)alloced count */
+   UInt4       num_cached_keys;    /* count of keys kept in backend_keys member */
    KeySet      *keyset;
+   Int4        key_base;   /* relative position of rowset start in the current keyset cache */
    UInt4       reload_count;
-   UInt2       rb_alloc;   /* count of allocated rollback info */
-   UInt2       rb_count;   /* count of rollback info */
-   Rollback    *rollback;
-   UInt2       dl_alloc;   /* count of allocated deleted info */
-   UInt2       dl_count;   /* count of deleted info */
-   UInt4       *deleted;
+   UInt2       rb_alloc;   /* count of allocated rollback info */  
+   UInt2       rb_count;   /* count of rollback info */    
+   Rollback    *rollback;  
+   UInt4       ad_alloc;   /* count of allocated added info */
+   UInt4       ad_count;   /* count of newly added rows */
+   KeySet      *added_keyset;  /* added keyset info */
+   TupleField  *added_tuples;  /* added data by myself */
+   UInt2       dl_alloc;   /* count of allocated deleted info */   
+   UInt2       dl_count;   /* count of deleted info */ 
+   UInt4       *deleted;   /* deleted index info */
+   KeySet      *deleted_keyset;    /* deleted keyset info */
+   UInt2       up_alloc;   /* count of allocated updated info */   
+   UInt2       up_count;   /* count of updated info */ 
+   UInt4       *updated;   /* updated index info */
+   KeySet      *updated_keyset;    /* uddated keyset info */
+   TupleField  *updated_tuples;    /* uddated data by myself */
 };
 
-#define QR_get_fields(self)                    (self->fields)
+enum {
+    FQR_HASKEYSET  = 1L
+   ,FQR_WITHHOLD   = (1L << 1)
+   ,FQR_HOLDPERMANENT = (1L << 2) /* the cursor is alive across transactions */ 
+   ,FQR_SYNCHRONIZEKEYS = (1L<<3) /* synchronize the keyset range with that of cthe tuples cache */
+}; 
+
+#define    QR_haskeyset(self)      (0 != (self->flags & FQR_HASKEYSET))
+#define    QR_is_withhold(self)        (0 != (self->flags & FQR_WITHHOLD))
+#define    QR_is_permanent(self)       (0 != (self->flags & FQR_HOLDPERMANENT))
+#define    QR_synchronize_keys(self)   (0 != (self->flags & FQR_SYNCHRONIZEKEYS))
+#define QR_get_fields(self)        (self->fields)
 
 
 /* These functions are for retrieving data from the qresult */
-/* Retrieve results from manual_tuples since it has the results */
-#define QR_get_value_manual(self, tupleno, fieldno) (TL_get_fieldval(self->manual_tuples, tupleno, fieldno))
-#define QR_get_value_backend(self,fieldno)         (TL_get_fieldval(self->manual_tuples,self->currTuple, fieldno))
-#define QR_get_value_backend_row(self, tupleno, fieldno) (TL_get_fieldval(self->manual_tuples, tupleno, fieldno))
+#define QR_get_value_backend(self, fieldno)    (self->tupleField[fieldno].value)
+#define QR_get_value_backend_row(self, tupleno, fieldno) ((self->backend_tuples + (tupleno * self->num_fields))[fieldno].value)
 
 /* These functions are used by both manual and backend results */
 #define QR_NumResultCols(self)     (CI_get_num_fields(self->fields))
-#define QR_NumPublicResultCols(self)   (self->haskeyset ? CI_get_num_fields(self->fields) - 2 : CI_get_num_fields(self->fields))
+#define QR_NumPublicResultCols(self)   (QR_haskeyset(self) ? (CI_get_num_fields(self->fields) - self->num_key_fields) : CI_get_num_fields(self->fields))
 #define QR_get_fieldname(self, fieldno_)   (CI_get_fieldname(self->fields, fieldno_))
 #define QR_get_fieldsize(self, fieldno_)   (CI_get_fieldsize(self->fields, fieldno_))
 #define QR_get_display_size(self, fieldno_) (CI_get_display_size(self->fields, fieldno_))
@@ -82,74 +118,117 @@ struct QResultClass_
 #define QR_get_field_type(self, fieldno_)  (CI_get_oid(self->fields, fieldno_))
 
 /* These functions are used only for manual result sets */
-#define QR_get_num_total_tuples(self)      (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->num_total_rows)
-#define QR_get_num_backend_tuples(self)        (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->num_backend_rows)
-#define QR_add_tuple(self, new_tuple)      (TL_add_tuple(self->manual_tuples, new_tuple))
-#define QR_set_field_info(self, field_num, name, adtid, adtsize)  (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1))
+#define QR_get_num_total_tuples(self)      (QR_once_reached_eof(self) ? (self->num_total_read + self->ad_count) : self->num_total_read)
+#define QR_get_num_total_read(self)        (self->num_total_read)
+#define QR_get_num_cached_tuples(self)     (self->num_cached_rows)
+#define QR_set_field_info(self, field_num, name, adtid, adtsize, relid, attid)  (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1, relid, attid))
+#define QR_set_field_info_v(self, field_num, name, adtid, adtsize)  (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1, 0, 0))
 
 /* status macros */
-#define QR_command_successful(self)    ( !(self->status == PGRES_BAD_RESPONSE || self->status == PGRES_NONFATAL_ERROR || self->status == PGRES_FATAL_ERROR))
-#define QR_command_maybe_successful(self) ( !(self->status == PGRES_BAD_RESPONSE || self->status == PGRES_FATAL_ERROR))
-#define QR_command_nonfatal(self)  ( self->status == PGRES_NONFATAL_ERROR)
-#define QR_command_fatal(self) ( self->status == PGRES_FATAL_ERROR)
-#define QR_end_tuples(self)        ( self->status == PGRES_END_TUPLES)
-#define QR_set_status(self, condition)     ( self->status = condition )
+#define QR_command_successful(self)    (self && !(self->rstatus == PGRES_BAD_RESPONSE || self->rstatus == PGRES_NONFATAL_ERROR || self->rstatus == PGRES_FATAL_ERROR))
+#define QR_command_maybe_successful(self) (self && !(self->rstatus == PGRES_BAD_RESPONSE || self->rstatus == PGRES_FATAL_ERROR))
+#define QR_command_nonfatal(self)  ( self->rstatus == PGRES_NONFATAL_ERROR)
+#define QR_set_conn(self, conn_)           ( self->conn = conn_ )
+#define QR_set_rstatus(self, condition)        ( self->rstatus = condition )
+#define QR_set_sqlstatus(self, status)     strcpy(self->sqlstatus, status)
 #define QR_set_aborted(self, aborted_)     ( self->aborted = aborted_)
-#define QR_set_haskeyset(self)     (self->haskeyset = TRUE)
+#define QR_set_haskeyset(self)     (self->flags |= FQR_HASKEYSET)
+#define QR_set_synchronize_keys(self)  (self->flags |= FQR_SYNCHRONIZEKEYS)
+#define QR_set_no_cursor(self)     (self->flags &= ~(FQR_WITHHOLD | FQR_HOLDPERMANENT))
+#define QR_set_withhold(self)      (self->flags |= FQR_WITHHOLD)
+#define QR_set_permanent(self)     (self->flags |= FQR_HOLDPERMANENT)
+#define    QR_set_reached_eof(self)    (self->pstatus |= FQR_REACHED_EOF)
+#define    QR_set_fetching_tuples(self)    (self->pstatus |= FQR_FETCHING_TUPLES)
+#define    QR_set_no_fetching_tuples(self) (self->pstatus &= ~FQR_FETCHING_TUPLES)
+#define QR_set_has_valid_base(self)    (self->pstatus |= FQR_HAS_VALID_BASE)
+#define QR_set_no_valid_base(self) (self->pstatus &= ~FQR_HAS_VALID_BASE)
+#define    QR_inc_num_cache(self) \
+do { \
+   self->num_cached_rows++; \
+   if (QR_haskeyset(self)) \
+       self->num_cached_keys++; \
+} while (0)
+#define    QR_set_next_in_cache(self, number) \
+do { \
+   inolog("set the number to %d to read next\n", number); \
+   self->fetch_number = number; \
+} while (0)
+#define    QR_inc_next_in_cache(self) \
+do { \
+   inolog("increased the number %d", self->fetch_number); \
+   self->fetch_number++; \
+   inolog("to %d to next read\n", self->fetch_number); \
+} while (0)
 
 #define QR_get_message(self)               (self->message)
 #define QR_get_command(self)               (self->command)
-#define QR_get_notice(self)                    (self->notice)
-#define QR_get_status(self)                    (self->status)
+#define QR_get_notice(self)                (self->notice)
+#define QR_get_rstatus(self)               (self->rstatus)
 #define QR_get_aborted(self)               (self->aborted)
-
-#define QR_aborted(self)                   (!self || self->aborted)
-
-#define QR_MALLOC_return_with_error(t, tp, s, self, n, m, r) \
-   { \
-       if (t = (tp *) malloc(s), NULL == t) \
-       { \
-           QR_set_status(self, n); \
-           QR_set_message(self, m); \
-           return r; \
-       } \
-   }
-#define QR_REALLOC_return_with_error(t, tp, s, self, m, r) \
-   { \
-       if (t = (tp *) realloc(t, s), NULL == t) \
-       { \
-           QR_set_status(self, PGRES_FATAL_ERROR); \
-           QR_set_message(self, m); \
-           return r; \
-       } \
-   }
-#define QR_MALLOC_exit_if_error(t, tp, s, self, n, m) \
-   { \
-       if (t = (tp *) malloc(s), NULL == t) \
-       { \
-           self->status = n; \
-           QR_set_message(self, m); \
-           goto MALLOC_exit; \
-       } \
-   }
+#define QR_get_conn(self)              (self->conn)
+#define QR_get_cursor(self)                (self->cursor_name)
+#define QR_get_rowstart_in_cache(self)         (self->base)
+#define QR_once_reached_eof(self)  ((self->pstatus & FQR_REACHED_EOF) != 0)
+#define QR_is_fetching_tuples(self)    ((self->pstatus & FQR_FETCHING_TUPLES) != 0)
+#define    QR_has_valid_base(self)     (0 != (self->pstatus & FQR_HAS_VALID_BASE))
+
+#define QR_aborted(self)       (!self || self->aborted)
+#define QR_get_reqsize(self)       (self->rowset_size_include_ommitted)
+
+#define QR_stop_movement(self)     (self->move_direction = 0)
+#define QR_is_moving(self)     (0 != self->move_direction)
+#define QR_is_not_moving(self)     (0 == self->move_direction)
+#define QR_set_move_forward(self)  (self->move_direction = 1)
+#define QR_is_moving_forward(self) (1 == self->move_direction)
+#define QR_set_move_backward(self) (self->move_direction = -1)
+#define QR_is_moving_backward(self)    (-1 == self->move_direction)
+#define QR_set_move_from_the_last(self)    (self->move_direction = 2)
+#define QR_is_moving_from_the_last(self)   (2 == self->move_direction)
+#define QR_is_moving_not_backward(self)    (0 < self->move_direction)
 
 /* Core Functions */
-QResultClass *QR_Constructor(void);
+QResultClass   *QR_Constructor(void);
 void       QR_Destructor(QResultClass *self);
-char       QR_read_tuple(QResultClass *self, char binary);
-int            QR_next_tuple(QResultClass *self);
+TupleField *QR_AddNew(QResultClass *self);
+BOOL       QR_get_tupledata(QResultClass *self, BOOL binary);
+int            QR_next_tuple(QResultClass *self, StatementClass *);
 int            QR_close(QResultClass *self);
-char       QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor);
+void       QR_close_result(QResultClass *self, BOOL destroy);
+char       QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, const char *cursor);
 void       QR_free_memory(QResultClass *self);
 void       QR_set_command(QResultClass *self, const char *msg);
 void       QR_set_message(QResultClass *self, const char *msg);
+void       QR_add_message(QResultClass *self, const char *msg);
 void       QR_set_notice(QResultClass *self, const char *msg);
+void       QR_add_notice(QResultClass *self, const char *msg);
 
-void       QR_set_num_fields(QResultClass *self, int new_num_fields);  /* manual result only */
+void       QR_set_num_fields(QResultClass *self, int new_num_fields); /* catalog functions' result only */
 
-void       QR_inc_base(QResultClass *self, int base_inc);
+void       QR_set_num_cached_rows(QResultClass *, int);
+void       QR_set_rowstart_in_cache(QResultClass *, int);
+void       QR_inc_rowstart_in_cache(QResultClass *self, int base_inc);
 void       QR_set_cache_size(QResultClass *self, int cache_size);
 void       QR_set_rowset_size(QResultClass *self, int rowset_size);
 void       QR_set_position(QResultClass *self, int pos);
+void       QR_set_cursor(QResultClass *self, const char *name);
+Int4       getNthValid(const QResultClass *self, Int4 sta, UWORD orientation, UInt4 nth, Int4 *nearest);
 
-#endif
+#define QR_MALLOC_return_with_error(t, tp, s, a, m, r) \
+do { \
+   if (t = (tp *) malloc(s), NULL == t) \
+   { \
+       QR_set_rstatus(a, PGRES_FATAL_ERROR); \
+       QR_set_message(a, m); \
+       return r; \
+   } \
+} while (0)
+#define QR_REALLOC_return_with_error(t, tp, s, a, m, r) \
+do { \
+   if (t = (tp *) realloc(t, s), NULL == t) \
+   { \
+       QR_set_rstatus(a, PGRES_FATAL_ERROR); \
+       QR_set_message(a, m); \
+       return r; \
+   } \
+} while (0)
+#endif /* __QRESULT_H__ */
index 5aad119c688d437b7bc00164ca085b5c776239b5..c1705fbeb35b130414237eb0e2e6d266aece0fa7 100644 (file)
 #define IDS_ADVANCE_OPTION_DSN2         7
 #define IDS_ADVANCE_OPTION_CON2         8
 #define IDS_ADVANCE_CONNECTION          9
-#define IDS_SSLREQUEST_PREFER           10
-#define IDS_SSLREQUEST_ALLOW            11
-#define IDS_SSLREQUEST_REQUIRE          12
-#define IDS_SSLREQUEST_DISABLE          13
 #define DLG_OPTIONS_DRV                 102
 #define DLG_OPTIONS_DS                  103
-#define DLG_OPTIONS_GLOBAL              104
-#define IDC_DSNAME                      400
-#define IDC_DSNAMETEXT                  401
-#define IDC_DESC                        404
-#define IDC_SERVER                      407
-#define IDC_DATABASE                    408
+#define DLG_OPTIONS_GLOBAL     104
+#define IDC_DSNAME         400
+#define IDC_DSNAMETEXT         401
+#define IDC_DESC           404
+#define IDC_SERVER         407
+#define IDC_DATABASE           408
+#define IDC_SSLMODE            409
+#define IDS_SSLREQUEST_PREFER      410
+#define IDS_SSLREQUEST_ALLOW       411
+#define IDS_SSLREQUEST_REQUIRE     412
+#define IDS_SSLREQUEST_DISABLE     413
+#define IDC_NOTICE_USER            414
 #define DLG_CONFIG                      1001
 #define IDC_PORT                        1002
 #define DLG_DRIVER_CHANGE               1002
@@ -34,6 +36,7 @@
 #define DS_SHOWOIDCOLUMN                1012
 #define DS_FAKEOIDINDEX                 1013
 #define DRV_COMMLOG                     1014
+#define DS_PG62                         1016
 #define IDC_DATASOURCE                  1018
 #define DRV_OPTIMIZER                   1019
 #define DS_CONNSETTINGS                 1020
@@ -61,6 +64,8 @@
 #define DRV_CANCELASFREESTMT            1053
 #define IDC_OPTIONS                     1054
 #define DRV_KSQO                        1055
+#define DS_PG64                         1057
+#define DS_PG63                         1058
 #define DRV_OR_DSN                      1059
 #define DRV_DEBUG                       1060
 #define DS_DISALLOWPREMATURE            1061
 #define IDC_DRIVERNAME                  1076
 #define IDC_MANAGEDSN                   1077
 #define IDC_DRIVER_LIST                 1078
-#define IDC_SSLMODE                     1079
+#define DS_PG74                1079
+#define DS_NO_ROLLBACK         1080
+#define DS_TRANSACTION_ROLLBACK        1081
+#define DS_STATEMENT_ROLLBACK      1082
 
 // Next default values for new objects
 // 
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        109
+#define _APS_NEXT_RESOURCE_VALUE        105
 #define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1082
+#define _APS_NEXT_CONTROL_VALUE         1083
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
index bbe2da0c81c3db562a600b498cbec3c370d3d4ff..191639da3e47b618c82fab0da0ba5acc362539ea 100644 (file)
--- a/results.c
+++ b/results.c
@@ -1,4 +1,4 @@
-/*-------
+/*
  * Module:         results.c
  *
  * Description:        This module contains functions related to
@@ -18,6 +18,7 @@
 #include "psqlodbc.h"
 
 #include <string.h>
+#include "psqlodbc.h"
 #include "dlg_specific.h"
 #include "environ.h"
 #include "connection.h"
 #include "pgtypes.h"
 
 #include <stdio.h>
+#include <limits.h>
 
 #include "pgapifunc.h"
 
 
 
 RETCODE        SQL_API
-PGAPI_RowCount(HSTMT hstmt,
-       SQLINTEGER *pcrow)
+PGAPI_RowCount(
+              HSTMT hstmt,
+              SQLLEN FAR * pcrow)
 {
    CSTR func = "PGAPI_RowCount";
    StatementClass *stmt = (StatementClass *) hstmt;
@@ -49,13 +52,22 @@ PGAPI_RowCount(HSTMT hstmt,
        return SQL_INVALID_HANDLE;
    }
    ci = &(SC_get_conn(stmt)->connInfo);
+   if (stmt->proc_return > 0)
+   {
+       if (pcrow)
+{
+           *pcrow = 0;
+inolog("returning RowCount=%d\n", *pcrow);
+}
+       return SQL_SUCCESS;
+   }
+
    res = SC_get_Curres(stmt);
    if (res && pcrow)
    {
        if (stmt->status != STMT_FINISHED)
        {
-           SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get row count while statement is still executing.");
-           SC_log_error(func, "", stmt);
+           SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get row count while statement is still executing.", func);
            return  SQL_ERROR;
        }
        if (res->recent_processed_row_count >= 0)
@@ -75,9 +87,6 @@ PGAPI_RowCount(HSTMT hstmt,
 
    *pcrow = -1;
    return SQL_SUCCESS;
-   /* SC_set_errornumber(stmt, STMT_SEQUENCE_ERROR);
-   SC_log_error(func, "Bad return value", stmt);
-   return SQL_ERROR; */
 }
 
 
@@ -88,13 +97,14 @@ PGAPI_RowCount(HSTMT hstmt,
 RETCODE        SQL_API
 PGAPI_NumResultCols(
                    HSTMT hstmt,
-                   SWORD FAR * pccol)
+                   SQLSMALLINT FAR * pccol)
 {
    CSTR func = "PGAPI_NumResultCols";
    StatementClass *stmt = (StatementClass *) hstmt;
    QResultClass *result;
    char        parse_ok;
    ConnInfo   *ci;
+   RETCODE     ret = SQL_SUCCESS;
 
    mylog("%s: entering...\n", func);
    if (!stmt)
@@ -105,17 +115,24 @@ PGAPI_NumResultCols(
    ci = &(SC_get_conn(stmt)->connInfo);
 
    SC_clear_error(stmt);
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
 
+   if (stmt->proc_return > 0)
+   {
+       *pccol = 0;
+       goto cleanup;
+   }
    parse_ok = FALSE;
-   if (!stmt->manual_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
+   if (!stmt->catalog_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
    {
-       if (stmt->parse_status == STMT_PARSE_NONE)
+       if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
        {
-           mylog("PGAPI_NumResultCols: calling parse_statement on stmt=%u\n", stmt);
-           parse_statement(stmt);
+           mylog("PGAPI_NumResultCols: calling parse_statement on stmt=%x\n", stmt);
+           parse_statement(stmt, FALSE);
        }
 
-       if (stmt->parse_status != STMT_PARSE_FATAL)
+       if (SC_parsed_status(stmt) != STMT_PARSE_FATAL)
        {
            parse_ok = TRUE;
            *pccol = SC_get_IRDF(stmt)->nfields;
@@ -125,28 +142,34 @@ PGAPI_NumResultCols(
 
    if (!parse_ok)
    {
-       SC_pre_execute(stmt);
+       Int4 num_fields = SC_pre_execute(stmt);
        result = SC_get_Curres(stmt);
 
-       mylog("PGAPI_NumResultCols: result = %u, status = %d, numcols = %d\n", result, stmt->status, result != NULL ? QR_NumResultCols(result) : -1);
-       if ((!result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
+       mylog("PGAPI_NumResultCols: result = %x, status = %d, numcols = %d\n", result, stmt->status, result != NULL ? QR_NumResultCols(result) : -1);
+       /****if ((!result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) ****/
+       if (!result || num_fields < 0)
        {
            /* no query has been executed on this statement */
-           SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been executed with that handle");
-           SC_log_error(func, "", stmt);
-           return SQL_ERROR;
+           SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been executed with that handle", func);
+           ret = SQL_ERROR;
+           goto cleanup;
        }
        else if (!QR_command_maybe_successful(result))
        {
            SC_set_errornumber(stmt, STMT_EXEC_ERROR);
            SC_log_error(func, "", stmt);
-           return SQL_ERROR;
+           ret = SQL_ERROR;
+           goto cleanup;
        }
 
        *pccol = QR_NumPublicResultCols(result);
    }
 
-   return SQL_SUCCESS;
+cleanup:
+#undef return
+   if (stmt->internal)
+       ret = DiscardStatementSvp(stmt, ret, FALSE);
+   return ret;
 }
 
 
@@ -157,14 +180,14 @@ PGAPI_NumResultCols(
 RETCODE        SQL_API
 PGAPI_DescribeCol(
                  HSTMT hstmt,
-                 UWORD icol,
-                 UCHAR FAR * szColName,
-                 SWORD cbColNameMax,
-                 SWORD FAR * pcbColName,
-                 SWORD FAR * pfSqlType,
-                 UDWORD FAR * pcbColDef,
-                 SWORD FAR * pibScale,
-                 SWORD FAR * pfNullable)
+                 SQLUSMALLINT icol,
+                 SQLCHAR FAR * szColName,
+                 SQLSMALLINT cbColNameMax,
+                 SQLSMALLINT FAR * pcbColName,
+                 SQLSMALLINT FAR * pfSqlType,
+                 SQLULEN FAR * pcbColDef,
+                 SQLSMALLINT FAR * pibScale,
+                 SQLSMALLINT FAR * pfNullable)
 {
    CSTR func = "PGAPI_DescribeCol";
 
@@ -175,13 +198,14 @@ PGAPI_DescribeCol(
    QResultClass *res;
    char       *col_name = NULL;
    Int4        fieldtype = 0;
-   int         column_size = 0,
-               decimal_digits = 0;
+   SQLLEN      column_size = 0;
+   SQLINTEGER  decimal_digits = 0;
    ConnInfo   *ci;
    char        parse_ok;
+   FIELD_INFO  *fi;
    char        buf[255];
    int         len = 0;
-   RETCODE     result;
+   RETCODE     result = SQL_SUCCESS;
 
    mylog("%s: entering.%d..\n", func, icol);
 
@@ -196,12 +220,15 @@ PGAPI_DescribeCol(
 
    SC_clear_error(stmt);
 
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
    irdflds = SC_get_IRDF(stmt);
-
+#if (ODBCVER >= 0x0300)
    if (0 == icol) /* bookmark column */
    {
        SQLSMALLINT fType = stmt->options.use_bookmarks == SQL_UB_VARIABLE ? SQL_BINARY : SQL_INTEGER;
 
+inolog("answering bookmark info\n");
        if (szColName && cbColNameMax > 0)
            *szColName = '\0';
        if (pcbColName)
@@ -214,9 +241,10 @@ PGAPI_DescribeCol(
            *pibScale = 0;
        if (pfNullable)
            *pfNullable = SQL_NO_NULLS;
-       return SQL_SUCCESS;
+       result = SQL_SUCCESS;
+       goto cleanup;
    }
-
+#endif /* ODBCVER */
    /*
     * Dont check for bookmark column. This is the responsibility of the
     * driver manager.
@@ -225,74 +253,91 @@ PGAPI_DescribeCol(
    icol--;                     /* use zero based column numbers */
 
    parse_ok = FALSE;
-   if (!stmt->manual_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
+   fi = NULL;
+   if (icol < irdflds->nfields && irdflds->fi)
+   {
+       fi = irdflds->fi[icol];
+       if (fi && 0 == (fi->flag & (FIELD_PARSED_OK | FIELD_COL_ATTRIBUTE)))
+           fi = NULL;
+   }
+   if (!fi && !stmt->catalog_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
    {
-       if (stmt->parse_status == STMT_PARSE_NONE)
+       if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
        {
-           mylog("PGAPI_DescribeCol: calling parse_statement on stmt=%u\n", stmt);
-           parse_statement(stmt);
+           mylog("PGAPI_DescribeCol: calling parse_statement on stmt=%x\n", stmt);
+           parse_statement(stmt, FALSE);
        }
 
-       mylog("PARSE: DescribeCol: icol=%d, stmt=%u, stmt->nfld=%d, stmt->fi=%u\n", icol, stmt, irdflds->nfields, irdflds->fi);
+       mylog("PARSE: DescribeCol: icol=%d, stmt=%x, stmt->nfld=%d, stmt->fi=%x\n", icol, stmt, irdflds->nfields, irdflds->fi);
 
-       if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[icol])
+       if (SC_parsed_status(stmt) != STMT_PARSE_FATAL && irdflds->fi)
        {
-           if (icol >= irdflds->nfields)
+           if (icol < irdflds->nfields)
+               fi = irdflds->fi[icol];
+           else
            {
-               SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.");
-               SC_log_error(func, "", stmt);
-               return SQL_ERROR;
+               SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.", func);
+               result = SQL_ERROR;
+               goto cleanup;
            }
            mylog("DescribeCol: getting info for icol=%d\n", icol);
-
-           fieldtype = irdflds->fi[icol]->type;
-           if (irdflds->fi[icol]->alias[0])
-               col_name = irdflds->fi[icol]->alias;
-           else
-               col_name = irdflds->fi[icol]->name;
-           column_size = irdflds->fi[icol]->column_size;
-           decimal_digits = irdflds->fi[icol]->decimal_digits;
-
-           mylog("PARSE: fieldtype=%d, col_name='%s', column_size=%d\n", fieldtype, col_name, column_size);
-           if (fieldtype > 0)
-               parse_ok = TRUE;
        }
    }
 
+   if (fi && 0 == fi->type)
+       fi = NULL;
+
    /*
     * If couldn't parse it OR the field being described was not parsed
     * (i.e., because it was a function or expression, etc, then do it the
     * old fashioned way.
     */
-   if (!parse_ok)
+   if (!fi)
    {
-       SC_pre_execute(stmt);
+       Int4 num_fields = SC_pre_execute(stmt);
 
        res = SC_get_Curres(stmt);
 
-       mylog("**** PGAPI_DescribeCol: res = %u, stmt->status = %d, !finished=%d, !premature=%d\n", res, stmt->status, stmt->status != STMT_FINISHED, stmt->status != STMT_PREMATURE);
-       if ((NULL == res) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
+       mylog("**** PGAPI_DescribeCol: res = %x, stmt->status = %d, !finished=%d, !premature=%d\n", res, stmt->status, stmt->status != STMT_FINISHED, stmt->status != STMT_PREMATURE);
+       /**** if ((NULL == res) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) ****/
+       if ((NULL == res) || num_fields < 0)
        {
            /* no query has been executed on this statement */
-           SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been assigned to this statement.");
-           SC_log_error(func, "", stmt);
-           return SQL_ERROR;
+           SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been assigned to this statement.", func);
+           result = SQL_ERROR;
+           goto cleanup;
        }
        else if (!QR_command_maybe_successful(res))
        {
            SC_set_errornumber(stmt, STMT_EXEC_ERROR);
            SC_log_error(func, "", stmt);
-           return SQL_ERROR;
+           result = SQL_ERROR;
+           goto cleanup;
        }
 
        if (icol >= QR_NumPublicResultCols(res))
        {
-           SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.");
-           sprintf(buf, "Col#=%d, #Cols=%d", icol, QR_NumResultCols(res));
+           SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.", NULL);
+           snprintf(buf, sizeof(buf), "Col#=%d, #Cols=%d,%d keys=%d", icol, QR_NumResultCols(res), QR_NumPublicResultCols(res), res->num_key_fields);
            SC_log_error(func, buf, stmt);
-           return SQL_ERROR;
+           result = SQL_ERROR;
+           goto cleanup;
        }
+   }
+   if (fi)
+   {
+       fieldtype = fi->type;
+       if (NAME_IS_VALID(fi->column_alias))
+           col_name = GET_NAME(fi->column_alias);
+       else
+           col_name = GET_NAME(fi->column_name);
+       column_size = fi->column_size;
+       decimal_digits = fi->decimal_digits;
 
+       mylog("PARSE: fieldtype=%d, col_name='%s', column_size=%d\n", fieldtype, col_name, column_size);
+   }       
+   else
+   {
        col_name = QR_get_fieldname(res, icol);
        fieldtype = QR_get_field_type(res, icol);
 
@@ -322,7 +367,7 @@ PGAPI_DescribeCol(
        if (len >= cbColNameMax)
        {
            result = SQL_SUCCESS_WITH_INFO;
-           SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the colName.");
+           SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the colName.", func);
        }
    }
 
@@ -357,7 +402,7 @@ PGAPI_DescribeCol(
        if (decimal_digits < 0)
            decimal_digits = 0;
 
-       *pibScale = decimal_digits;
+       *pibScale = (SQLSMALLINT) decimal_digits;
        mylog("describeCol: col %d  *pibScale = %d\n", icol, *pibScale);
    }
 
@@ -371,19 +416,24 @@ PGAPI_DescribeCol(
        mylog("describeCol: col %d  *pfNullable = %d\n", icol, *pfNullable);
    }
 
+cleanup:
+#undef return
+   if (stmt->internal)
+       result = DiscardStatementSvp(stmt, result, FALSE);
    return result;
 }
 
 
 /*     Returns result column descriptor information for a result set. */
 RETCODE        SQL_API
-PGAPI_ColAttributes(HSTMT hstmt,
-           SQLUSMALLINT icol,
-           SQLUSMALLINT fDescType,
-           PTR rgbDesc,
-           SQLSMALLINT cbDescMax,
-           SQLSMALLINT *pcbDesc,
-           SQLINTEGER *pfDesc)
+PGAPI_ColAttributes(
+                   HSTMT hstmt,
+                   SQLUSMALLINT icol,
+                   SQLUSMALLINT fDescType,
+                   PTR rgbDesc,
+                   SQLSMALLINT cbDescMax,
+                   SQLSMALLINT FAR * pcbDesc,
+                   SQLLEN FAR * pfDesc)
 {
    CSTR func = "PGAPI_ColAttributes";
    StatementClass *stmt = (StatementClass *) hstmt;
@@ -399,6 +449,7 @@ PGAPI_ColAttributes(HSTMT hstmt,
    int         len = 0,
                value = 0;
    const   FIELD_INFO  *fi = NULL;
+   const   TABLE_INFO  *ti = NULL;
 
    mylog("%s: entering..col=%d %d len=%d.\n", func, icol, fDescType,
                cbDescMax);
@@ -421,8 +472,10 @@ PGAPI_ColAttributes(HSTMT hstmt,
     * is ignored anyway, so it may be 0.
     */
 
+#if (ODBCVER >= 0x0300)
    if (0 == icol && SQL_DESC_COUNT != fDescType) /* bookmark column */
    {
+inolog("answering bookmark info\n");
        switch (fDescType)
        {
            case SQL_DESC_OCTET_LENGTH:
@@ -436,7 +489,7 @@ PGAPI_ColAttributes(HSTMT hstmt,
        }
        return SQL_SUCCESS;
    }
-
+#endif /* ODBCVER */
    col_idx = icol - 1;
 
    /* atoi(ci->unknown_sizes); */
@@ -447,12 +500,12 @@ PGAPI_ColAttributes(HSTMT hstmt,
        unknown_sizes = UNKNOWNS_AS_MAX;
 
    parse_ok = FALSE;
-   if (ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
+   if (!stmt->catalog_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
    {
-       if (stmt->parse_status == STMT_PARSE_NONE)
+       if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
        {
-           mylog("PGAPI_ColAttributes: calling parse_statement\n");
-           parse_statement(stmt);
+           mylog("%s: calling parse_statement\n", func);
+           parse_statement(stmt, FALSE);
        }
 
        cols = irdflds->nfields;
@@ -461,8 +514,11 @@ PGAPI_ColAttributes(HSTMT hstmt,
         * Column Count is a special case.  The Column number is ignored
         * in this case.
         */
-
+#if (ODBCVER >= 0x0300)
        if (fDescType == SQL_DESC_COUNT)
+#else
+       if (fDescType == SQL_COLUMN_COUNT)
+#endif /* ODBCVER */
        {
            if (pfDesc)
                *pfDesc = cols;
@@ -470,12 +526,11 @@ PGAPI_ColAttributes(HSTMT hstmt,
            return SQL_SUCCESS;
        }
 
-       if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi)
+       if (SC_parsed_status(stmt) != STMT_PARSE_FATAL && irdflds->fi)
        {
            if (col_idx >= cols)
            {
-               SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.");
-               SC_log_error(func, "", stmt);
+               SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.", func);
                return SQL_ERROR;
            }
            if (irdflds->fi[col_idx])
@@ -487,18 +542,20 @@ PGAPI_ColAttributes(HSTMT hstmt,
        }
    }
 
-   if (parse_ok)
+   if (col_idx < irdflds->nfields && irdflds->fi)
        fi = irdflds->fi[col_idx];
+   if (fi && 0 != (fi->flag & (FIELD_COL_ATTRIBUTE | FIELD_PARSED_OK)))
+       ;
    else
    {
+       fi = NULL;
        SC_pre_execute(stmt);
 
-       mylog("**** PGAPI_ColAtt: result = %u, status = %d, numcols = %d\n", SC_get_Curres(stmt), stmt->status, SC_get_Curres(stmt) != NULL ? QR_NumResultCols(SC_get_Curres(stmt)) : -1);
+       mylog("**** PGAPI_ColAtt: result = %x, status = %d, numcols = %d\n", SC_get_Curres(stmt), stmt->status, SC_get_Curres(stmt) != NULL ? QR_NumResultCols(SC_get_Curres(stmt)) : -1);
 
        if ((NULL == SC_get_Curres(stmt)) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
        {
-           SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get column attributes: no result found.");
-           SC_log_error(func, "", stmt);
+           SC_set_error(stmt, STMT_EXEC_ERROR, "Can't get column attributes: no result found.", func);
            return SQL_ERROR;
        }
 
@@ -508,7 +565,11 @@ PGAPI_ColAttributes(HSTMT hstmt,
         * Column Count is a special case.  The Column number is ignored
         * in this case.
         */
+#if (ODBCVER >= 0x0300)
        if (fDescType == SQL_DESC_COUNT)
+#else
+       if (fDescType == SQL_COLUMN_COUNT)
+#endif /* ODBCVER */
        {
            if (pfDesc)
                *pfDesc = cols;
@@ -518,22 +579,29 @@ PGAPI_ColAttributes(HSTMT hstmt,
 
        if (col_idx >= cols)
        {
-           SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.");
-           SC_log_error(func, "", stmt);
+           SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.", func);
            return SQL_ERROR;
        }
 
        field_type = QR_get_field_type(SC_get_Curres(stmt), col_idx);
-       if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[col_idx])
+       if (SC_parsed_status(stmt) != STMT_PARSE_FATAL && irdflds->fi && col_idx < irdflds->nfields)
            fi = irdflds->fi[col_idx];
    }
+   if (fi)
+   {
+       ti = fi->ti;
+       field_type = fi->type;
+   }
 
    mylog("colAttr: col %d field_type = %d\n", col_idx, field_type);
 
    switch (fDescType)
    {
        case SQL_COLUMN_AUTO_INCREMENT: /* == SQL_DESC_AUTO_UNIQUE_VALUE */
-           value = pgtype_auto_increment(stmt, field_type);
+           if (fi && fi->auto_increment)
+               value = TRUE;
+           else
+               value = pgtype_auto_increment(stmt, field_type);
            if (value == -1)    /* non-numeric becomes FALSE (ODBC Doc) */
                value = FALSE;
 inolog("AUTO_INCREMENT=%d\n", value);
@@ -552,25 +620,31 @@ inolog("AUTO_INCREMENT=%d\n", value);
        case SQL_COLUMN_DISPLAY_SIZE: /* == SQL_DESC_DISPLAY_SIZE */
            value = (fi && 0 != fi->display_size) ? fi->display_size : pgtype_display_size(stmt, field_type, col_idx, unknown_sizes);
 
-           mylog("PGAPI_ColAttributes: col %d, display_size= %d\n", col_idx, value);
+           mylog("%s: col %d, display_size= %d\n", func, col_idx, value);
 
            break;
 
        case SQL_COLUMN_LABEL: /* == SQL_DESC_LABEL */
-           if (fi && fi->alias[0] != '\0')
+           if (fi && (NAME_IS_VALID(fi->column_alias)))
            {
-               p = fi->alias;
+               p = GET_NAME(fi->column_alias);
 
-               mylog("PGAPI_ColAttr: COLUMN_LABEL = '%s'\n", p);
+               mylog("%s: COLUMN_LABEL = '%s'\n", func, p);
                break;
-
            }
            /* otherwise same as column name -- FALL THROUGH!!! */
 
+#if (ODBCVER >= 0x0300)
        case SQL_DESC_NAME:
-           p = fi ? (fi->alias[0] ? fi->alias : fi->name) : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
-
-           mylog("PGAPI_ColAttr: COLUMN_NAME = '%s'\n", p);
+#else
+       case SQL_COLUMN_NAME:
+#endif /* ODBCVER */
+inolog("fi=%x", fi);
+if (fi)
+inolog(" (%s,%s)", PRINT_NAME(fi->column_alias), PRINT_NAME(fi->column_name));
+           p = fi ? (NAME_IS_NULL(fi->column_alias) ? SAFE_NAME(fi->column_name) : GET_NAME(fi->column_alias)) : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
+
+           mylog("%s: COLUMN_NAME = '%s'\n", func, p);
            break;
 
        case SQL_COLUMN_LENGTH:
@@ -578,7 +652,7 @@ inolog("AUTO_INCREMENT=%d\n", value);
            if (value < 0)
                value = 0;
 
-           mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value);
+           mylog("%s: col %d, length = %d\n", func, col_idx, value);
            break;
 
        case SQL_COLUMN_MONEY: /* == SQL_DESC_FIXED_PREC_SCALE */
@@ -586,13 +660,17 @@ inolog("AUTO_INCREMENT=%d\n", value);
 inolog("COLUMN_MONEY=%d\n", value);
            break;
 
+#if (ODBCVER >= 0x0300)
        case SQL_DESC_NULLABLE:
+#else
+       case SQL_COLUMN_NULLABLE:
+#endif /* ODBCVER */
            value = fi ? fi->nullable : pgtype_nullable(stmt, field_type);
 inolog("COLUMN_NULLABLE=%d\n", value);
            break;
 
        case SQL_COLUMN_OWNER_NAME: /* == SQL_DESC_SCHEMA_NAME */
-           p = fi && (fi->ti) ? fi->ti->schema : "";
+           p = ti ? SAFE_NAME(ti->schema_name) : NULL_STRING;
            break;
 
        case SQL_COLUMN_PRECISION: /* in 2.x */
@@ -600,7 +678,7 @@ inolog("COLUMN_NULLABLE=%d\n", value);
            if (value < 0)
                value = 0;
 
-           mylog("PGAPI_ColAttributes: col %d, column_size = %d\n", col_idx, value);
+           mylog("%s: col %d, column_size = %d\n", func, col_idx, value);
            break;
 
        case SQL_COLUMN_QUALIFIER_NAME: /* == SQL_DESC_CATALOG_NAME */
@@ -619,9 +697,9 @@ inolog("COLUMN_SCALE=%d\n", value);
            break;
 
        case SQL_COLUMN_TABLE_NAME: /* == SQL_DESC_TABLE_NAME */
-           p = fi && (fi->ti) ? fi->ti->name : "";
+           p = ti ? SAFE_NAME(ti->table_name) : NULL_STRING;
 
-           mylog("PGAPI_ColAttr: TABLE_NAME = '%s'\n", p);
+           mylog("%sr: TABLE_NAME = '%s'\n", func, p);
            break;
 
        case SQL_COLUMN_TYPE: /* == SQL_DESC_CONCISE_TYPE */
@@ -651,39 +729,39 @@ inolog("COLUMN_TYPE=%d\n", value);
            value = fi ? (fi->updatable ? SQL_ATTR_WRITE : SQL_ATTR_READONLY) : SQL_ATTR_READWRITE_UNKNOWN;
            if (SQL_ATTR_READONLY != value)
            {
-               const char *name = fi ? fi->name : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
-               if (stricmp(name, "oid") == 0 ||
+               const char *name = fi ? SAFE_NAME(fi->column_name) : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
+               if (stricmp(name, OID_NAME) == 0 ||
                    stricmp(name, "ctid") == 0 ||
                    stricmp(name, "xmin") == 0)
                    value = SQL_ATTR_READONLY;
            }
 
-           mylog("PGAPI_ColAttr: UPDATEABLE = %d\n", value);
+           mylog("%s: UPDATEABLE = %d\n", func, value);
            break;
-
+#if (ODBCVER >= 0x0300)
        case SQL_DESC_BASE_COLUMN_NAME:
 
-           p = fi ? fi->name : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
+           p = fi ? SAFE_NAME(fi->column_name) : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
 
-           mylog("PGAPI_ColAttr: BASE_COLUMN_NAME = '%s'\n", p);
+           mylog("%s: BASE_COLUMN_NAME = '%s'\n", func, p);
            break;
        case SQL_DESC_BASE_TABLE_NAME: /* the same as TABLE_NAME ok ? */
-           p = (fi && (fi->ti)) ? fi->ti->name : "";
+           p = ti ? SAFE_NAME(ti->table_name) : NULL_STRING;
 
-           mylog("PGAPI_ColAttr: BASE_TABLE_NAME = '%s'\n", p);
+           mylog("%s: BASE_TABLE_NAME = '%s'\n", func, p);
            break;
        case SQL_DESC_LENGTH: /* different from SQL_COLUMN_LENGTH */
            value = (fi && fi->length > 0) ? fi->length : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
-           if (value < 0)
+           if (-1 == value)
                value = 0;
 
-           mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value);
+           mylog("%s: col %d, length = %d\n", func, col_idx, value);
            break;
        case SQL_DESC_OCTET_LENGTH:
            value = (fi && fi->length > 0) ? fi->length : pgtype_transfer_octet_length(stmt, field_type, col_idx, unknown_sizes);
-           if (value < 0)
+           if (-1 == value)
                value = 0;
-           mylog("PGAPI_ColAttributes: col %d, octet_length = %d\n", col_idx, value);
+           mylog("%s: col %d, octet_length = %d\n", func, col_idx, value);
            break;
        case SQL_DESC_PRECISION: /* different from SQL_COLUMN_PRECISION */
            if (value = FI_precision(fi), value <= 0)
@@ -691,7 +769,7 @@ inolog("COLUMN_TYPE=%d\n", value);
            if (value < 0)
                value = 0;
 
-           mylog("PGAPI_ColAttributes: col %d, desc_precision = %d\n", col_idx, value);
+           mylog("%s: col %d, desc_precision = %d\n", func, col_idx, value);
            break;
        case SQL_DESC_SCALE: /* different from SQL_COLUMN_SCALE */
            value = pgtype_scale(stmt, field_type, col_idx);
@@ -714,15 +792,14 @@ inolog("COLUMN_TYPE=%d\n", value);
            p = pgtype_literal_suffix(stmt, field_type);
            break;
        case SQL_DESC_UNNAMED:
-           value = (fi && !fi->name[0] && !fi->alias[0]) ? SQL_UNNAMED : SQL_NAMED;
+           value = (fi && NAME_IS_NULL(fi->column_name) && NAME_IS_NULL(fi->column_alias)) ? SQL_UNNAMED : SQL_NAMED;
            break;
-
+#endif /* ODBCVER */
        case 1212: /* SQL_CA_SS_COLUMN_KEY ? */
-           SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "this request may be for MS SQL Server");
+           SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "this request may be for MS SQL Server", func);
            return SQL_ERROR;
        default:
-           SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "ColAttribute for this type not implemented yet");
-           SC_log_error(func, "", stmt);
+           SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "ColAttribute for this type not implemented yet", func);
            return SQL_ERROR;
    }
 
@@ -739,7 +816,7 @@ inolog("COLUMN_TYPE=%d\n", value);
            if (len >= cbDescMax)
            {
                result = SQL_SUCCESS_WITH_INFO;
-               SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.");
+               SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.", func);
            }
        }
 
@@ -759,12 +836,13 @@ inolog("COLUMN_TYPE=%d\n", value);
 
 /* Returns result data for a single column in the current row. */
 RETCODE        SQL_API
-PGAPI_GetData(HSTMT hstmt,
-       SQLUSMALLINT icol, 
-       SQLSMALLINT fCType,
-       PTR rgbValue, 
-       SQLINTEGER cbValueMax,
-       SQLINTEGER *pcbValue)
+PGAPI_GetData(
+             HSTMT hstmt,
+             SQLUSMALLINT icol,
+             SQLSMALLINT fCType,
+             PTR rgbValue,
+             SQLLEN cbValueMax,
+             SQLLEN FAR * pcbValue)
 {
    CSTR func = "PGAPI_GetData";
    QResultClass *res;
@@ -773,11 +851,11 @@ PGAPI_GetData(HSTMT hstmt,
                num_rows;
    Int4        field_type;
    void       *value = NULL;
-   int         result;
+   RETCODE     result = SQL_SUCCESS;
    char        get_bookmark = FALSE;
    ConnInfo   *ci;
 
-   mylog("PGAPI_GetData: enter, stmt=%u\n", stmt);
+   mylog("%s: enter, stmt=%x\n", func, stmt);
 
    if (!stmt)
    {
@@ -789,15 +867,13 @@ PGAPI_GetData(HSTMT hstmt,
 
    if (STMT_EXECUTING == stmt->status)
    {
-       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get data while statement is still executing.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get data while statement is still executing.", func);
        return SQL_ERROR;
    }
 
    if (stmt->status != STMT_FINISHED)
    {
-       SC_set_error(stmt, STMT_STATUS_ERROR, "GetData can only be called after the successful execution on a SQL statement");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_STATUS_ERROR, "GetData can only be called after the successful execution on a SQL statement", func);
        return SQL_ERROR;
    }
 
@@ -805,8 +881,7 @@ PGAPI_GetData(HSTMT hstmt,
    {
        if (stmt->options.use_bookmarks == SQL_UB_OFF)
        {
-           SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled");
-           SC_log_error(func, "", stmt);
+           SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled", func);
            return SQL_ERROR;
        }
 
@@ -814,12 +889,13 @@ PGAPI_GetData(HSTMT hstmt,
        switch (fCType)
        {
            case SQL_C_BOOKMARK:
+#if (ODBCVER >= 0x0300)
            case SQL_C_VARBOOKMARK:
+#endif /* ODBCVER */
                break;
            default:
 inolog("GetData Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
-               SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Column 0 is not of type SQL_C_BOOKMARK");
-               SC_log_error(func, "", stmt);
+               SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Column 0 is not of type SQL_C_BOOKMARK", func);
                return SQL_ERROR;
        }
 
@@ -834,47 +910,31 @@ inolog("GetData Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
        num_cols = QR_NumPublicResultCols(res);
        if (icol >= num_cols)
        {
-           SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number.");
-           SC_log_error(func, "", stmt);
+           SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number.", func);
            return SQL_ERROR;
        }
    }
-   if (stmt->manual_result)
+
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
+   if (!SC_is_fetchcursor(stmt))
    {
-       if(!SC_is_fetchcursor(stmt))
-       {
-           /* make sure we're positioned on a valid row */
-           num_rows = QR_get_num_total_tuples(res);
-           if ((stmt->currTuple < 0) ||
-               (stmt->currTuple >= num_rows))
-           {
-               SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.");
-               SC_log_error(func, "", stmt);
-               return SQL_ERROR;
-           }
-       }
-       else
+       /* make sure we're positioned on a valid row */
+       num_rows = QR_get_num_total_tuples(res);
+       if ((stmt->currTuple < 0) ||
+           (stmt->currTuple >= num_rows))
        {
-           if (stmt->currTuple < 0)
-           {
-               SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.");
-               SC_log_error(func, "", stmt);
-               return SQL_ERROR;
-           }
+           SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.", func);
+           result = SQL_ERROR;
+           goto cleanup;
        }
+       mylog("     num_rows = %d\n", num_rows);
 
        if (!get_bookmark)
        {
-           if (stmt->manual_result)
-               if(SC_is_fetchcursor(stmt))
-                   value = QR_get_value_manual(res, (stmt->currTuple % stmt->hdbc->connInfo.drivers.fetch_max), icol);
-               else
-                   value = QR_get_value_manual(res, stmt->currTuple, icol);
-           else
-           {
-               Int4    curt = GIdx2ResultIdx(stmt->currTuple, stmt, res);
-               value = QR_get_value_backend_row(res, curt, icol);
-           }
+           Int4    curt = GIdx2CacheIdx(stmt->currTuple, stmt, res);
+           value = QR_get_value_backend_row(res, curt, icol);
+inolog("currT=%d base=%d rowset=%d\n", stmt->currTuple, QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt)); 
            mylog("     value = '%s'\n", value ? value : "(null)");
        }
    }
@@ -883,14 +943,17 @@ inolog("GetData Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
        /* it's a SOCKET result (backend data) */
        if (stmt->currTuple == -1 || !res || !res->tupleField)
        {
-           SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.");
-           SC_log_error(func, "", stmt);
-           return SQL_ERROR;
+           SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.", func);
+           result = SQL_ERROR;
+           goto cleanup;
        }
 
        if (!get_bookmark)
-           value = QR_get_value_backend(res, icol);
-
+       {
+           /** value = QR_get_value_backend(res, icol); maybe thiw doesn't work */
+           Int4    curt = GIdx2CacheIdx(stmt->currTuple, stmt, res);
+           value = QR_get_value_backend_row(res, curt, icol);
+       }
        mylog("  socket: value = '%s'\n", value ? value : "(null)");
    }
 
@@ -903,24 +966,25 @@ inolog("GetData Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
            if (SQL_C_BOOKMARK == fCType || 4 <= cbValueMax)
            {
                contents_get = TRUE; 
-               *((UDWORD *) rgbValue) = SC_get_bookmark(stmt);
+               *((SQLULEN *) rgbValue) = SC_get_bookmark(stmt);
            }
        }
        if (pcbValue)
-           *pcbValue = sizeof(UDWORD);
+           *pcbValue = sizeof(SQLULEN);
 
        if (contents_get)
-           return SQL_SUCCESS;
+           result = SQL_SUCCESS;
        else
        {
-           SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.");
-           return SQL_SUCCESS_WITH_INFO;
+           SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.", func);
+           result = SQL_SUCCESS_WITH_INFO;
        }
+       goto cleanup;
    }
 
    field_type = QR_get_field_type(res, icol);
 
-   mylog("**** PGAPI_GetData: icol = %d, fCType = %d, field_type = %d, value = '%s'\n", icol, fCType, field_type, value ? value : "(null)");
+   mylog("**** %s: icol = %d, fCType = %d, field_type = %d, value = '%s'\n", func, icol, fCType, field_type, value ? value : "(null)");
 
    SC_set_current_col(stmt, icol);
 
@@ -930,35 +994,44 @@ inolog("GetData Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
    switch (result)
    {
        case COPY_OK:
-           return SQL_SUCCESS;
+           result = SQL_SUCCESS;
+           break;
 
        case COPY_UNSUPPORTED_TYPE:
-           SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.");
-           SC_log_error(func, "", stmt);
-           return SQL_ERROR;
+           SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.", func);
+           result = SQL_ERROR;
+           break;
 
        case COPY_UNSUPPORTED_CONVERSION:
-           SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.");
-           SC_log_error(func, "", stmt);
-           return SQL_ERROR;
+           SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.", func);
+           result = SQL_ERROR;
+           break;
 
        case COPY_RESULT_TRUNCATED:
-           SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.");
-           return SQL_SUCCESS_WITH_INFO;
+           SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.", func);
+           result = SQL_SUCCESS_WITH_INFO;
+           break;
 
        case COPY_GENERAL_ERROR:        /* error msg already filled in */
-           SC_log_error(func, "", stmt);
-           return SQL_ERROR;
+           result = SQL_ERROR;
+           break;
 
        case COPY_NO_DATA_FOUND:
            /* SC_log_error(func, "no data found", stmt); */
-           return SQL_NO_DATA_FOUND;
+           result = SQL_NO_DATA_FOUND;
+           break;
 
        default:
-           SC_set_error(stmt, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.");
-           SC_log_error(func, "", stmt);
-           return SQL_ERROR;
+           SC_set_error(stmt, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.", func);
+           result = SQL_ERROR;
+           break;
    }
+
+cleanup:
+#undef return
+   if (stmt->internal)
+       result = DiscardStatementSvp(stmt, result, FALSE);
+   return result;
 }
 
 
@@ -975,8 +1048,9 @@ PGAPI_Fetch(
    ARDFields   *opts;
    QResultClass *res;
    BindInfoClass   *bookmark;
+   RETCODE     retval = SQL_SUCCESS;
 
-   mylog("PGAPI_Fetch: stmt = %u, stmt->result= %u\n", stmt, SC_get_Curres(stmt));
+   mylog("%s: stmt = %x, stmt->result= %x\n", func, stmt, stmt ? SC_get_Curres(stmt) : NULL);
 
    if (!stmt)
    {
@@ -988,8 +1062,7 @@ PGAPI_Fetch(
 
    if (!(res = SC_get_Curres(stmt)))
    {
-       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_Fetch.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_Fetch.", func);
        return SQL_ERROR;
    }
 
@@ -997,22 +1070,19 @@ PGAPI_Fetch(
    opts = SC_get_ARDF(stmt);
    if ((bookmark = opts->bookmark) && bookmark->buffer)
    {
-       SC_set_error(stmt, STMT_COLNUM_ERROR, "Not allowed to bind a bookmark column when using PGAPI_Fetch");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_COLNUM_ERROR, "Not allowed to bind a bookmark column when using PGAPI_Fetch", func);
        return SQL_ERROR;
    }
 
    if (stmt->status == STMT_EXECUTING)
    {
-       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.", func);
        return SQL_ERROR;
    }
 
    if (stmt->status != STMT_FINISHED)
    {
-       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Fetch can only be called after the successful execution on a SQL statement");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Fetch can only be called after the successful execution on a SQL statement", func);
        return SQL_ERROR;
    }
 
@@ -1022,27 +1092,38 @@ PGAPI_Fetch(
            return SQL_NO_DATA_FOUND;
        /* just to avoid a crash if the user insists on calling this */
        /* function even if SQL_ExecDirect has reported an Error */
-       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.", func);
        return SQL_ERROR;
    }
 
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(stmt); */
+   if (stmt->rowset_start < 0)
+       SC_set_rowset_start(stmt, 0, TRUE);
    QR_set_rowset_size(res, 1);
-   QR_inc_base(res, stmt->last_fetch_count_include_ommitted);
-
-   return SC_fetch(stmt);
+   /* QR_inc_rowstart_in_cache(res, stmt->last_fetch_count_include_ommitted); */
+   SC_inc_rowset_start(stmt, stmt->last_fetch_count_include_ommitted);
+
+   retval = SC_fetch(stmt);
+#undef return
+   if (stmt->internal)
+       retval = DiscardStatementSvp(stmt, retval, FALSE);
+   return retval;
 }
 
-#ifdef DRIVER_CURSOR_IMPLEMENT
 static RETCODE SQL_API
-SC_pos_reload_needed(StatementClass *stmt, UDWORD flag);
-static Int4
-getNthValid(QResultClass *res, Int4 sta, UWORD orientation, UInt4 nth, Int4 *nearest)
+SC_pos_reload_needed(StatementClass *stmt, UInt4 req_size, UDWORD flag);
+Int4
+getNthValid(const QResultClass *res, Int4 sta, UWORD orientation, UInt4 nth, Int4 *nearest)
 {
-   Int4    i, num_tuples = QR_get_num_total_tuples(res);
+   Int4    i, num_tuples = QR_get_num_total_tuples(res), nearp;
    UInt4   count;
    KeySet  *keyset;
 
+   if (!QR_once_reached_eof(res))
+       num_tuples = INT_MAX;
+   /* Note that the parameter nth is 1-based */
+inolog("get %dth Valid data from %d to %s [dlt=%d]", nth, sta, orientation == SQL_FETCH_PRIOR ? "backward" : "forward", res->dl_count);
    if (0 == res->dl_count)
    {
        if (SQL_FETCH_PRIOR == orientation)
@@ -1057,21 +1138,66 @@ getNthValid(QResultClass *res, Int4 sta, UWORD orientation, UInt4 nth, Int4 *nea
        }
        else
        {   
-           if ((*nearest = sta + nth - 1) < num_tuples)
+           nearp = sta - 1 + nth;
+           if (nearp < num_tuples)
+           {
+               *nearest = nearp;
                return nth;
+           }
            *nearest = num_tuples;
            return -(Int4)(num_tuples - sta);
        }
    }
    count = 0;
-   if (SQL_FETCH_PRIOR == orientation)
+   if (QR_get_cursor(res))
+   {
+       UInt4   *deleted = res->deleted;
+
+       *nearest = sta - 1 + nth;
+       if (SQL_FETCH_PRIOR == orientation)
+       {
+           for (i = res->dl_count - 1; i >=0 && *nearest <= (Int4) deleted[i]; i--)
+           {
+inolog("deleted[%d]=%d\n", i, deleted[i]);
+               if (sta >= (Int4)deleted[i])
+                   (*nearest)--;
+           }
+inolog("nearest=%d\n", *nearest);
+           if (*nearest < 0)
+           {
+               *nearest = -1;
+               count = sta + 1;
+           }
+           else
+               return nth;
+       }
+       else
+       {
+           if (!QR_once_reached_eof(res))
+               num_tuples = INT_MAX;
+           for (i = 0; i < res->dl_count && *nearest >= (Int4)deleted[i]; i++)
+           {
+               if (sta <= (Int4)deleted[i])
+                   (*nearest)++;
+           }
+           if (*nearest >= num_tuples)
+           {
+               *nearest = num_tuples;
+               count = *nearest - sta;
+           }
+           else
+               return nth;
+       }
+   }
+   else if (SQL_FETCH_PRIOR == orientation)
    {
        for (i = sta, keyset = res->keyset + sta;
            i >= 0; i--, keyset--)
        {
-           if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETING | CURS_OTHER_DELETED)))
+           if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
            {
                *nearest = i;
+inolog(" nearest=%d\n", *nearest);
                if (++count == nth)
                    return count;
            }
@@ -1083,47 +1209,105 @@ getNthValid(QResultClass *res, Int4 sta, UWORD orientation, UInt4 nth, Int4 *nea
        for (i = sta, keyset = res->keyset + sta;
            i < num_tuples; i++, keyset++)
        {
-           if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETING | CURS_OTHER_DELETED)))
+           if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
            {
                *nearest = i;
+inolog(" nearest=%d\n", *nearest);
                if (++count == nth)
                    return count;
            }
        }
        *nearest = num_tuples; 
    }
+inolog(" nearest not found\n");
    return -(Int4)count;
 }
-#endif /* DRIVER_CURSOR_IMPLEMENT */
 
+static void
+move_cursor_position_if_needed(StatementClass *self, QResultClass *res)
+{
+   int move_offset;
+   
+   /*
+    * The move direction must be initialized to is_not_moving or
+    * is_moving_from_the_last in advance.
+    */
+   if (!QR_get_cursor(res))
+   {
+       QR_stop_movement(res); /* for safety */
+       res->move_offset = 0;
+       return;
+   }
+inolog("BASE=%d numb=%d curr=%d cursT=%d\n", QR_get_rowstart_in_cache(res), res->num_cached_rows, self->currTuple, res->cursTuple);
+
+   /* retrieve "move from the last" case first */
+   if (QR_is_moving_from_the_last(res))
+   {
+       mylog("must MOVE from the last\n");
+       if (QR_once_reached_eof(res) || self->rowset_start <= QR_get_num_total_tuples(res)) /* this shouldn't happen */
+           mylog("strange situation in move from the last\n");
+       if (0 == res->move_offset)
+           res->move_offset = INT_MAX - self->rowset_start;
+else
+{
+inolog("!!move_offset=%d calc=%d\n", res->move_offset, INT_MAX - self->rowset_start);
+}
+       return;
+   }
+
+   /* normal case */
+   res->move_offset = 0;
+   move_offset = self->currTuple - res->cursTuple;
+   if (QR_get_rowstart_in_cache(res) >= 0 &&
+        QR_get_rowstart_in_cache(res) <= (Int4)res->num_cached_rows)
+   {
+       QR_set_next_in_cache(res, (QR_get_rowstart_in_cache(res) < 0) ? 0 : QR_get_rowstart_in_cache(res));
+       return;
+   }
+   if (0 == move_offset) 
+       return;
+   if (move_offset > 0)
+   {
+       QR_set_move_forward(res);
+       res->move_offset = move_offset;
+   }
+   else
+   {
+       QR_set_move_backward(res);
+       res->move_offset = -move_offset;
+   }
+}
 /*
  * return NO_DATA_FOUND macros
  *   save_rowset_start or num_tuples must be defined 
  */
 #define    EXTFETCH_RETURN_BOF(stmt, res) \
 { \
-   stmt->rowset_start = -1; \
+inolog("RETURN_BOF\n"); \
+   SC_set_rowset_start(stmt, -1, TRUE); \
    stmt->currTuple = -1; \
-   res->base += (stmt->rowset_start - save_rowset_start); \
+   /* move_cursor_position_if_needed(stmt, res); */ \
    return SQL_NO_DATA_FOUND; \
 }
 #define    EXTFETCH_RETURN_EOF(stmt, res) \
 { \
-   stmt->rowset_start = num_tuples; \
+inolog("RETURN_EOF\n"); \
+   SC_set_rowset_start(stmt, num_tuples, TRUE); \
    stmt->currTuple = -1; \
-   res->base += (stmt->rowset_start - save_rowset_start); \
+   /* move_cursor_position_if_needed(stmt, res); */ \
    return SQL_NO_DATA_FOUND; \
 }
    
 /* This fetchs a block of data (rowset). */
 RETCODE        SQL_API
-PGAPI_ExtendedFetch(HSTMT hstmt,
-           SQLUSMALLINT fFetchType,
-           SQLINTEGER irow,
-           SQLUINTEGER *pcrow,
-           SQLUSMALLINT *rgfRowStatus,
-           SQLINTEGER bookmark_offset,
-           SQLINTEGER rowsetSize)
+PGAPI_ExtendedFetch(
+                   HSTMT hstmt,
+                   SQLUSMALLINT fFetchType,
+                   SQLLEN irow,
+                   SQLULEN FAR * pcrow,
+                   SQLUSMALLINT FAR * rgfRowStatus,
+                   SQLINTEGER bookmark_offset,
+                   SQLINTEGER rowsetSize)
 {
    CSTR func = "PGAPI_ExtendedFetch";
    StatementClass *stmt = (StatementClass *) hstmt;
@@ -1131,20 +1315,19 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
    QResultClass *res;
    BindInfoClass   *bookmark;
    int         num_tuples,
-               i,
-               save_rowset_size,
+               i, fc_io;
+   Int4            save_rowset_size,
                save_rowset_start,
-               progress_size;
-   RETCODE     result;
-   char        truncated,
-               error;
+               progress_size,
+               rowset_start;
+   RETCODE     result = SQL_SUCCESS;
+   char        truncated, error, should_set_rowset_start = FALSE; 
    ConnInfo   *ci;
-   DWORD       currp;
-#ifdef DRIVER_CURSOR_IMPLEMENT
+   Int4        currp;
    UWORD       pstatus;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
+   BOOL        currp_is_valid, reached_eof;
 
-   mylog("PGAPI_ExtendedFetch: stmt=%u\n", stmt);
+   mylog("%s: stmt=%x rowsetSize=%d\n", func, stmt, rowsetSize);
 
    if (!stmt)
    {
@@ -1153,11 +1336,12 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
    }
    ci = &(SC_get_conn(stmt)->connInfo);
 
+   /* if (SC_is_fetchcursor(stmt) && !stmt->manual_result) */
    if (SQL_CURSOR_FORWARD_ONLY == stmt->options.cursor_type)
    {
        if (fFetchType != SQL_FETCH_NEXT)
        {
-           SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "The fetch type for PGAPI_ExtendedFetch isn't allowed with ForwardOnly cursor.");
+           SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "The fetch type for PGAPI_ExtendedFetch isn't allowed with ForwardOnly cursor.", func);
            return SQL_ERROR;
        }
    }
@@ -1166,8 +1350,7 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
 
    if (!(res = SC_get_Curres(stmt)))
    {
-       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Null statement result in PGAPI_ExtendedFetch.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_ExtendedFetch.", func);
        return SQL_ERROR;
    }
 
@@ -1178,22 +1361,19 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
     */
    if ((bookmark = opts->bookmark) && bookmark->buffer && stmt->options.use_bookmarks == SQL_UB_OFF)
    {
-       SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled", func);
        return SQL_ERROR;
    }
 
    if (stmt->status == STMT_EXECUTING)
    {
-       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.", func);
        return SQL_ERROR;
    }
 
    if (stmt->status != STMT_FINISHED)
    {
-       SC_set_error(stmt, STMT_STATUS_ERROR, "ExtendedFetch can only be called after the successful execution on a SQL statement");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_STATUS_ERROR, "ExtendedFetch can only be called after the successful execution on a SQL statement", func);
        return SQL_ERROR;
    }
 
@@ -1203,8 +1383,7 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
            return SQL_NO_DATA_FOUND;
        /* just to avoid a crash if the user insists on calling this */
        /* function even if SQL_ExecDirect has reported an Error */
-       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.", func);
        return SQL_ERROR;
    }
 
@@ -1217,12 +1396,19 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
        *pcrow = 0;
 
    num_tuples = QR_get_num_total_tuples(res);
+   reached_eof = QR_once_reached_eof(res) && QR_get_cursor(res);
+   if (SC_is_fetchcursor(stmt) && !reached_eof)
+       num_tuples = INT_MAX;
 
+inolog("num_tuples=%d\n", num_tuples);
    /* Save and discard the saved rowset size */
-   save_rowset_start = stmt->rowset_start;
+   save_rowset_start = SC_get_rowset_start(stmt);
    save_rowset_size = stmt->save_rowset_size;
    stmt->save_rowset_size = -1;
+   rowset_start = SC_get_rowset_start(stmt);
 
+   QR_stop_movement(res);
+   res->move_offset = 0;
    switch (fFetchType)
    {
        case SQL_FETCH_NEXT:
@@ -1234,30 +1420,30 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
             */
 
            progress_size = (save_rowset_size > 0 ? save_rowset_size : rowsetSize);
-           if (stmt->rowset_start < 0)
-               stmt->rowset_start = 0;
-
-#ifdef DRIVER_CURSOR_IMPLEMENT
+           if (rowset_start < 0)
+               SC_set_rowset_start(stmt, 0, TRUE);
            else if (res->keyset)
            {
                if (stmt->last_fetch_count <= progress_size)
                {
-                   stmt->rowset_start += stmt->last_fetch_count_include_ommitted;
+                   SC_inc_rowset_start(stmt, stmt->last_fetch_count_include_ommitted);
                    progress_size -= stmt->last_fetch_count;
                }
-               if (progress_size > 0 &&
-                   getNthValid(res, stmt->rowset_start,
-                   SQL_FETCH_NEXT, progress_size + 1,
-                   &stmt->rowset_start) <= 0)
+               if (progress_size > 0)
                {
-                   EXTFETCH_RETURN_EOF(stmt, res)
+                   if (getNthValid(res, SC_get_rowset_start(stmt),
+                       SQL_FETCH_NEXT, progress_size + 1,
+                       &rowset_start) <= 0)
+                   {
+                       EXTFETCH_RETURN_EOF(stmt, res)
+                   }
+                   else
+                       should_set_rowset_start =TRUE;
                }
            }
-#endif /* DRIVER_CURSOR_IMPLEMENT */
            else
-               stmt->rowset_start += progress_size;
-
-           mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
+               SC_inc_rowset_start(stmt, progress_size);
+           mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d, rowst=%d\n", num_tuples, stmt->currTuple, rowset_start);
            break;
 
        case SQL_FETCH_PRIOR:
@@ -1268,53 +1454,56 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
             * RESULT SET, then this should be equivalent to
             * SQL_FETCH_LAST.
             */
-           if (stmt->rowset_start <= 0)
+           if (SC_get_rowset_start(stmt) <= 0)
            {
                EXTFETCH_RETURN_BOF(stmt, res)
            }
-           if (stmt->rowset_start >= num_tuples)
+           if (SC_get_rowset_start(stmt) >= num_tuples)
            {
                if (rowsetSize > num_tuples)
                {
-                   SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beggining");
+                   SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beginning", func);
                }
-               stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - rowsetSize);
-
+               SC_set_rowset_start(stmt, num_tuples <= 0 ? 0 : (num_tuples - rowsetSize), TRUE);
            }
-           else
+           else if (QR_haskeyset(res))
            {
-#ifdef DRIVER_CURSOR_IMPLEMENT
-               if (i = getNthValid(res, stmt->rowset_start - 1, SQL_FETCH_PRIOR, rowsetSize, &stmt->rowset_start), i < -1)
+               if (i = getNthValid(res, SC_get_rowset_start(stmt) - 1, SQL_FETCH_PRIOR, rowsetSize, &rowset_start), i < -1)
                {
-                   SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior and before the beggining");
-                   stmt->rowset_start = 0;
+                   SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior and before the beggining", func);
+                   SC_set_rowset_start(stmt, 0, TRUE);
                }
                else if (i <= 0)
                {
                    EXTFETCH_RETURN_BOF(stmt, res)
                }
-#else
-               if (stmt->rowset_start < opts->size_of_rowset)
-               {
-                   SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior and before the beggining");
-                   stmt->rowset_start = 0;
-               }
                else
-                   stmt->rowset_start -= opts->size_of_rowset;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
+                   should_set_rowset_start = TRUE;
+           }
+           else if (SC_get_rowset_start(stmt) < rowsetSize)
+           {
+               SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beggining", func);
+               SC_set_rowset_start(stmt, 0, TRUE);
            }
+           else
+               SC_inc_rowset_start(stmt, -rowsetSize);
            break;
 
        case SQL_FETCH_FIRST:
            mylog("SQL_FETCH_FIRST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
 
-           stmt->rowset_start = 0;
+           SC_set_rowset_start(stmt, 0, TRUE);
            break;
 
        case SQL_FETCH_LAST:
            mylog("SQL_FETCH_LAST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
 
-           stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - rowsetSize);
+           if (!reached_eof)
+           {
+               QR_set_move_from_the_last(res);
+               res->move_offset = rowsetSize;
+           }
+           SC_set_rowset_start(stmt, num_tuples <= 0 ? 0 : (num_tuples - rowsetSize), TRUE);
            break;
 
        case SQL_FETCH_ABSOLUTE:
@@ -1327,28 +1516,31 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
            }
            /* Position before the desired row */
            else if (irow > 0)
-#ifdef DRIVER_CURSOR_IMPLEMENT
            {
-               if (getNthValid(res, 0, SQL_FETCH_NEXT, irow, &stmt->rowset_start) <= 0)
+               if (getNthValid(res, 0, SQL_FETCH_NEXT, irow, &rowset_start) <= 0)
                {
                    EXTFETCH_RETURN_EOF(stmt, res)
                }
+               else
+                   should_set_rowset_start = TRUE;
            }
-#else
-               stmt->rowset_start = irow - 1;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
            /* Position with respect to the end of the result set */
            else
-#ifdef DRIVER_CURSOR_IMPLEMENT
            {
-               if (getNthValid(res, num_tuples - 1, SQL_FETCH_PRIOR, -irow, &stmt->rowset_start) <= 0)
+               if (getNthValid(res, num_tuples - 1, SQL_FETCH_PRIOR, -irow, &rowset_start) <= 0)
                {
                    EXTFETCH_RETURN_BOF(stmt, res)
                }
+               else
+               {
+                   if (!reached_eof)
+                   {
+                       QR_set_move_from_the_last(res);
+                       res->move_offset = -irow;
+                   }
+                   should_set_rowset_start = TRUE;
+               }
            }
-#else
-               stmt->rowset_start = num_tuples + irow;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
            break;
 
        case SQL_FETCH_RELATIVE:
@@ -1360,48 +1552,62 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
            if (irow == 0)
                break;
 
-#ifdef DRIVER_CURSOR_IMPLEMENT
            if (irow > 0)
            {
-               if (getNthValid(res, stmt->rowset_start + 1, SQL_FETCH_NEXT, irow, &stmt->rowset_start) <= 0)
+               if (getNthValid(res, SC_get_rowset_start(stmt) + 1, SQL_FETCH_NEXT, irow, &rowset_start) <= 0)
                {
                    EXTFETCH_RETURN_EOF(stmt, res)
                }
+               else
+                   should_set_rowset_start = TRUE;
            }
            else
            {
-               if (getNthValid(res, stmt->rowset_start - 1, SQL_FETCH_PRIOR, -irow, &stmt->rowset_start) <= 0)
+               if (getNthValid(res, SC_get_rowset_start(stmt) - 1, SQL_FETCH_PRIOR, -irow, &rowset_start) <= 0)
                {
                    EXTFETCH_RETURN_BOF(stmt, res)
                }
+               else
+                   should_set_rowset_start = TRUE;
            }
-#else
-           stmt->rowset_start += irow;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
            break;
 
        case SQL_FETCH_BOOKMARK:
-#ifdef DRIVER_CURSOR_IMPLEMENT
-           if (bookmark_offset > 0)
            {
-               if (getNthValid(res, irow - 1, SQL_FETCH_NEXT, bookmark_offset + 1, &stmt->rowset_start) <= 0)
+           Int4    bidx = SC_resolve_bookmark(irow);
+
+           if (bidx < 0)
+           {
+               if (!reached_eof)
+               {
+                   QR_set_move_from_the_last(res);
+                   res->move_offset = 1 + res->ad_count + bidx;
+               }
+               bidx = num_tuples - 1 - res->ad_count - bidx;
+           } 
+
+           rowset_start = bidx;
+           if (bookmark_offset >= 0)
+           {
+               if (getNthValid(res, bidx, SQL_FETCH_NEXT, bookmark_offset + 1, &rowset_start) <= 0)
                {
                    EXTFETCH_RETURN_EOF(stmt, res)
                }
+               else
+                   should_set_rowset_start = TRUE;
            }
-           else if (getNthValid(res, irow - 1, SQL_FETCH_PRIOR, 1 - bookmark_offset, &stmt->rowset_start) <= 0)
+           else if (getNthValid(res, bidx, SQL_FETCH_PRIOR, 1 - bookmark_offset, &rowset_start) <= 0)
            {
                stmt->currTuple = -1;
                EXTFETCH_RETURN_BOF(stmt, res)
            }
-#else
-           stmt->rowset_start = irow + bookmark_offset - 1;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
+           else
+               should_set_rowset_start = TRUE;
+           }
            break;
 
        default:
-           SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "Unsupported PGAPI_ExtendedFetch Direction");
-           SC_log_error(func, "Unsupported PGAPI_ExtendedFetch Direction", stmt);
+           SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "Unsupported PGAPI_ExtendedFetch Direction", func);
            return SQL_ERROR;
    }
 
@@ -1413,84 +1619,124 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
     * Handle Declare Fetch style specially because the end is not really
     * the end...
     */
-   if (SC_is_fetchcursor(stmt) )
+   if (!should_set_rowset_start)
+       rowset_start = SC_get_rowset_start(stmt);
+   if (SC_is_fetchcursor(stmt))
    {
-       if(!stmt->manual_result)
+       if (reached_eof &&
+           rowset_start >= num_tuples)
        {
-           return SQL_NO_DATA_FOUND;
+           EXTFETCH_RETURN_EOF(stmt, res)
        }
    }
    else
    {
        /* If *new* rowset is after the result_set, return no data found */
-       if (stmt->rowset_start >= num_tuples)
+       if (rowset_start >= num_tuples)
        {
            EXTFETCH_RETURN_EOF(stmt, res)
        }
    }
-
    /* If *new* rowset is prior to result_set, return no data found */
-   if (stmt->rowset_start < 0)
+   if (rowset_start < 0)
    {
-       if (stmt->rowset_start + rowsetSize <= 0)
+       if (rowset_start + rowsetSize <= 0)
        {
            EXTFETCH_RETURN_BOF(stmt, res)
        }
        else
-       {                       /* overlap with beginning of result set,
-                                * so get first rowset */
-           stmt->rowset_start = 0;
+       {   /* overlap with beginning of result set,
+            * so get first rowset */
+           SC_set_rowset_start(stmt, 0, TRUE);
        }
+       should_set_rowset_start = FALSE;
    }
 
-   /* currTuple is always 1 row prior to the rowset */
-   stmt->currTuple = RowIdx2GIdx(-1, stmt);
-
+#define    return DONT_CALL_RETURN_FROM_HERE???
    /* increment the base row in the tuple cache */
    QR_set_rowset_size(res, rowsetSize);
+   /* set the rowset_start if needed */
+   if (should_set_rowset_start)
+       SC_set_rowset_start(stmt, rowset_start, TRUE);
+   /* currTuple is always 1 row prior to the rowset start */
+   stmt->currTuple = RowIdx2GIdx(-1, stmt);
+
    if (SC_is_fetchcursor(stmt) ||
        SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
-       QR_inc_base(res, stmt->last_fetch_count_include_ommitted);
+   {
+       move_cursor_position_if_needed(stmt, res);
+   }
    else
-       res->base = stmt->rowset_start;
+       QR_set_rowstart_in_cache(res, SC_get_rowset_start(stmt));
 
-#ifdef DRIVER_CURSOR_IMPLEMENT
-   if (res->keyset)
+   if (res->keyset && !QR_get_cursor(res))
    {
        UDWORD  flag = 0;
+       Int4    rowset_end, req_size;
 
-       if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
-           SQL_RD_ON == stmt->options.retrieve_data)
+       getNthValid(res, rowset_start, SQL_FETCH_NEXT, rowsetSize, &rowset_end);
+       req_size = rowset_end - rowset_start + 1;
+       if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
        {
            if (fFetchType != SQL_FETCH_NEXT ||
-               res->base + rowsetSize > QR_get_num_backend_tuples(res))
+                   QR_get_rowstart_in_cache(res) + req_size > (Int4)QR_get_num_cached_tuples(res))
                flag = 1;
        }
-       SC_pos_reload_needed(stmt, flag);
+       if (SQL_RD_ON == stmt->options.retrieve_data ||
+           flag != 0)
+       {
+           SC_pos_reload_needed(stmt, req_size, flag);
+       }
    }
-#endif /* DRIVER_CURSOR_IMPLEMENT */
    /* Physical Row advancement occurs for each row fetched below */
 
    mylog("PGAPI_ExtendedFetch: new currTuple = %d\n", stmt->currTuple);
 
    truncated = error = FALSE;
-   for (i = 0, currp = stmt->rowset_start; i < rowsetSize; currp++)
+
+   currp = -1;
+   stmt->bind_row = 0;     /* set the binding location */
+   result = SC_fetch(stmt);
+   if (SQL_NO_DATA_FOUND != result && res->keyset)
    {
-       stmt->bind_row = i;     /* set the binding location */
-       result = SC_fetch(stmt);
-       res = SC_get_Curres(stmt);
-#ifdef DRIVER_CURSOR_IMPLEMENT
-       if (SQL_SUCCESS_WITH_INFO == result && 0 == stmt->last_fetch_count && res->keyset)
+       currp = GIdx2KResIdx(SC_get_rowset_start(stmt), stmt, res);
+inolog("currp=%d\n", currp);
+       if (currp < 0)
+       {
+           result = SQL_ERROR;
+           mylog("rowset_start=%d but currp=%d\n", SC_get_rowset_start(stmt), currp);
+           SC_set_error(stmt, STMT_INTERNAL_ERROR, "rowset_start not in the keyset", func);
+           goto cleanup;
+       }
+   }
+   for (i = 0, fc_io = 0; SQL_NO_DATA_FOUND != result; currp++)
+   {
+       fc_io++;
+       currp_is_valid = FALSE;
+       if (res->keyset)
+       {
+           if (currp < (Int4)res->num_cached_keys)
+           {
+               currp_is_valid = TRUE;
+               res->keyset[currp].status &= ~CURS_IN_ROWSET; /* Off the flag first */
+           }
+           else
+           {
+               mylog("Umm current row is out of keyset\n");
+               break;
+           }
+       }
+inolog("ExtFetch result=%d\n", result);
+       if (currp_is_valid && SQL_SUCCESS_WITH_INFO == result && 0 == stmt->last_fetch_count)
        {
-           res->keyset[stmt->currTuple].status &= ~CURS_IN_ROWSET;
+inolog("just skipping deleted row %d\n", currp);
+           QR_set_rowset_size(res, rowsetSize - i + fc_io);
+           result = SC_fetch(stmt);
            continue;
        }
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
 
        /* Determine Function status */
-       if (result == SQL_NO_DATA_FOUND)
-           break;
-       else if (result == SQL_SUCCESS_WITH_INFO)
+       if (result == SQL_SUCCESS_WITH_INFO)
            truncated = TRUE;
        else if (result == SQL_ERROR)
            error = TRUE;
@@ -1500,8 +1746,7 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
        {
            if (result == SQL_ERROR)
                *(rgfRowStatus + i) = SQL_ROW_ERROR;
-#ifdef DRIVER_CURSOR_IMPLEMENT
-           else if (res->keyset)
+           else if (currp_is_valid)
            {
                pstatus = (res->keyset[currp].status & KEYSET_INFO_PUBLIC);
                if (pstatus != 0 && pstatus != SQL_ROW_ADDED)
@@ -1514,20 +1759,25 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
                /* if (SQL_ROW_DELETED != pstatus) */
                res->keyset[currp].status &= (~KEYSET_INFO_PUBLIC);
            }
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
            else
                *(rgfRowStatus + i) = SQL_ROW_SUCCESS;
        }
-#ifdef DRIVER_CURSOR_IMPLEMENT
-       if (SQL_ERROR != result && res->keyset)
-           res->keyset[currp].status |= CURS_IN_ROWSET;
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
+       if (SQL_ERROR != result && currp_is_valid)
+           res->keyset[currp].status |= CURS_IN_ROWSET; /* This is the unique place where the CURS_IN_ROWSET bit is turned on */
        i++;
+       if (i >= rowsetSize)
+           break;
+       stmt->bind_row = i;     /* set the binding location */
+       result = SC_fetch(stmt);
    }
 
    /* Save the fetch count for SQLSetPos */
    stmt->last_fetch_count = i;
+   /*
+   currp = KResIdx2GIdx(currp, stmt, res);
    stmt->last_fetch_count_include_ommitted = GIdx2RowIdx(currp, stmt);
+   */
+   stmt->last_fetch_count_include_ommitted = fc_io;
 
    /* Reset next binding row */
    stmt->bind_row = 0;
@@ -1536,24 +1786,31 @@ PGAPI_ExtendedFetch(HSTMT hstmt,
    stmt->currTuple = RowIdx2GIdx(0, stmt);
 
    /* For declare/fetch, need to reset cursor to beginning of rowset */
-   if (SC_is_fetchcursor(stmt) && !stmt->manual_result)
+   if (SC_is_fetchcursor(stmt))
        QR_set_position(res, 0);
 
    /* Set the number of rows retrieved */
    if (pcrow)
        *pcrow = i;
+inolog("pcrow=%d\n", i);
 
    if (i == 0)
        /* Only DeclareFetch should wind up here */
-       return SQL_NO_DATA_FOUND;
+       result = SQL_NO_DATA_FOUND;
    else if (error)
-       return SQL_ERROR;
+       result = SQL_ERROR;
    else if (truncated)
-       return SQL_SUCCESS_WITH_INFO;
+       result = SQL_SUCCESS_WITH_INFO;
    else if (SC_get_errornumber(stmt) == STMT_POS_BEFORE_RECORDSET)
-       return SQL_SUCCESS_WITH_INFO;
+       result = SQL_SUCCESS_WITH_INFO;
    else
-       return SQL_SUCCESS;
+       result = SQL_SUCCESS;
+
+cleanup:
+#undef return
+   if (stmt->internal)
+       result = DiscardStatementSvp(stmt, result, FALSE);
+   return result;
 }
 
 
@@ -1569,6 +1826,7 @@ PGAPI_MoreResults(
    CSTR func = "PGAPI_MoreResults";
    StatementClass  *stmt = (StatementClass *) hstmt;
    QResultClass    *res;
+   RETCODE     ret = SQL_SUCCESS;
 
    mylog("%s: entering...\n", func);
    if (stmt && (res = SC_get_Curres(stmt)))
@@ -1576,15 +1834,16 @@ PGAPI_MoreResults(
    if (res = SC_get_Curres(stmt), res)
    {
        stmt->diag_row_count = res->recent_processed_row_count;
-       stmt->rowset_start = -1;
+       SC_set_rowset_start(stmt, -1, FALSE);
        stmt->currTuple = -1;
-       return SQL_SUCCESS;
-   } 
-   return SQL_NO_DATA_FOUND;
+   }
+   else
+       ret = SQL_NO_DATA_FOUND;
+   mylog("%s: returning %d\n", func, ret);
+   return ret;
 }
 
 
-#ifdef DRIVER_CURSOR_IMPLEMENT
 /*
  * Stuff for updatable cursors.
  */
@@ -1602,18 +1861,24 @@ static void getTid(const QResultClass *res, int index, UInt4 *blocknum, UInt2 *o
    *blocknum = res->keyset[index].blocknum;
    *offset = res->keyset[index].offset;
 }
-static void KeySetSet(const TupleField *tuple, int num_fields, KeySet *keyset)
+static void KeySetSet(const TupleField *tuple, int num_fields, int num_key_fields, KeySet *keyset)
 {
-   sscanf(tuple[num_fields - 2].value, "(%u,%hu)",
-          (unsigned int *) &keyset->blocknum, &keyset->offset);
-   sscanf(tuple[num_fields - 1].value, "%u", (unsigned int *) &keyset->oid);
+   sscanf(tuple[num_fields - num_key_fields].value, "(%u,%hu)",
+           &keyset->blocknum, &keyset->offset);
+   if (num_key_fields > 1)
+       sscanf(tuple[num_fields - 1].value, "%u", &keyset->oid);
+   else
+       keyset->oid = 0;
 }
 
-static void DiscardDeleted(QResultClass *res, int index);
-static void AddRollback(ConnectionClass *conn, QResultClass *res, int index, const KeySet *keyset)
+static void AddRollback(StatementClass *stmt, QResultClass *res, int index, const KeySet *keyset, Int4 dmlcode)
 {
+   ConnectionClass *conn = SC_get_conn(stmt);
    Rollback *rollback;
 
+   if (!CC_is_in_trans(conn))
+       return;
+inolog("AddRollback %d(%d,%d) %s\n", index, keyset->blocknum, keyset->offset, dmlcode == SQL_ADD ? "ADD" : (dmlcode == SQL_UPDATE ? "UPDATE" : (dmlcode == SQL_DELETE ? "DELETE" : "REFRESH")));
    if (!res->rollback)
    {
        res->rb_count = 0;
@@ -1635,91 +1900,765 @@ static void AddRollback(ConnectionClass *conn, QResultClass *res, int index, con
        rollback = res->rollback + res->rb_count;
    }
    rollback->index = index;
+   rollback->option = dmlcode;
+   rollback->offset = 0;
+   rollback->blocknum = 0;
    if (keyset)
    {
-       rollback->blocknum = keyset[index].blocknum;
-       rollback->offset = keyset[index].offset;
-   }
-   else
-   {
-       rollback->offset = 0;
-       rollback->blocknum = 0;
+       rollback->blocknum = keyset->blocknum;
+       rollback->offset = keyset->offset;
    }
 
    conn->result_uncommitted = 1;
    res->rb_count++;    
 }
 
-static void DiscardRollback(QResultClass *res)
+int ClearCachedRows(TupleField *tuple, int num_fields, int num_rows)
 {
-   int i, index;
-   UWORD   status;
-   Rollback *rollback;
-   KeySet  *keyset;
+   int i;
 
-   if (0 == res->rb_count || NULL == res->rollback)
-       return;
-   rollback = res->rollback;
-   keyset = res->keyset;
-   for (i = 0; i < res->rb_count; i++)
+   for (i = 0; i < num_fields * num_rows; i++, tuple++)
    {
-       index = rollback[i].index;
-       status = keyset[index].status;
-       if (0 != (status & CURS_SELF_DELETING))
-           DiscardDeleted(res, index);
-       keyset[index].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING);
-       keyset[index].status |= ((status & (CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING)) << 3);
+       if (tuple->value)
+       {
+inolog("freeing tuple[%d][%d].value=%x\n", i / num_fields, i % num_fields, tuple->value);
+           free(tuple->value);
+           tuple->value = NULL;
+       }
+       tuple->len = -1;
    }
-   free(rollback);
-   res->rollback = NULL;
-   res->rb_count = res->rb_alloc = 0;
+   return i;
+}
+int ReplaceCachedRows(TupleField *otuple, const TupleField *ituple, int num_fields, int num_rows)
+{
+   int i;
+
+inolog("ReplaceCachedRows %x num_fields=%d num_rows=%d\n", otuple, num_fields, num_rows);
+   for (i = 0; i < num_fields * num_rows; i++, ituple++, otuple++)
+   {
+       if (otuple->value)
+       {
+           free(otuple->value);
+           otuple->value = NULL;
+       }
+       if (ituple->value)
+{
+           otuple->value = strdup(ituple->value);
+inolog("[%d,%d] %s copied\n", i / num_fields, i % num_fields, otuple->value);
+}
+       otuple->len = ituple->len;
+   }
+   return i;
+}
+
+int MoveCachedRows(TupleField *otuple, TupleField *ituple, Int4 num_fields, int num_rows)
+{
+   int i;
+
+inolog("MoveCachedRows %x num_fields=%d num_rows=%d\n", otuple, num_fields, num_rows);
+   for (i = 0; i < num_fields * num_rows; i++, ituple++, otuple++)
+   {
+       if (otuple->value)
+       {
+           free(otuple->value);
+           otuple->value = NULL;
+       }
+       if (ituple->value)
+       {
+           otuple->value = ituple->value;
+           ituple->value = NULL;
+inolog("[%d,%d] %s copied\n", i / num_fields, i % num_fields, otuple->value);
+       }
+       otuple->len = ituple->len;
+       ituple->len = -1;
+   }
+   return i;
+}
+
+static BOOL    tupleExists(const StatementClass *stmt, const KeySet *keyset)
+{
+   char    selstr[256];
+   const TABLE_INFO    *ti = stmt->ti[0];
+   QResultClass    *res;
+   RETCODE     ret = FALSE;
+
+   if (NAME_IS_VALID(ti->schema_name))
+       snprintf(selstr, sizeof(selstr), "select 1 from \"%s\".\"%s\" where ctid = '(%d,%d)'",
+           SAFE_NAME(ti->schema_name), SAFE_NAME(ti->table_name), keyset->blocknum, keyset->offset);
+   else
+       snprintf(selstr, sizeof(selstr), "select 1 from \"%s\" where ctid = '(%d,%d)'",
+           SAFE_NAME(ti->table_name), keyset->blocknum, keyset->offset);
+   res = CC_send_query(SC_get_conn(stmt), selstr, NULL, 0, NULL);
+   if (QR_command_maybe_successful(res) && 1 == res->num_cached_rows)
+       ret = TRUE;
+   QR_Destructor(res);
+   return ret;
+}
+static BOOL    tupleIsAdding(const StatementClass *stmt, const QResultClass *res, Int4 index)
+{
+   int i;
+   BOOL    ret = FALSE;
+   UWORD   status;
+
+   if (!res->added_keyset)
+       return ret;
+   if (index < (Int4)res->num_total_read || index >= (Int4)QR_get_num_total_read(res))
+       return ret;
+   i = index - res->num_total_read; 
+   status = res->added_keyset[i].status;
+   if (0 == (status & CURS_SELF_ADDING))
+       return ret;
+   if (tupleExists(stmt, res->added_keyset + i))
+       ret = TRUE;
+
+   return ret;
+}
+
+static BOOL    tupleIsUpdating(const StatementClass *stmt, const QResultClass *res, Int4 index)
+{
+   int i;
+   BOOL    ret = FALSE;
+   UWORD   status;
+
+   if (!res->updated || !res->updated_keyset)
+       return ret;
+   for (i = res->up_count - 1; i >= 0; i--)
+   {
+       if (index == res->updated[i])
+       {
+           status = res->updated_keyset[i].status;
+           if (0 == (status & CURS_SELF_UPDATING))
+               continue;
+           if (tupleExists(stmt, res->updated_keyset + i))
+           {
+               ret = TRUE;
+               break;
+           }
+       } 
+   }
+   return ret;
+}
+static BOOL    tupleIsDeleting(const StatementClass *stmt, const QResultClass *res, Int4 index)
+{
+   int i;
+   BOOL    ret = FALSE;
+   UWORD   status;
+
+   if (!res->deleted || !res->deleted_keyset)
+       return ret;
+   for (i = 0; i < res->dl_count; i++)
+   {
+       if (index == res->deleted[i])
+       {
+           status = res->deleted_keyset[i].status;
+           if (0 == (status & CURS_SELF_DELETING))
+               ;
+           else if (tupleExists(stmt, res->deleted_keyset + i))
+               ;
+           else
+               ret = TRUE;
+           break;
+       } 
+   }
+   return ret;
+}
+
+
+static BOOL enlargeAdded(QResultClass *res, UInt4 number, const StatementClass *stmt)
+{
+   UInt4   alloc;
+   KeySet  *added_keyset;
+   TupleField  *added_tuples;
+   int num_fields = res->num_fields;
+
+   alloc = res->ad_alloc;
+   if (0 == alloc)
+       alloc = number > 10 ? number : 10;
+   else
+       while (alloc < number)
+       {
+           alloc *= 2;
+       }
+   if (alloc <= res->ad_alloc)
+       return TRUE;
+   if (added_keyset = realloc(res->added_keyset, sizeof(KeySet) * alloc), !added_keyset)
+   {
+       res->ad_alloc = 0;
+       return FALSE;
+   }
+   added_tuples = res->added_tuples;
+   if (SQL_CURSOR_KEYSET_DRIVEN != stmt->options.cursor_type)
+       if (added_tuples = realloc(res->added_tuples, sizeof(TupleField) * num_fields * alloc), !added_tuples)
+       {
+           if (added_keyset)
+               free(added_keyset);
+           added_keyset = NULL;
+       }
+   res->added_keyset = added_keyset; 
+   res->added_tuples = added_tuples;
+   if (!added_keyset)
+   {
+       res->ad_alloc = 0;
+       return FALSE;
+   }
+   res->ad_alloc = alloc;
+   return TRUE;
+}
+static void AddAdded(StatementClass *stmt, QResultClass *res, int index, const TupleField *tuple_added)
+{
+   KeySet  *added_keyset, *keyset, keys;
+   TupleField  *added_tuples = NULL, *tuple;
+   UInt4   ad_count;
+   int num_fields;
+
+   if (!res)   return;
+   num_fields = res->num_fields;
+inolog("AddAdded index=%d, tuple=%x, num_fields=%d\n", index, tuple_added, num_fields);
+   ad_count = res->ad_count;
+   res->ad_count++;
+   if (QR_get_cursor(res))
+       index = -(Int4)res->ad_count;
+   if (!tuple_added)
+       return;
+   KeySetSet(tuple_added, num_fields + res->num_key_fields, res->num_key_fields, &keys);
+   keys.status = SQL_ROW_ADDED;
+   if (CC_is_in_trans(SC_get_conn(stmt)))
+       keys.status |= CURS_SELF_ADDING;
+   else
+       keys.status |= CURS_SELF_ADDED;
+   AddRollback(stmt, res, index, &keys, SQL_ADD);
+
+   if (!QR_get_cursor(res))
+       return;
+   if (ad_count > 0 && 0 == res->ad_alloc)
+       return;
+   if (!enlargeAdded(res, ad_count + 1, stmt))
+       return;
+   added_keyset = res->added_keyset; 
+   added_tuples = res->added_tuples;
+
+   keyset = added_keyset + ad_count;
+   *keyset = keys; 
+   if (added_tuples)
+   {
+       tuple = added_tuples + num_fields * ad_count;
+       memset(tuple, 0, sizeof(TupleField) * num_fields);
+       ReplaceCachedRows(tuple, tuple_added, num_fields, 1);
+   }
+}
+
+static void RemoveAdded(QResultClass *, Int4);
+static void RemoveUpdated(QResultClass *, Int4);
+static void RemoveUpdatedAfterTheKey(QResultClass *, Int4, const KeySet*);
+static void RemoveDeleted(QResultClass *, Int4);
+static void RemoveAdded(QResultClass *res, Int4 index)
+{
+   Int4    rmidx, num_fields = res->num_fields, mv_count;
+   KeySet  *added_keyset;
+   TupleField  *added_tuples;
+
+   mylog("RemoveAdded index=%d\n", index);
+   if (index < 0)
+       rmidx = -index - 1;
+   else
+       rmidx = index - res->num_total_read;
+   if (rmidx >= (Int4)res->ad_count)
+       return;
+   added_keyset = res->added_keyset + rmidx;
+   added_tuples = res->added_tuples + num_fields * rmidx;
+   ClearCachedRows(added_tuples, num_fields, 1);
+   mv_count = res->ad_count - rmidx - 1;
+   if (mv_count > 0)
+   {
+       memmove(added_keyset, added_keyset + 1, mv_count * sizeof(KeySet));
+       memmove(added_tuples, added_tuples + num_fields, mv_count * num_fields * sizeof(TupleField));
+   }
+   RemoveDeleted(res, index);
+   RemoveUpdated(res, index);
+   res->ad_count--;
+   mylog("RemoveAdded removed=1 count=%d\n", res->ad_count);
+}
+
+static void CommitAdded(QResultClass *res)
+{
+   KeySet  *added_keyset;
+   int i;
+   UWORD   status;
+
+   mylog("CommitAdded res=%x\n", res);
+   if (!res || !res->added_keyset) return;
+   added_keyset = res->added_keyset;
+   for (i = res->ad_count - 1; i >= 0; i--)
+   {
+       status = added_keyset[i].status;
+       if (0 != (status & CURS_SELF_ADDING))
+       {
+           status |= CURS_SELF_ADDED;
+           status &= ~CURS_SELF_ADDING;
+       }
+       if (0 != (status & CURS_SELF_UPDATING))
+       {
+           status |= CURS_SELF_UPDATED;
+           status &= ~CURS_SELF_UPDATING;
+       }
+       if (0 != (status & CURS_SELF_DELETING))
+       {
+           status |= CURS_SELF_DELETED;
+           status &= ~CURS_SELF_DELETING;
+       }
+       if (status != added_keyset[i].status)
+       {
+inolog("!!Commit Added=%d(%d)\n", QR_get_num_total_read(res) + i, i);
+           added_keyset[i].status = status;
+       }
+   }
+}
+
+
+int AddDeleted(QResultClass *res, UInt4 index, KeySet *keyset)
+{
+   int i;
+   Int4    dl_count;
+   UInt4   new_alloc;
+   UInt4   *deleted;
+   KeySet  *deleted_keyset;
+   UWORD   status;
+   Int4    num_fields = res->num_fields;
+
+inolog("AddDeleted %d\n", index);
+   if (!res)   return FALSE;
+   dl_count = res->dl_count;
+   res->dl_count++;
+   if (!QR_get_cursor(res))
+       return TRUE;
+   if (!res->deleted)
+   {
+       dl_count = 0;
+       new_alloc = 10;
+       QR_MALLOC_return_with_error(res->deleted, UInt4, sizeof(UInt4) * new_alloc, res, "Deleted index malloc error", FALSE);
+       QR_MALLOC_return_with_error(res->deleted_keyset, KeySet, sizeof(KeySet) * new_alloc, res, "Deleted keyset malloc error", FALSE);
+       deleted = res->deleted;
+       deleted_keyset = res->deleted_keyset;
+       res->dl_alloc = new_alloc;
+   }
+   else
+   {
+       if (dl_count >= res->dl_alloc)
+       {
+           new_alloc = res->dl_alloc * 2;
+           res->dl_alloc = 0;
+           QR_REALLOC_return_with_error(res->deleted, UInt4, sizeof(UInt4) * new_alloc, res, "Dleted index realloc error", FALSE);
+           deleted = res->deleted;
+           QR_REALLOC_return_with_error(res->deleted_keyset, KeySet, sizeof(KeySet) * new_alloc, res, "Dleted KeySet realloc error", FALSE);
+           deleted_keyset = res->deleted_keyset;
+           res->dl_alloc = new_alloc; 
+       }
+       /* sort deleted indexes in ascending order */
+       for (i = 0, deleted = res->deleted, deleted_keyset = res->deleted_keyset; i < dl_count; i++, deleted++, deleted_keyset += num_fields)
+       {
+           if (index < *deleted)
+               break;
+       }
+       memmove(deleted + 1, deleted, sizeof(UInt4) * (dl_count - i)); 
+       memmove(deleted_keyset + 1, deleted_keyset, sizeof(KeySet) * (dl_count - i)); 
+   }
+   *deleted = index;
+   *deleted_keyset = *keyset;
+   status = keyset->status;
+   status &= (~KEYSET_INFO_PUBLIC);
+   status |= SQL_ROW_DELETED;
+   if (CC_is_in_trans(QR_get_conn(res)))
+   {
+       status |= CURS_SELF_DELETING;
+       QR_get_conn(res)->result_uncommitted = 1;
+   }
+   else
+   {
+       status &= ~(CURS_SELF_ADDING | CURS_SELF_UPDATING | CURS_SELF_DELETING);
+       status |= CURS_SELF_DELETED;
+   }
+   deleted_keyset->status = status;
+   res->dl_count = dl_count + 1;
+
+   return TRUE;
+}
+
+static void RemoveDeleted(QResultClass *res, Int4 index)
+{
+   int i, mv_count, rm_count = 0;
+   Int4    pidx, midx;
+   UInt4   *deleted, num_read = QR_get_num_total_read(res);
+   KeySet  *deleted_keyset;
+
+   mylog("RemoveDeleted index=%d\n", index);
+   if (index < 0)
+   {
+       midx = index;
+       pidx = num_read - index - 1;
+   }
+   else
+   {
+       pidx = index;
+       if (index >= (Int4) num_read)
+           midx = num_read - index - 1;
+       else
+           midx = index;
+   }
+   for (i = 0; i < res->dl_count; i++)
+   {
+       if (pidx == res->deleted[i] ||
+           midx == res->deleted[i])
+       {
+           mv_count = res->dl_count - i - 1;
+           if (mv_count > 0)
+           {
+               deleted = res->deleted + i;
+               deleted_keyset = res->deleted_keyset + i;
+               memmove(deleted, deleted + 1, mv_count * sizeof(UInt4));
+               memmove(deleted_keyset, deleted_keyset + 1, mv_count * sizeof(KeySet));
+           }
+           res->dl_count--;
+           rm_count++;     
+       }
+   }
+   mylog("RemoveDeleted removed count=%d,%d\n", rm_count, res->dl_count);
+}
+
+static void CommitDeleted(QResultClass *res)
+{
+   int i;
+   UInt4   *deleted;
+   KeySet  *deleted_keyset;
+   UWORD   status;
+
+   if (!res->deleted)
+       return;
+
+   for (i = 0, deleted = res->deleted, deleted_keyset = res->deleted_keyset; i < res->dl_count; i++, deleted++, deleted_keyset++)
+   {
+       status = deleted_keyset->status;
+       if (0 != (status & CURS_SELF_ADDING))
+       {
+           status |= CURS_SELF_ADDED;
+           status &= ~CURS_SELF_ADDING;
+       }
+       if (0 != (status & CURS_SELF_UPDATING))
+       {
+           status |= CURS_SELF_UPDATED;
+           status &= ~CURS_SELF_UPDATING;
+       }
+       if (0 != (status & CURS_SELF_DELETING))
+       {
+           status |= CURS_SELF_DELETED;
+           status &= ~CURS_SELF_DELETING;
+       }
+       if (status != deleted_keyset->status)
+       {
+inolog("!!Commit Deleted=%d(%d)\n", *deleted, i);
+           deleted_keyset->status = status;
+       }
+   } 
+}
+
+static BOOL enlargeUpdated(QResultClass *res, Int4 number, const StatementClass *stmt)
+{
+   Int4    alloc;
+   UInt4   *updated;
+   KeySet  *updated_keyset;
+   TupleField  *updated_tuples = NULL;
+
+   alloc = res->up_alloc;
+   if (0 == alloc)
+       alloc = number > 10 ? number : 10;
+   else
+       while (alloc < number)
+       {
+           alloc *= 2;
+       }
+   if (alloc <= res->up_alloc)
+       return TRUE;
+   if (updated = realloc(res->updated, sizeof(UInt4) * alloc), !updated)
+   {
+       if (res->updated_keyset)
+       {
+           free(res->updated_keyset);
+           res->updated_keyset = NULL;
+       }
+       res->up_alloc = 0;
+       return FALSE;
+   }
+   if (updated_keyset = realloc(res->updated_keyset, sizeof(KeySet) * alloc), !updated_keyset)
+   {
+       free(res->updated);
+       res->updated = NULL;
+       res->up_alloc = 0;
+       return FALSE;
+   }
+   if (SQL_CURSOR_KEYSET_DRIVEN != stmt->options.cursor_type)
+       if (updated_tuples = realloc(res->updated_tuples, sizeof(TupleField) * res->num_fields * alloc), !updated_tuples)
+       {
+           free(res->updated);
+           res->updated = NULL;
+           free(res->updated_keyset);
+           res->updated_keyset = NULL;
+           res->up_alloc = 0;
+           return FALSE;
+       }
+   res->updated = updated; 
+   res->updated_keyset = updated_keyset; 
+   res->updated_tuples = updated_tuples;
+   res->up_alloc = alloc;
+
+   return TRUE;
+}
+
+static void AddUpdated(StatementClass *stmt, int index)
+{
+   QResultClass    *res;
+   UInt4   *updated;
+   KeySet  *updated_keyset, *keyset;
+   TupleField  *updated_tuples = NULL, *tuple_updated,  *tuple;
+   UInt4   kres_ridx, up_count;
+   BOOL    is_in_trans;
+   int i, num_fields, upd_idx, upd_add_idx;
+   UWORD   status;
+
+inolog("AddUpdated index=%d\n", index);
+   if (!stmt)  return;
+   if (res = SC_get_Curres(stmt), !res)    return;
+   if (!res->keyset)       return;
+   kres_ridx = GIdx2KResIdx(index, stmt, res);
+   if (kres_ridx < 0 || kres_ridx >= res->num_cached_keys)
+       return;
+   keyset = res->keyset + kres_ridx;
+   if (0 != (keyset->status & CURS_SELF_ADDING))
+       AddRollback(stmt, res, index, res->keyset + kres_ridx, SQL_REFRESH);
+   if (!QR_get_cursor(res))    return;
+   up_count = res->up_count;
+   if (up_count > 0 && 0 == res->up_alloc) return;
+   num_fields = res->num_fields;
+   tuple_updated = res->backend_tuples + kres_ridx * num_fields;
+   if (!tuple_updated)
+       return;
+   upd_idx = -1;
+   upd_add_idx = -1;
+   updated = res->updated;
+   is_in_trans = CC_is_in_trans(SC_get_conn(stmt));
+   updated_keyset = res->updated_keyset;   
+   status = keyset->status;
+   status &= (~KEYSET_INFO_PUBLIC);
+   status |= SQL_ROW_UPDATED;
+   if (is_in_trans)
+       status |= CURS_SELF_UPDATING;
+   else
+   {
+       for (i = up_count - 1; i >= 0; i--)
+       {
+           if (updated[i] == index)
+               break;
+       }
+       if (i >= 0)
+           upd_idx = i;
+       else
+       {
+           Int4    num_totals = QR_get_num_total_tuples(res);
+           if (index >= num_totals)
+               upd_add_idx = num_totals - index;
+       }
+       status |= CURS_SELF_UPDATED;
+       status &= ~(CURS_SELF_ADDING | CURS_SELF_UPDATING | CURS_SELF_DELETING);
+   }
+
+   tuple = NULL;
+   /* update the corresponding add(updat)ed info */
+   if (upd_add_idx >= 0)
+   {
+       res->added_keyset[upd_add_idx].status = status;
+       if (res->added_tuples)
+       {
+           tuple = res->added_tuples + num_fields * upd_add_idx;
+           ClearCachedRows(tuple, num_fields, 1);
+       }
+   }
+   else if (upd_idx >= 0)
+   {
+       res->updated_keyset[upd_idx].status = status;
+       if (res->updated_tuples)
+       {
+           tuple = res->added_tuples + num_fields * upd_add_idx;
+           ClearCachedRows(tuple, num_fields, 1);
+       }
+   }
+   else
+   {
+       if (!enlargeUpdated(res, res->up_count + 1, stmt))
+           return;
+       updated = res->updated; 
+       updated_keyset = res->updated_keyset; 
+       updated_tuples = res->updated_tuples;
+       upd_idx = up_count;
+       updated[up_count] = index;
+       updated_keyset[up_count] = *keyset;
+       updated_keyset[up_count].status = status;
+       if (updated_tuples)
+       {
+           tuple = updated_tuples + num_fields * up_count;
+           memset(tuple, 0, sizeof(TupleField) * num_fields);
+       }
+       res->up_count++;
+   }
+
+   if (tuple)
+       ReplaceCachedRows(tuple, tuple_updated, num_fields, 1);
+   if (is_in_trans)
+       SC_get_conn(stmt)->result_uncommitted = 1;
+   mylog("up_count=%d\n", res->up_count);
 }
 
-static void UndoRollback(StatementClass *stmt, QResultClass *res)
+static void RemoveUpdated(QResultClass *res, Int4 index)
+{
+   mylog("RemoveUpdated index=%d\n", index);
+   RemoveUpdatedAfterTheKey(res, index, NULL);
+}
+
+static void RemoveUpdatedAfterTheKey(QResultClass *res, Int4 index, const KeySet *keyset)
+{
+   UInt4   *updated, num_read = QR_get_num_total_read(res);
+   KeySet  *updated_keyset;
+   TupleField  *updated_tuples = NULL;
+   Int4    pidx, midx, mv_count;
+   int i, num_fields = res->num_fields, rm_count = 0;
+
+   mylog("RemoveUpdatedAfterTheKey %d,(%d,%d)\n", index, keyset ? keyset->blocknum : 0, keyset ? keyset->offset : 0);
+   if (index < 0)
+   {
+       midx = index;
+       pidx = num_read - index - 1;
+   }
+   else
+   {
+       pidx = index;
+       if (index >= (Int4)num_read)
+           midx = num_read - index - 1;
+       else
+           midx = index;
+   }
+   for (i = 0; i < res->up_count; i++)
+   {
+       updated = res->updated + i;
+       if (pidx == *updated ||
+           midx == *updated)
+       {
+           updated_keyset = res->updated_keyset + i;
+           if (keyset &&
+               updated_keyset->blocknum == keyset->blocknum &&
+               updated_keyset->offset == keyset->offset)
+               break;
+           updated_tuples = NULL;
+           if (res->updated_tuples)
+           {
+               updated_tuples = res->updated_tuples + i * num_fields;
+               ClearCachedRows(updated_tuples, num_fields, 1);
+           }
+           mv_count = res->up_count - i -1;
+           if (mv_count > 0)
+           {
+               memmove(updated, updated + 1, sizeof(UInt4) * mv_count); 
+               memmove(updated_keyset, updated_keyset + 1, sizeof(KeySet) * mv_count); 
+               if (updated_tuples)
+                   memmove(updated_tuples, updated_tuples + num_fields, sizeof(TupleField) * num_fields * mv_count);
+           }
+           res->up_count--;
+           rm_count++;
+       }
+   }
+   mylog("RemoveUpdatedAfter removed count=%d,%d\n", rm_count, res->up_count);
+}
+
+static void CommitUpdated(QResultClass *res)
+{
+   KeySet  *updated_keyset;
+   TupleField  *updated_tuples = NULL;
+   int i, num_fields = res->num_fields;
+   UWORD   status;
+
+   mylog("CommitUpdated res=%x\n", res);
+   if (!res)   return;
+   if (!QR_get_cursor(res))
+       return;
+   if (res->up_count <= 0)
+       return;
+   if (updated_keyset = res->updated_keyset, !updated_keyset)
+       return;
+   for (i = res->up_count - 1; i >= 0; i--)
+   {
+       status = updated_keyset[i].status;
+       if (0 != (status & CURS_SELF_UPDATING))
+       {
+           status &= ~CURS_SELF_UPDATING;
+           status |= CURS_SELF_UPDATED;
+       }
+       if (0 != (status & CURS_SELF_ADDING))
+       {
+           status &= ~CURS_SELF_ADDING;
+           status |= CURS_SELF_ADDED;
+       }
+       if (0 != (status & CURS_SELF_DELETING))
+       {
+           status &= ~CURS_SELF_DELETING;
+           status |= CURS_SELF_DELETED;
+       }
+       if (status != updated_keyset[i].status)
+       {
+inolog("!!Commit Updated=%d(%d)\n", res->updated[i], i);
+           updated_keyset[i].status = status;
+       }
+   }
+}
+
+
+static void DiscardRollback(StatementClass *stmt, QResultClass *res)
 {
-   int i, index, ridx;
+   int i;
+   Int4    index, kres_ridx;
    UWORD   status;
    Rollback *rollback;
    KeySet  *keyset;
+   BOOL    kres_is_valid;
+
+inolog("DiscardRollback");
+   if (QR_get_cursor(res))
+   {
+       CommitAdded(res);
+       CommitUpdated(res);
+       CommitDeleted(res);
+       return;
+   }
 
    if (0 == res->rb_count || NULL == res->rollback)
        return;
    rollback = res->rollback;
    keyset = res->keyset;
-   for (i = res->rb_count - 1; i >= 0; i--)
+   for (i = 0; i < res->rb_count; i++)
    {
        index = rollback[i].index;
-       status = keyset[index].status;
-       if (0 != (status & CURS_SELF_ADDING))
+       status = 0;
+       kres_is_valid = FALSE;
+       if (index >= 0)
        {
-           ridx = GIdx2ResultIdx(index, stmt, res);
-           if (ridx >=0 && ridx < res->num_backend_rows)
+           kres_ridx = GIdx2KResIdx(index, stmt, res);
+           if (kres_ridx >= 0 && kres_ridx < (Int4)res->num_cached_keys)
            {
-               TupleField *tuple = res->backend_tuples + res->num_fields * ridx;
-               int j;
-
-               for (j = 0; j < res->num_fields; j++, tuple++)
-               {
-                   if (tuple->len > 0 && tuple->value)
-                   {
-                       free(tuple->value);
-                       tuple->value = NULL;
-                   }
-                   tuple->len = 0;
-               }
+               kres_is_valid = TRUE;
+               status = keyset[kres_ridx].status;
            }
-           if (index < res->num_total_rows)
-               res->num_total_rows = index;
        }
-       else
+       if (kres_is_valid)
        {
-           if (0 != (status & CURS_SELF_DELETING))
-               DiscardDeleted(res, index);
-           keyset[index].blocknum = rollback[i].blocknum;
-           keyset[index].offset = rollback[i].offset;
-           if (0 != (keyset[index].status & CURS_SELF_UPDATING))
-               keyset[index].status |= CURS_NEEDS_REREAD;
-           keyset[index].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING | KEYSET_INFO_PUBLIC);
+           keyset[kres_ridx].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING);
+           keyset[kres_ridx].status |= ((status & (CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING)) << 3);
        }
    }
    free(rollback);
@@ -1727,136 +2666,346 @@ static void UndoRollback(StatementClass *stmt, QResultClass *res)
    res->rb_count = res->rb_alloc = 0;
 }
 
-void   ProcessRollback(ConnectionClass *conn, BOOL undo) 
+static BOOL IndexExists(const StatementClass *stmt, const QResultClass *res, const Rollback *rollback)
 {
-   int i;
-   StatementClass  *stmt;
-   QResultClass    *res;
+   Int4    index = rollback->index, i, *updated;
+   BOOL    ret = TRUE;
 
-   for (i = 0; i < conn->num_stmts; i++)
+inolog("IndexExists index=%d(%d,%d)\n", rollback->index, rollback->blocknum, rollback->offset);
+   if (QR_get_cursor(res))
    {
-       if (stmt = conn->stmts[i], !stmt)
-           continue;
-       for (res = SC_get_Result(stmt); res; res = res->next)
+       KeySet  *updated_keyset = res->updated_keyset, *keyset;
+       Int4    num_read = QR_get_num_total_read(res), pidx, midx, marki;
+
+       updated = (Int4 *) res->updated;
+       if (!updated || res->up_count < 1)
+           return FALSE;
+       if (index < 0)
        {
-           if (undo)
-               UndoRollback(stmt, res);
+           midx = index;
+           pidx = num_read - index - 1;
+       }
+       else
+       {
+           pidx = index;
+           if (index >= (Int4) num_read)
+               midx = num_read - index - 1;
            else
-               DiscardRollback(res);
+               midx = index;
+       }
+       for (i = res->up_count - 1, marki = -1; i >= 0; i--)
+       {
+           if (updated[i] == pidx ||
+               updated[i] == midx)
+           {
+               keyset = updated_keyset + i;
+               if (keyset->blocknum == rollback->blocknum &&
+                   keyset->offset == rollback->offset)
+                   break;
+               else
+                   marki = i;
+           }
+       }
+       if (marki < 0)
+           ret = FALSE;
+       if (marki >= 0)
+       {
+           if (!tupleExists(stmt, updated_keyset + marki))
+               ret = FALSE;
        }
    }
+   return ret;
 }
 
-
-static void AddDeleted(QResultClass *res, int index)
+static QResultClass *positioned_load(StatementClass *stmt, UInt4 flag, const UInt4 *oidint, const char *tid);
+static void UndoRollback(StatementClass *stmt, QResultClass *res, BOOL partial)
 {
-   int i;
-   UInt4   *deleted;
+   Int4    i, rollbp;
+   Int4    index, ridx, kres_ridx;
+   UWORD   status;
+   Rollback *rollback;
+   KeySet  *keyset, keys, *wkey;
+   BOOL    curs = (NULL != QR_get_cursor(res)),
+       reached_eof = QR_once_reached_eof(res), kres_is_valid, texist;
 
-   if (!res->deleted)
+   if (0 == res->rb_count || NULL == res->rollback)
+       return;
+   rollback = res->rollback;
+   keyset = res->keyset;
+
+   rollbp = 0;
+   if (partial)
    {
-       res->dl_count = 0;
-       res->dl_alloc = 10;
-       deleted = res->deleted = malloc(sizeof(UInt4) * res->dl_alloc);
+       Int4    doubtp, rollbps, j, pidx, midx;
+
+       rollbps = rollbp = res->rb_count;
+       for (i = 0, doubtp = 0; i < res->rb_count; i++)
+       {
+           index = rollback[i].index;
+           keys.blocknum = rollback[i].blocknum;
+           keys.offset = rollback[i].offset;
+           texist = tupleExists(stmt, &keys);
+inolog("texist[%d]=%d", i, texist);
+           if (SQL_ADD == rollback[i].option)
+           {
+               if (texist)
+                   doubtp = i + 1;
+           }
+           else if (SQL_REFRESH == rollback[i].option)
+           {
+               if (texist || doubtp == i)
+                   doubtp = i + 1;
+           }
+           else
+           {
+               if (texist)
+                   break;
+               if (doubtp == i)
+                   doubtp = i + 1;
+           }
+inolog(" doubtp=%d\n", doubtp);
+       }
+       rollbp = i;
+inolog(" doubtp=%d,rollbp=%d\n", doubtp, rollbp);
+       if (doubtp < 0)
+           doubtp = 0;
+       do
+       {
+           rollbps = rollbp;
+           for (i = doubtp; i < rollbp; i++)
+           {
+               index = rollback[i].index;
+               if (SQL_ADD == rollback[i].option)
+               {
+inolog("index[%d]=%d\n", i, index);
+                   if (index < 0)
+                   {
+                       midx = index;
+                       pidx = res->num_total_read - index - 1;
+                   }
+                   else
+                   {
+                       pidx = index;
+                       midx = res->num_total_read - index - 1;
+                   }
+inolog("pidx=%d,midx=%d\n", pidx, midx); 
+                   for (j = rollbp - 1; j > i; j--)
+                   {
+                       if (rollback[j].index == midx ||
+                           rollback[j].index == pidx)
+                       {
+                           if (SQL_DELETE == rollback[j].option)
+                           {
+inolog("delete[%d].index=%d\n", j, rollback[j].index);
+                               break;
+                           }
+                           /*else if (SQL_UPDATE == rollback[j].option)
+                           {
+inolog("update[%d].index=%d\n", j, rollback[j].index);
+                               if (IndexExists(stmt, res, rollback + j))
+                                   break;
+                           }*/
+                       }
+                   }
+                   if (j <= i)
+                   {
+                       rollbp = i;
+                       break;
+                   }
+               }
+           }
+       } while (rollbp < rollbps);
    }
-   else
+inolog("rollbp=%d\n", rollbp);
+
+   for (i = res->rb_count - 1; i >= rollbp; i--)
    {
-       if (res->dl_count >= res->dl_alloc)
+inolog("UndoRollback %d(%d)\n", i, rollback[i].option);
+       index = rollback[i].index;
+       if (curs)
+       {
+           if (SQL_ADD == rollback[i].option)
+               RemoveAdded(res, index);
+           RemoveDeleted(res, index);
+           keys.blocknum = rollback[i].blocknum;
+           keys.offset = rollback[i].offset;
+           RemoveUpdatedAfterTheKey(res, index, &keys);
+       }
+       status = 0;
+       kres_is_valid = FALSE;
+       if (index >= 0)
        {
-           res->dl_alloc *= 2; 
-           if (deleted = realloc(res->deleted, sizeof(UInt4) * res->dl_alloc), !deleted)
+           kres_ridx = GIdx2KResIdx(index, stmt, res);
+           if (kres_ridx >= 0 && kres_ridx < (Int4)res->num_cached_keys)
            {
-               res->dl_alloc = res->dl_count = 0;
-               return;
+               kres_is_valid = TRUE;
+               wkey = keyset + kres_ridx;
+               status = wkey->status;
            }
-           res->deleted = deleted; 
        }
-       for (i = 0, deleted = res->deleted; i < res->dl_count; i++, deleted++)
+inolog(" index=%d status=%x", index, status);
+       if (kres_is_valid)
        {
-           if (index < (int) *deleted)
-               break;
+           QResultClass    *qres;
+           Int4        num_fields = res->num_fields;
+
+           ridx = GIdx2CacheIdx(index, stmt, res);
+           if (SQL_ADD == rollback[i].option)
+           {
+               if (ridx >=0 && ridx < (Int4)res->num_cached_rows)
+               {
+                   TupleField *tuple = res->backend_tuples + res->num_fields * ridx;
+                   ClearCachedRows(tuple, res->num_fields, 1);
+                   res->num_cached_rows--;
+               }
+               res->num_cached_keys--;
+               if (!curs)
+                   res->ad_count--;
+           }
+           else if (SQL_REFRESH == rollback[i].option)
+               continue;
+           else
+           {
+inolog(" (%u, %u)", wkey->blocknum,  wkey->offset);
+               wkey->blocknum = rollback[i].blocknum;
+               wkey->offset = rollback[i].offset;
+inolog("->(%u, %u)\n", wkey->blocknum, wkey->offset);
+               wkey->status &= ~KEYSET_INFO_PUBLIC;
+               if (SQL_DELETE == rollback[i].option)
+                   wkey->status &= ~CURS_SELF_DELETING;
+               else if (SQL_UPDATE == rollback[i].option)
+                   wkey->status &= ~CURS_SELF_UPDATING;
+               wkey->status |= CURS_NEEDS_REREAD;
+               if (ridx >=0 && ridx < (Int4)res->num_cached_rows)
+               {
+                   char    tidval[32];
+
+                   sprintf(tidval, "(%d,%d)", wkey->blocknum, wkey->offset);
+                   qres = positioned_load(stmt, 0, NULL, tidval);
+                   if (QR_command_maybe_successful(qres) &&
+                       QR_get_num_cached_tuples(qres) == 1)
+                   {
+                       MoveCachedRows(res->backend_tuples + num_fields * ridx, qres->backend_tuples, num_fields, 1);
+                       wkey->status &= ~CURS_NEEDS_REREAD;
+                   }
+                   QR_Destructor(qres);
+               }
+           }
        }
-       memmove(deleted + 1, deleted, sizeof(UInt4) * (res->dl_count - i)); 
    }
-   *deleted = index;
-   res->dl_count++;    
+   res->rb_count = rollbp;
+   if (0 == rollbp)
+   {
+       free(rollback);
+       res->rollback = NULL;
+       res->rb_alloc = 0;
+   }
 }
-static void DiscardDeleted(QResultClass *res, int index)
+
+void   ProcessRollback(ConnectionClass *conn, BOOL undo, BOOL partial) 
 {
    int i;
-   UInt4   *deleted;
-
-   if (!res->deleted)
-       return;
+   StatementClass  *stmt;
+   QResultClass    *res;
 
-   for (i = 0, deleted = res->deleted; i < res->dl_count; i++, deleted++)
+   for (i = 0; i < conn->num_stmts; i++)
    {
-       if (index == (int) *deleted)
-           break;
+       if (stmt = conn->stmts[i], !stmt)
+           continue;
+       for (res = SC_get_Result(stmt); res; res = res->next)
+       {
+           if (undo)
+               UndoRollback(stmt, res, partial);
+           else
+               DiscardRollback(stmt, res);
+       }
    }
-   if (i >= res->dl_count)
-       return;
-   memmove(deleted, deleted + 1, sizeof(UInt4) * (res->dl_count - i - 1)); 
-   res->dl_count--;    
 }
 
+
 #define    LATEST_TUPLE_LOAD   1L
 #define    USE_INSERTED_TID    (1L << 1)
 static QResultClass *
-positioned_load(StatementClass *stmt, UInt4 flag, UInt4 oid, const char *tidval)
+positioned_load(StatementClass *stmt, UInt4 flag, const UInt4 *oidint, const char *tidval)
 {
-   QResultClass *qres;
-   char    *selstr;
+   CSTR    func = "positioned_load";
+   CSTR    andqual = " and ";
+   QResultClass *qres = NULL;
+   char    *selstr, oideqstr[256];
    BOOL    latest = ((flag & LATEST_TUPLE_LOAD) != 0);
    UInt4   len;
+   TABLE_INFO  *ti = stmt->ti[0];
+   const char *bestitem = GET_NAME(ti->bestitem);
+   const char *bestqual = GET_NAME(ti->bestqual);
 
+inolog("%s bestitem=%s bestqual=%s\n", func, SAFE_NAME(ti->bestitem), SAFE_NAME(ti->bestqual));
+   if (!bestitem || !oidint)
+       *oideqstr = '\0';
+   else
+   {
+       /*snprintf(oideqstr, sizeof(oideqstr), " and \"%s\" = %u", bestitem, oid);*/
+       strcpy(oideqstr, andqual);
+       sprintf(oideqstr + strlen(andqual), bestqual, *oidint);
+   }
    len = strlen(stmt->load_statement);
+   len += strlen(oideqstr);
    if (tidval)
        len += 100;
    else if ((flag & USE_INSERTED_TID) != 0)
        len += 50;
    else
        len += 20;
-   SC_MALLOC_return_with_error(selstr, char, len, stmt,
-       "Couldn't alloc selstr", NULL)
+   selstr = malloc(len);
    if (tidval)
    {
        if (latest)
        {
-           if (stmt->ti[0]->schema[0])
-               sprintf(selstr, "%s where ctid = currtid2('\"%s\".\"%s\"', '%s') and oid  = %u",
-               stmt->load_statement, stmt->ti[0]->schema,
-               stmt->ti[0]->name, tidval, oid);
+           if (NAME_IS_VALID(ti->schema_name))
+               snprintf(selstr, len, "%s where ctid = currtid2('\"%s\".\"%s\"', '%s') %s",
+               stmt->load_statement, SAFE_NAME(ti->schema_name),
+               SAFE_NAME(ti->table_name), tidval, oideqstr);
            else
-               sprintf(selstr, "%s where ctid = currtid2('%s', '%s') and oid  = %u", stmt->load_statement, stmt->ti[0]->name, tidval, oid);
+               snprintf(selstr, len, "%s where ctid = currtid2('%s', '%s') %s", stmt->load_statement, SAFE_NAME(ti->table_name), tidval, oideqstr);
        }
        else 
-           sprintf(selstr, "%s where ctid = '%s' and oid = %u", stmt->load_statement, tidval, oid); 
+           snprintf(selstr, len, "%s where ctid = '%s' %s", stmt->load_statement, tidval, oideqstr); 
    }
    else if ((flag & USE_INSERTED_TID) != 0)
-       sprintf(selstr, "%s where ctid = currtid(0, '(0,0)') and oid = %u", stmt->load_statement, oid);
+       snprintf(selstr, len, "%s where ctid = currtid(0, '(,)') %s", stmt->load_statement, oideqstr);
+   else if (bestitem && oidint)
+   {
+       Int4    slen;
+       /*snprintf(selstr, len, "%s where \"%s\" = %u", stmt->load_statement, bestitem, *oid);*/
+       snprintf(selstr, len, "%s where ", stmt->load_statement);
+       slen = strlen(selstr);
+       snprintf(selstr + slen, len - slen, bestqual, *oidint);
+   }
    else
-       sprintf(selstr, "%s where oid = %u", stmt->load_statement, oid);
+   {
+       SC_set_error(stmt,STMT_INTERNAL_ERROR, "can't find the add and updating row because of the lack of oid", func);
+       goto cleanup;
+   } 
 
    mylog("selstr=%s\n", selstr);
-   qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, CLEAR_RESULT_ON_ABORT);
+   qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, 0, stmt);
+cleanup:
    free(selstr);
    return qres;
 }
 
-RETCODE        SQL_API
-SC_pos_reload(StatementClass *stmt, UDWORD global_ridx, UWORD *count, BOOL logChanges)
+RETCODE
+SC_pos_reload(StatementClass *stmt, SQLULEN global_ridx, UWORD *count, Int4 logKind)
 {
-   int         i,
-               res_cols;
+   CSTR        func = "SC_pos_reload";
+   int     res_cols;
    UWORD       rcnt, offset;
-   Int4        res_ridx;
-   UInt4       oid, blocknum;
-   QResultClass *res,
-              *qres;
+   Int4        res_ridx, kres_ridx;
+   UInt4       oidint, blocknum;
+   QResultClass    *res, *qres;
    IRDFields   *irdflds = SC_get_IRDF(stmt);
    RETCODE     ret = SQL_ERROR;
    char        tidval[32];
+   BOOL        use_ctid = TRUE, data_in_cache = TRUE, key_in_cache = TRUE;
 
    mylog("positioned load fi=%x ti=%x\n", irdflds->fi, stmt->ti);
    rcnt = 0;
@@ -1864,72 +3013,91 @@ SC_pos_reload(StatementClass *stmt, UDWORD global_ridx, UWORD *count, BOOL logCh
        *count = 0;
    if (!(res = SC_get_Curres(stmt)))
    {
-       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload.");
+       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload.", func);
+       return SQL_ERROR;
+   }
+   res_ridx = GIdx2CacheIdx(global_ridx, stmt, res);
+   if (res_ridx < 0 || res_ridx >= (Int4)QR_get_num_cached_tuples(res))
+   {
+       data_in_cache = FALSE;
+       SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
+       return SQL_ERROR;
+   }
+   kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
+   if (kres_ridx < 0 || kres_ridx >= (Int4) res->num_cached_keys)
+   {
+       key_in_cache = FALSE;
+       SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
        return SQL_ERROR;
    }
-   if (!stmt->ti)
-       parse_statement(stmt);  /* not preferable */
+   else if (0 != (res->keyset[kres_ridx].status & CURS_SELF_ADDING))
+   {
+       use_ctid = FALSE;
+       mylog("The tuple is currently being added and can't use ctid\n");
+   }   
+
+   if (SC_update_not_ready(stmt))
+       parse_statement(stmt, TRUE);    /* not preferable */
    if (!stmt->updatable)
    {
        stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-       SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
+       SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
        return SQL_ERROR;
    }
-   res_ridx = GIdx2ResultIdx(global_ridx, stmt, res);
-   if (!(oid = getOid(res, global_ridx)))
+   if (!(oidint = getOid(res, kres_ridx)))
    {
-       SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?");
-       return SQL_SUCCESS_WITH_INFO;
+       if (!strcmp(SAFE_NAME(stmt->ti[0]->bestitem), OID_NAME))
+       {
+           SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
+           return SQL_SUCCESS_WITH_INFO;
+       }
    }
-   getTid(res, global_ridx, &blocknum, &offset);
+   getTid(res, kres_ridx, &blocknum, &offset);
    sprintf(tidval, "(%u, %u)", blocknum, offset);
    res_cols = getNumResultCols(res);
-   if (qres = positioned_load(stmt, LATEST_TUPLE_LOAD, oid, tidval), qres)
+   qres = positioned_load(stmt, use_ctid ? LATEST_TUPLE_LOAD : 0, &oidint, use_ctid ? tidval : NULL);
+   if (!QR_command_maybe_successful(qres))
+   {
+       ret = SQL_ERROR;
+       SC_replace_error_with_res(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "positioned_load failed", qres, TRUE);
+   }
+   else
    {
-       TupleField *tupleo, *tuplen;
+       TupleField *tuple_old, *tuple_new;
        ConnectionClass *conn = SC_get_conn(stmt);
 
-       rcnt = QR_get_num_backend_tuples(qres);
-       tupleo = res->backend_tuples + res->num_fields * res_ridx;
-       if (logChanges && CC_is_in_trans(conn))
-           AddRollback(conn, res, global_ridx, res->keyset);
+       rcnt = QR_get_num_cached_tuples(qres);
+       tuple_old = res->backend_tuples + res->num_fields * res_ridx;
+       if (0 != logKind && CC_is_in_trans(conn))
+           AddRollback(stmt, res, global_ridx, res->keyset + kres_ridx, logKind);
        if (rcnt == 1)
        {
            int effective_fields = res_cols;
 
            QR_set_position(qres, 0);
-           tuplen = qres->tupleField;
-           if (res->keyset)
+           tuple_new = qres->tupleField;
+           if (res->keyset && key_in_cache)
            {
                if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
-                   strcmp(tuplen[qres->num_fields - 2].value, tidval))
-                   res->keyset[global_ridx].status |= SQL_ROW_UPDATED;
-               KeySetSet(tuplen, qres->num_fields, res->keyset + global_ridx);
-           }
-           for (i = 0; i < effective_fields; i++)
-           {
-               if (tupleo[i].value)
-                   free(tupleo[i].value);
-               tupleo[i].len = tuplen[i].len;
-               tuplen[i].len = 0;
-               tupleo[i].value = tuplen[i].value;
-               tuplen[i].value = NULL;
+                   strcmp(tuple_new[qres->num_fields - res->num_key_fields].value, tidval))
+                   res->keyset[kres_ridx].status |= SQL_ROW_UPDATED;
+               KeySetSet(tuple_new, qres->num_fields, res->num_key_fields, res->keyset + kres_ridx);
            }
+           if (data_in_cache)
+               MoveCachedRows(tuple_old, tuple_new, effective_fields, 1); 
            ret = SQL_SUCCESS;
        }
        else
        {
-           SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was deleted after last fetch");
+           SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was deleted after last fetch", func);
            ret = SQL_SUCCESS_WITH_INFO;
            if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
            {
-               res->keyset[global_ridx].status |= SQL_ROW_DELETED;
+               res->keyset[kres_ridx].status |= SQL_ROW_DELETED;
            }
        }
-       QR_Destructor(qres);
    }
-   else if (SC_get_errornumber(stmt) == 0)
-       SC_set_errornumber(stmt, STMT_ERROR_TAKEN_FROM_BACKEND);
+   QR_Destructor(qres);
    if (count)
        *count = rcnt;
    return ret;
@@ -1938,16 +3106,18 @@ SC_pos_reload(StatementClass *stmt, UDWORD global_ridx, UWORD *count, BOOL logCh
 static const int   pre_fetch_count = 32;
 static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per_fetch, int limitrow)
 {
+   CSTR    func = "LoadFromKeyset";
    ConnectionClass *conn = SC_get_conn(stmt);
    int i, j, rowc, rcnt = 0;
    BOOL    prepare;
    UInt4   oid, blocknum, lodlen;
+   Int4    kres_ridx;
    UWORD   offset;
    char    *qval = NULL, *sval;
    int keys_per_fetch = 10;
 
    prepare = PG_VERSION_GE(conn, 7.3);
-   for (i = stmt->rowset_start, rowc = 0;; i++)
+   for (i =SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt, res), rowc = 0;; i++)
    {
        if (i >= limitrow)
        {
@@ -1971,21 +3141,21 @@ static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per
            QResultClass    *qres;
 
            strcpy(sval, ")");
-           qres = CC_send_query(conn, qval, NULL, CLEAR_RESULT_ON_ABORT | CREATE_KEYSET);
-           if (qres)
+           qres = CC_send_query(conn, qval, NULL, CREATE_KEYSET, stmt);
+           if (QR_command_maybe_successful(qres))
            {
                int     j, k, l, m;
                TupleField  *tuple, *tuplew;
 
-               for (j = 0; j < qres->num_total_rows; j++)
+               for (j = 0; j < (Int4) QR_get_num_total_read(qres); j++)
                {
                    oid = getOid(qres, j); 
                    getTid(qres, j, &blocknum, &offset);
-                   for (k = stmt->rowset_start; k < limitrow; k++)
+                   for (k = SC_get_rowset_start(stmt); k < limitrow; k++)
                    {
                        if (oid == getOid(res, k))
                        {
-                           l = GIdx2ResultIdx(k, stmt, res);
+                           l = GIdx2CacheIdx(k, stmt, res);
                            tuple = res->backend_tuples + res->num_fields * l;
                            tuplew = qres->backend_tuples + qres->num_fields * j;
                            for (m = 0; m < res->num_fields; m++, tuple++, tuplew++)
@@ -1995,21 +3165,22 @@ static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per
                                tuple->value = tuplew->value;
                                tuple->len = tuplew->len;
                                tuplew->value = NULL;
-                               tuplew->len = 0;
+                               tuplew->len = -1;
                            }
                            res->keyset[k].status &= ~CURS_NEEDS_REREAD;
                            break;
                        }
                    }
                }
-               QR_Destructor(qres);
            }
            else
            {
-               SC_set_error(stmt, STMT_EXEC_ERROR, "Data Load Error");
+               SC_set_error(stmt, STMT_EXEC_ERROR, "Data Load Error", func);
                rcnt = -1;
+               QR_Destructor(qres);
                break;
            }
+           QR_Destructor(qres);
            if (rowc < 0)
                break;
            rowc = 0;
@@ -2034,14 +3205,16 @@ static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per
                            keys_per_fetch = pre_fetch_count;
                        else
                            keys_per_fetch = rows_per_fetch;
+                       if (!keys_per_fetch)
+                           keys_per_fetch = 2;
                        lodlen = strlen(stmt->load_statement);
-                       sprintf(planname, "_KEYSET_%p", res);
+                       sprintf(planname, "_KEYSET_%0x", res);
                        allen = 8 + strlen(planname) +
                            3 + 4 * keys_per_fetch + 1
                            + 1 + 2 + lodlen + 20 +
                            4 * keys_per_fetch + 1;
                        SC_MALLOC_return_with_error(qval, char, allen,
-                           stmt, "Couldn't alloc qval", -1)
+                           stmt, "Couldn't alloc qval", -1);
                        sprintf(qval, "PREPARE \"%s\"", planname);
                        sval = strchr(qval, '\0');
                        for (j = 0; j < keys_per_fetch; j++)
@@ -2063,18 +3236,19 @@ static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per
                            sval = strchr(sval, '\0');
                        }
                        strcpy(sval, ")");
-                       qres = CC_send_query(conn, qval, NULL, CLEAR_RESULT_ON_ABORT);
-                       if (qres)
+                       qres = CC_send_query(conn, qval, NULL, 0, stmt);
+                       if (QR_command_maybe_successful(qres))
                        {
                            res->reload_count = keys_per_fetch;
-                           QR_Destructor(qres);
                        }
                        else
                        {
-                           SC_set_error(stmt, STMT_EXEC_ERROR, "Prepare for Data Load Error");
+                           SC_set_error(stmt, STMT_EXEC_ERROR, "Prepare for Data Load Error", func);
                            rcnt = -1;
+                           QR_Destructor(qres);
                            break;
                        }
+                       QR_Destructor(qres);
                    }
                    allen = 25 + 23 * keys_per_fetch;
                }
@@ -2085,11 +3259,11 @@ static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per
                    allen = lodlen + 20 + 23 * keys_per_fetch;
                }
                SC_REALLOC_return_with_error(qval, char, allen,
-                   stmt, "Couldn't alloc qval", -1)
+                   stmt, "Couldn't alloc qval", -1);
            }
            if (res->reload_count > 0)
            {
-               sprintf(qval, "EXECUTE \"_KEYSET_%p\"(", res);
+               sprintf(qval, "EXECUTE \"_KEYSET_%x\"(", res);
                sval = qval;
            }
            else
@@ -2101,7 +3275,7 @@ static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per
            }
            sval = strchr(sval, '\0');
        }
-       if (0 != (res->keyset[i].status & CURS_NEEDS_REREAD))
+       if (0 != (res->keyset[kres_ridx].status & CURS_NEEDS_REREAD))
        {
            getTid(res, i, &blocknum, &offset);
            if (rowc)
@@ -2119,90 +3293,98 @@ static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per
 }
 
 static RETCODE SQL_API
-SC_pos_reload_needed(StatementClass *stmt, UDWORD flag)
+SC_pos_reload_needed(StatementClass *stmt, UInt4 req_size, UDWORD flag)
 {
-   Int4        i, limitrow;
+   CSTR    func = "SC_pos_reload_needed";
+   Int4        i, req_rows_size, limitrow;
    UWORD       qcount;
    QResultClass    *res;
+   IRDFields   *irdflds = SC_get_IRDF(stmt);
    RETCODE     ret = SQL_ERROR;
-   Int4        rowc, rows_per_fetch=0;
+   ConnectionClass *conn = SC_get_conn(stmt);
+   Int4        kres_ridx, rowc, rows_per_fetch;
    BOOL        create_from_scratch = (0 != flag);
 
-   mylog("SC_pos_reload_needed\n");
+   mylog("%s\n", func);
    if (!(res = SC_get_Curres(stmt)))
    {
-       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload_needed.");
+       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload_needed.", func);
        return SQL_ERROR;
    }
-   if (!stmt->ti)
-       parse_statement(stmt);  /* not preferable */
+   if (SC_update_not_ready(stmt))
+       parse_statement(stmt, TRUE);    /* not preferable */
    if (!stmt->updatable)
    {
        stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-       SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
+       SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
        return SQL_ERROR;
    }
+   rows_per_fetch = 0;
+   req_rows_size = QR_get_reqsize(res);
+   if ((Int4)req_size > req_rows_size)
+       req_rows_size = req_size;
    if (create_from_scratch)
    {
-       rows_per_fetch = ((pre_fetch_count - 1) / res->rowset_size + 1) * res->rowset_size;
+       rows_per_fetch = ((pre_fetch_count - 1) / req_rows_size + 1) * req_rows_size;
        limitrow = RowIdx2GIdx(rows_per_fetch, stmt);
    }
    else
-       limitrow = RowIdx2GIdx(res->rowset_size, stmt);
-   if (limitrow > res->num_total_rows)
-       limitrow = res->num_total_rows;
+   {
+       limitrow = RowIdx2GIdx(req_rows_size, stmt);
+   }
+   if (limitrow > (Int4) res->num_cached_keys)
+       limitrow = res->num_cached_keys;
    if (create_from_scratch)
    {
-       int flds_cnt = res->num_backend_rows * res->num_fields,
+       int flds_cnt = res->num_cached_rows * res->num_fields,
            brows;
 
-       for (i = 0; i < flds_cnt; i++)
-       {
-           if (res->backend_tuples[i].value)
-               free(res->backend_tuples[i].value);
-       }
+       ClearCachedRows(res->backend_tuples, res->num_fields, res->num_cached_rows);
        brows = GIdx2RowIdx(limitrow, stmt);
-       if (brows > res->count_backend_allocated)
+       if (brows > (Int4) res->count_backend_allocated)
        {
            res->backend_tuples = realloc(res->backend_tuples, sizeof(TupleField) * res->num_fields * brows);
            res->count_backend_allocated = brows;
        }
        if (brows > 0)
            memset(res->backend_tuples, 0, sizeof(TupleField) * res->num_fields * brows);
-       res->num_backend_rows = brows;
-       res->base = 0;
-       for (i = stmt->rowset_start; i < limitrow; i++)
+       QR_set_num_cached_rows(res, brows);
+       QR_set_rowstart_in_cache(res, 0);
+       if (SQL_RD_ON != stmt->options.retrieve_data)
+           return SQL_SUCCESS;
+       for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt,res); i < limitrow; i++, kres_ridx++)
        {
-           if (0 == (res->keyset[i].status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
-               res->keyset[i].status |= CURS_NEEDS_REREAD;
+           if (0 == (res->keyset[kres_ridx].status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
+               res->keyset[kres_ridx].status |= CURS_NEEDS_REREAD;
        }
    }
    if (rowc = LoadFromKeyset(stmt, res, rows_per_fetch, limitrow), rowc < 0)
    {
        return SQL_ERROR;
    }
-   for (i = stmt->rowset_start; i < limitrow; i++)
+   for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt, res); i < limitrow; i++)
    {
-       if (0 != (res->keyset[i].status & CURS_NEEDS_REREAD))
+       if (0 != (res->keyset[kres_ridx].status & CURS_NEEDS_REREAD))
        {
-           ret = SC_pos_reload(stmt, i, &qcount, FALSE);
+           ret = SC_pos_reload(stmt, i, &qcount, 0);
            if (SQL_ERROR == ret)
            {
                break;
            }
-           if (SQL_ROW_DELETED == (res->keyset[i].status & KEYSET_INFO_PUBLIC))
+           if (SQL_ROW_DELETED == (res->keyset[kres_ridx].status & KEYSET_INFO_PUBLIC))
            {
-               res->keyset[i].status |= CURS_OTHER_DELETED;
+               res->keyset[kres_ridx].status |= CURS_OTHER_DELETED;
            }
-           res->keyset[i].status &= ~CURS_NEEDS_REREAD;
+           res->keyset[kres_ridx].status &= ~CURS_NEEDS_REREAD;
        }
    }
    return ret;
 }
 
 RETCODE        SQL_API
-SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
+SC_pos_newload(StatementClass *stmt, const UInt4 *oidint, BOOL tidRef)
 {
+   CSTR    func = "SC_pos_newload";
    int         i;
    QResultClass *res, *qres;
    RETCODE     ret = SQL_ERROR;
@@ -2210,45 +3392,80 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
    mylog("positioned new ti=%x\n", stmt->ti);
    if (!(res = SC_get_Curres(stmt)))
    {
-       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_newload.");
+       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_newload.", func);
        return SQL_ERROR;
    }
-   if (!stmt->ti)
-       parse_statement(stmt);  /* not preferable */
+   if (SC_update_not_ready(stmt))
+       parse_statement(stmt, TRUE);    /* not preferable */
    if (!stmt->updatable)
    {
        stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-       SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
+       SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
        return SQL_ERROR;
    }
-   if (qres = positioned_load(stmt, tidRef ? USE_INSERTED_TID : 0, oid, NULL), qres)
+   qres = positioned_load(stmt, tidRef ? USE_INSERTED_TID : 0, oidint, NULL);
+   if (!qres || !QR_command_maybe_successful(qres))
+   {
+       SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "positioned_load in pos_newload failed", func);
+   }
+   else
    {
-       TupleField *tupleo, *tuplen;
-       int     count = QR_get_num_backend_tuples(qres);
+       int     count = QR_get_num_cached_tuples(qres);
 
        QR_set_position(qres, 0);
        if (count == 1)
        {
            int effective_fields = res->num_fields;
            int tuple_size;
-
-           tuplen = qres->tupleField;
-           if (res->haskeyset &&
-               res->num_total_rows >= res->count_keyset_allocated)
+           Int4    num_total_rows, num_cached_rows, kres_ridx;
+           BOOL    appendKey = FALSE, appendData = FALSE;
+           TupleField *tuple_old, *tuple_new;
+
+           tuple_new = qres->tupleField;
+           num_total_rows = QR_get_num_total_tuples(res);
+
+           AddAdded(stmt, res, num_total_rows, tuple_new);
+           num_cached_rows = QR_get_num_cached_tuples(res);
+           kres_ridx = GIdx2KResIdx(num_total_rows, stmt, res);
+           if (QR_haskeyset(res))
+           {   if (!QR_get_cursor(res))
+               {
+                   appendKey = TRUE;
+                   if (num_total_rows == CacheIdx2GIdx(num_cached_rows, stmt, res))
+                       appendData = TRUE;
+                   else
+                   {
+inolog("total %d <> backend %d - base %d + start %d cursor_type=%d\n", 
+num_total_rows, num_cached_rows,
+QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt), stmt->options.cursor_type);
+                   }
+               }
+               else if (kres_ridx >= 0 && kres_ridx < (Int4)res->cache_size)
+               {
+                   appendKey = TRUE;
+                   appendData = TRUE;
+               }
+           }
+           if (appendKey)
            {
-
-               if (!res->count_keyset_allocated)
-                   tuple_size = TUPLE_MALLOC_INC;
-               else
-                   tuple_size = res->count_keyset_allocated * 2;
-               res->keyset = (KeySet *) realloc(res->keyset, sizeof(KeySet) * tuple_size); 
-               res->count_keyset_allocated = tuple_size;
+                   if (res->num_cached_keys >= (Int4) res->count_keyset_allocated)
+               {
+                   if (!res->count_keyset_allocated)
+                       tuple_size = TUPLE_MALLOC_INC;
+                   else
+                       tuple_size = res->count_keyset_allocated * 2;
+                   res->keyset = (KeySet *) realloc(res->keyset, sizeof(KeySet) * tuple_size); 
+                   res->count_keyset_allocated = tuple_size;
+               }
+               KeySetSet(tuple_new, qres->num_fields, res->num_key_fields, res->keyset + kres_ridx);
+               res->num_cached_keys++;
            }
-           KeySetSet(tuplen, qres->num_fields, res->keyset + res->num_total_rows);
-
-           if (res->num_total_rows == ResultIdx2GIdx(res->num_backend_rows, stmt, res))
+           if (appendData)
            {
-               if (res->num_backend_rows >= res->count_backend_allocated)
+inolog("total %d == backend %d - base %d + start %d cursor_type=%d\n", 
+num_total_rows, num_cached_rows,
+QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt), stmt->options.cursor_type);
+               if (num_cached_rows >= (Int4)res->count_backend_allocated)
                {
                    if (!res->count_backend_allocated)
                        tuple_size = TUPLE_MALLOC_INC;
@@ -2259,46 +3476,42 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
                        res->num_fields * sizeof(TupleField) * tuple_size);
                    if (!res->backend_tuples)
                    {
-                       SC_set_error(stmt, res->status = PGRES_FATAL_ERROR, "Out of memory while reading tuples.");
+                       SC_set_error(stmt, QR_set_rstatus(res, PGRES_FATAL_ERROR), "Out of memory while reading tuples.", func);
                        QR_Destructor(qres);
                        return SQL_ERROR;
                    }
                    res->count_backend_allocated = tuple_size;
                }
-               tupleo = res->backend_tuples + res->num_fields * res->num_backend_rows;
+               tuple_old = res->backend_tuples + res->num_fields * num_cached_rows;
                for (i = 0; i < effective_fields; i++)
                {
-                   tupleo[i].len = tuplen[i].len;
-                   tuplen[i].len = 0;
-                   tupleo[i].value = tuplen[i].value;
-                   tuplen[i].value = NULL;
+                   tuple_old[i].len = tuple_new[i].len;
+                   tuple_new[i].len = -1;
+                   tuple_old[i].value = tuple_new[i].value;
+                   tuple_new[i].value = NULL;
                }
-               for (; i < res->num_fields; i++)
-               {
-                   tupleo[i].len = 0;
-                   tupleo[i].value = NULL;
-               }
-               res->num_backend_rows++;
+               res->num_cached_rows++;
            }
-           res->num_total_rows++;
            ret = SQL_SUCCESS;
        }
        else if (0 == count)
            ret = SQL_NO_DATA_FOUND;
        else
        {
-           SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the driver cound't identify inserted rows");
+           SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the driver cound't identify inserted rows", func);
            ret = SQL_ERROR;
        }
-       QR_Destructor(qres);
-       /* stmt->currTuple = stmt->rowset_start + ridx; */
+       /* stmt->currTuple = SC_get_rowset_start(stmt) + ridx; */
    }
+   QR_Destructor(qres);
    return ret;
 }
 
 static RETCODE SQL_API
-irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow, UDWORD global_ridx)
+irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow, SQLULEN global_ridx)
 {
+   CSTR    func = "irow_update";
+
    if (ret != SQL_ERROR)
    {
        int         updcnt;
@@ -2308,13 +3521,17 @@ irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow
            sscanf(cmdstr, "UPDATE %d", &updcnt) == 1)
        {
            if (updcnt == 1)
-               ret = SC_pos_reload(stmt, global_ridx, (UWORD *) 0, TRUE);
+           {
+               ret = SC_pos_reload(stmt, global_ridx, (UWORD *) 0, SQL_UPDATE);
+               if (SQL_ERROR != ret)
+                   AddUpdated(stmt, global_ridx);
+           }
            else if (updcnt == 0)
            {
-               SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before updation");
+               SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before updation", func);
                ret = SQL_ERROR;
                if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
-                   SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
+                   SC_pos_reload(stmt, global_ridx, (UWORD *) 0, 0);
            }
            else
                ret = SQL_ERROR;
@@ -2323,7 +3540,7 @@ irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow
            ret = SQL_ERROR;
        if (ret == SQL_ERROR && SC_get_errornumber(stmt) == 0)
        {
-           SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos update return error");
+           SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos update return error", func);
        }
    }
    return ret;
@@ -2337,33 +3554,46 @@ typedef struct
    StatementClass  *stmt, *qstmt;
    IRDFields   *irdflds;
    UWORD       irow;
-   UDWORD      global_ridx;
+   SQLULEN     global_ridx;
 }  pup_cdata;
 static RETCODE
 pos_update_callback(RETCODE retcode, void *para)
 {
+   CSTR    func = "pos_update_callback";
    RETCODE ret = retcode;
    pup_cdata *s = (pup_cdata *) para;
+   Int4    kres_ridx;
 
    if (s->updyes)
    {
        mylog("pos_update_callback in\n");
        ret = irow_update(ret, s->stmt, s->qstmt, s->irow, s->global_ridx);
+inolog("irow_update ret=%d,%d\n", ret, SC_get_errornumber(s->qstmt));
+       if (ret != SQL_SUCCESS)
+           SC_error_copy(s->stmt, s->qstmt, TRUE);
        PGAPI_FreeStmt(s->qstmt, SQL_DROP);
+       s->qstmt = NULL;
    }
    s->updyes = FALSE;
+   kres_ridx = GIdx2KResIdx(s->global_ridx, s->stmt, s->res);
+   if (kres_ridx < 0 || kres_ridx >= (Int4)s->res->num_cached_keys)
+   {
+       SC_set_error(s->stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
+inolog("gidx=%d num_keys=%d kresidx=%d\n", s->global_ridx, s->res->num_cached_keys, kres_ridx);
+       return SQL_ERROR;
+   }
    if (SQL_SUCCESS == ret && s->res->keyset)
    {
        ConnectionClass *conn = SC_get_conn(s->stmt);
 
        if (CC_is_in_trans(conn))
        {
-           s->res->keyset[s->global_ridx].status |= (SQL_ROW_UPDATED  | CURS_SELF_UPDATING);
+           s->res->keyset[kres_ridx].status |= (SQL_ROW_UPDATED  | CURS_SELF_UPDATING);
        }
        else
-           s->res->keyset[s->global_ridx].status |= (SQL_ROW_UPDATED  | CURS_SELF_UPDATED);
+           s->res->keyset[kres_ridx].status |= (SQL_ROW_UPDATED  | CURS_SELF_UPDATED);
    }
-
+#if (ODBCVER >= 0x0300)
    if (s->irdflds->rowStatusArray)
    {
        switch (ret)
@@ -2375,13 +3605,15 @@ pos_update_callback(RETCODE retcode, void *para)
                s->irdflds->rowStatusArray[s->irow] = ret;
        }
    }
+#endif /* ODBCVER */
 
    return ret;
 }
 RETCODE
 SC_pos_update(StatementClass *stmt,
-             UWORD irow, UDWORD global_ridx)
+             UWORD irow, SQLULEN global_ridx)
 {
+   CSTR    func = "SC_pos_update";
    int         i,
                num_cols,
                upd_cols;
@@ -2389,12 +3621,13 @@ SC_pos_update(StatementClass *stmt,
    ConnectionClass *conn;
    ARDFields   *opts = SC_get_ARDF(stmt);
    BindInfoClass *bindings = opts->bindings;
+   TABLE_INFO  *ti;
    FIELD_INFO  **fi;
    char        updstr[4096];
    RETCODE     ret;
    UInt4   oid, offset, blocknum;
    UInt2   pgoffset;
-   Int4    *used, bind_size = opts->bind_size;
+   Int4    kres_ridx, *used, bind_size = opts->bind_size;
 
    s.stmt = stmt;
    s.irow = irow;
@@ -2403,29 +3636,39 @@ SC_pos_update(StatementClass *stmt,
    fi = s.irdflds->fi;
    if (!(s.res = SC_get_Curres(s.stmt)))
    {
-       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_update.");
+       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_update.", func);
        return SQL_ERROR;
    }
-   mylog("POS UPDATE %d+%d fi=%x ti=%x\n", s.irow, s.res->base, fi, s.stmt->ti);
-   if (!s.stmt->ti)
-       parse_statement(s.stmt);    /* not preferable */
+   mylog("POS UPDATE %d+%d fi=%x ti=%x\n", s.irow, QR_get_rowstart_in_cache(s.res), fi, s.stmt->ti);
+   if (SC_update_not_ready(stmt))
+       parse_statement(s.stmt, TRUE);  /* not preferable */
    if (!s.stmt->updatable)
    {
        s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-       SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
+       SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
        return SQL_ERROR;
    }
-   if (!(oid = getOid(s.res, s.global_ridx)))
+   kres_ridx = GIdx2KResIdx(s.global_ridx, s.stmt, s.res);
+   if (kres_ridx < 0 || kres_ridx >= (Int4)s.res->num_cached_keys)
    {
-       SC_set_error(s.stmt, STMT_INVALID_CURSOR_POSITION, "The row is already deleted ?");
+       SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
        return SQL_ERROR;
    }
-   getTid(s.res, s.global_ridx, &blocknum, &pgoffset);
+   if (!(oid = getOid(s.res, kres_ridx)))
+   {
+       if (!strcmp(SAFE_NAME(stmt->ti[0]->bestitem), OID_NAME))
+       {
+           SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
+           return SQL_ERROR;
+       }
+   }
+   getTid(s.res, kres_ridx, &blocknum, &pgoffset);
 
-   if (s.stmt->ti[0]->schema[0])
-       sprintf(updstr, "update \"%s\".\"%s\" set", s.stmt->ti[0]->schema, s.stmt->ti[0]->name);
+   ti = s.stmt->ti[0];
+   if (NAME_IS_VALID(ti->schema_name))
+       sprintf(updstr, "update \"%s\".\"%s\" set", SAFE_NAME(ti->schema_name), SAFE_NAME(ti->table_name));
    else
-       sprintf(updstr, "update \"%s\" set", s.stmt->ti[0]->name);
+       sprintf(updstr, "update \"%s\" set", SAFE_NAME(ti->table_name));
    num_cols = s.irdflds->nfields;
    offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
    for (i = upd_cols = 0; i < num_cols; i++)
@@ -2441,9 +3684,9 @@ SC_pos_update(StatementClass *stmt,
            if (*used != SQL_IGNORE && fi[i]->updatable)
            {
                if (upd_cols)
-                   sprintf(updstr, "%s, \"%s\" = ?", updstr, fi[i]->name);
+                   sprintf(updstr, "%s, \"%s\" = ?", updstr, GET_NAME(fi[i]->column_name));
                else
-                   sprintf(updstr, "%s \"%s\" = ?", updstr, fi[i]->name);
+                   sprintf(updstr, "%s \"%s\" = ?", updstr, GET_NAME(fi[i]->column_name));
                upd_cols++;
            }
        }
@@ -2456,24 +3699,32 @@ SC_pos_update(StatementClass *stmt,
    {
        HSTMT       hstmt;
        int         j;
+       int         res_cols = QR_NumResultCols(s.res);
        ConnInfo    *ci = &(conn->connInfo);
        APDFields   *apdopts;
        Int4        fieldtype = 0;
+       const char *bestitem = GET_NAME(ti->bestitem);
+       const char *bestqual = GET_NAME(ti->bestqual);
 
-       /*sprintf(updstr, "%s where ctid = '%s' and oid = %s", updstr,
-               tidval, oidval);*/
-       sprintf(updstr, "%s where ctid = '(%u, %u)' and oid = %u", updstr,
-               blocknum, pgoffset, oid);
+       sprintf(updstr, "%s where ctid = '(%u, %u)'", updstr,
+               blocknum, pgoffset);
+       if (bestitem)
+       {
+           /*sprintf(updstr, "%s and \"%s\" = %u", updstr, bestitem, oid);*/
+           strcat(updstr, " and ");
+           sprintf(updstr + strlen(updstr), bestqual, oid);
+       }
        mylog("updstr=%s\n", updstr);
        if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
        {
-           SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error");
+           SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error", func);
            return SQL_ERROR;
        }
        s.qstmt = (StatementClass *) hstmt;
        apdopts = SC_get_APDF(s.qstmt);
        apdopts->param_bind_type = opts->bind_size;
        apdopts->param_offset_ptr = opts->row_offset_ptr;
+       SC_set_delegate(s.stmt, s.qstmt);
        for (i = j = 0; i < num_cols; i++)
        {
            if (used = bindings[i].used, used != NULL)
@@ -2496,30 +3747,27 @@ SC_pos_update(StatementClass *stmt,
                        (SQLSMALLINT) fi[i]->decimal_digits,
                        bindings[i].buffer,
                        bindings[i].buflen,
-                       (SQLINTEGER *) bindings[i].used);
+                       bindings[i].used);
                }
            }
        }
        s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow;
        s.updyes = TRUE; 
        ret = PGAPI_ExecDirect(hstmt, updstr, SQL_NTS, 0);
-       if (ret == SQL_ERROR)
-       {
-           SC_error_copy(s.stmt, s.qstmt);
-       }
-       else if (ret == SQL_NEED_DATA)  /* must be fixed */
+       if (ret == SQL_NEED_DATA)
        {
            pup_cdata *cbdata = (pup_cdata *) malloc(sizeof(pup_cdata));
            memcpy(cbdata, &s, sizeof(pup_cdata));
-           s.stmt->execute_delegate = s.qstmt;
            enqueueNeedDataCallback(s.stmt, pos_update_callback, cbdata);
            return ret;
        }
+       /* else if (ret != SQL_SUCCESS) this is unneccesary 
+           SC_error_copy(s.stmt, s.qstmt, TRUE); */
    }
    else
    {
        ret = SQL_SUCCESS_WITH_INFO;
-       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "update list null");
+       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "update list null", func);
    }
 
    ret = pos_update_callback(ret, &s);
@@ -2527,52 +3775,77 @@ SC_pos_update(StatementClass *stmt,
 }
 RETCODE
 SC_pos_delete(StatementClass *stmt,
-             UWORD irow, UDWORD global_ridx)
+             UWORD irow, SQLULEN global_ridx)
 {
+   CSTR    func = "SC_pos_update";
    UWORD       offset;
    QResultClass *res, *qres;
    ConnectionClass *conn = SC_get_conn(stmt);
+   ARDFields   *opts = SC_get_ARDF(stmt);
    IRDFields   *irdflds = SC_get_IRDF(stmt);
+   BindInfoClass *bindings = opts->bindings;
    char        dltstr[4096];
    RETCODE     ret;
+   Int4        kres_ridx;
    UInt4       oid, blocknum, qflag;
+   TABLE_INFO  *ti;
+   const char  *bestitem;
+   const char  *bestqual;
 
    mylog("POS DELETE ti=%x\n", stmt->ti);
    if (!(res = SC_get_Curres(stmt)))
    {
-       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_delete.");
+       SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_delete.", func);
        return SQL_ERROR;
    }
-   if (!stmt->ti)
-       parse_statement(stmt);  /* not preferable */
+   if (SC_update_not_ready(stmt))
+       parse_statement(stmt, TRUE);    /* not preferable */
    if (!stmt->updatable)
    {
        stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-       SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
+       SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
        return SQL_ERROR;
    }
-   if (!(oid = getOid(res, global_ridx)))
+   kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
+   if (kres_ridx < 0 || kres_ridx >= (Int4)res->num_cached_keys)
    {
-       SC_set_error(stmt, STMT_INVALID_CURSOR_POSITION, "The row is already deleted ?");
+       SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
        return SQL_ERROR;
    }
-   getTid(res, global_ridx, &blocknum, &offset);
+   ti = stmt->ti[0];
+   bestitem = GET_NAME(ti->bestitem);
+   if (!(oid = getOid(res, kres_ridx)))
+   {
+       if (bestitem && !strcmp(bestitem, OID_NAME))
+       {
+           SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
+           return SQL_ERROR;
+       }
+   }
+   bestqual = GET_NAME(ti->bestqual);
+   getTid(res, kres_ridx, &blocknum, &offset);
    /*sprintf(dltstr, "delete from \"%s\" where ctid = '%s' and oid = %s",*/
-   if (stmt->ti[0]->schema[0])
-       sprintf(dltstr, "delete from \"%s\".\"%s\" where ctid = '(%u, %u)' and oid = %u",
-       stmt->ti[0]->schema, stmt->ti[0]->name, blocknum, offset, oid);
+   if (NAME_IS_VALID(ti->schema_name))
+       sprintf(dltstr, "delete from \"%s\".\"%s\" where ctid = '(%u, %u)'",
+       SAFE_NAME(ti->schema_name), SAFE_NAME(ti->table_name), blocknum, offset);
    else
-       sprintf(dltstr, "delete from \"%s\" where ctid = '(%u, %u)' and oid = %u",
-           stmt->ti[0]->name, blocknum, offset, oid);
+       sprintf(dltstr, "delete from \"%s\" where ctid = '(%u, %u)'",
+           SAFE_NAME(ti->table_name), blocknum, offset);
+   if (bestitem)
+   {
+       /*sprintf(dltstr, "%s and \"%s\" = %u", dltstr, bestitem, oid);*/
+       strcat(dltstr, " and ");
+       sprintf(dltstr + strlen(dltstr), bestqual, oid);
+   }
 
    mylog("dltstr=%s\n", dltstr);
-   qflag = CLEAR_RESULT_ON_ABORT;
+   qflag = 0;
         if (!stmt->internal && !CC_is_in_trans(conn) &&
                  (!CC_is_in_autocommit(conn)))
        qflag |= GO_INTO_TRANSACTION;
-   qres = CC_send_query(conn, dltstr, NULL, qflag);
+   qres = CC_send_query(conn, dltstr, NULL, qflag, stmt);
    ret = SQL_SUCCESS;
-   if (qres && QR_command_maybe_successful(qres))
+   if (QR_command_maybe_successful(qres))
    {
        int         dltcnt;
        const char *cmdstr = QR_get_command(qres);
@@ -2581,13 +3854,17 @@ SC_pos_delete(StatementClass *stmt,
            sscanf(cmdstr, "DELETE %d", &dltcnt) == 1)
        {
            if (dltcnt == 1)
-               SC_pos_reload(stmt, global_ridx, (UWORD *) 0, TRUE);
+           {
+               RETCODE tret = SC_pos_reload(stmt, global_ridx, (UWORD *) 0, SQL_DELETE);
+               if (SQL_SUCCESS != tret && SQL_SUCCESS_WITH_INFO != tret)
+                   ret = tret;
+           }
            else if (dltcnt == 0)
            {
-               SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before deletion");
+               SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before deletion", func);
                ret = SQL_ERROR;
                if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
-                   SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
+                   SC_pos_reload(stmt, global_ridx, (UWORD *) 0, 0);
            }
            else
                ret = SQL_ERROR;
@@ -2599,21 +3876,23 @@ SC_pos_delete(StatementClass *stmt,
        ret = SQL_ERROR;
    if (ret == SQL_ERROR && SC_get_errornumber(stmt) == 0)
    {
-       SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos delete return error");
+       SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos delete return error", func);
    }
    if (qres)
        QR_Destructor(qres);
    if (SQL_SUCCESS == ret && res->keyset)
    {
-       AddDeleted(res, global_ridx);
+       AddDeleted(res, global_ridx, res->keyset + kres_ridx);
+       res->keyset[kres_ridx].status &= (~KEYSET_INFO_PUBLIC);
        if (CC_is_in_trans(conn))
        {
-           res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETING);
+           res->keyset[kres_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETING);
        }
        else
-           res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED);
+           res->keyset[kres_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED);
+inolog(".status[%d]=%x\n", global_ridx, res->keyset[kres_ridx].status);
    }
-
+#if (ODBCVER >= 0x0300)
    if (irdflds->rowStatusArray)
    {
        switch (ret)
@@ -2625,17 +3904,19 @@ SC_pos_delete(StatementClass *stmt,
                irdflds->rowStatusArray[irow] = ret;
        }
    }
-
+#endif /* ODBCVER */
    return ret;
 }
 
 static RETCODE SQL_API
-irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, int addpos)
+irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, Int4 addpos)
 {
+   CSTR    func = "irow_insert";
+
    if (ret != SQL_ERROR)
    {
        int     addcnt;
-       UInt4       oid;
+       UInt4       oid, *poid = NULL;
        ARDFields   *opts = SC_get_ARDF(stmt);
        QResultClass    *ires = SC_get_Curres(istmt);
        const char *cmdstr;
@@ -2649,16 +3930,18 @@ irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, int addpos
            ConnectionClass *conn = SC_get_conn(stmt);
            RETCODE qret;
 
+           if (0 != oid)
+               poid = &oid;
            qret = SQL_NO_DATA_FOUND;
            if (PG_VERSION_GE(conn, 7.2))
            {
-               qret = SC_pos_newload(stmt, oid, TRUE);
+               qret = SC_pos_newload(stmt, poid, TRUE);
                if (SQL_ERROR == qret)
                    return qret;
            }
            if (SQL_NO_DATA_FOUND == qret)
            {
-               qret = SC_pos_newload(stmt, oid, FALSE);
+               qret = SC_pos_newload(stmt, poid, FALSE);
                if (SQL_ERROR == qret)
                    return qret;
            }
@@ -2668,7 +3951,7 @@ irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, int addpos
                char    buf[32];
                UInt4   offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
 
-               sprintf(buf, "%d", addpos + 1);
+               snprintf(buf, sizeof(buf), "%ld", SC_make_bookmark(addpos));
                SC_set_current_col(stmt, -1);
                copy_and_convert_field(stmt,
                    PG_TYPE_INT4,
@@ -2676,14 +3959,13 @@ irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, int addpos
                                bookmark->returntype,
                    bookmark->buffer + offset,
                    bookmark->buflen,
-                   (SDWORD *) (bookmark->used
-                           ? (bookmark->used + (offset >> 2))
-                           : NULL));
+                   bookmark->used ? bookmark->used
+                   + (offset >> 2) : NULL);
            }
        }
        else
        {
-           SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos insert return error");
+           SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos insert return error", func);
        }
    }
    return ret;
@@ -2704,34 +3986,45 @@ pos_add_callback(RETCODE retcode, void *para)
 {
    RETCODE ret = retcode;
    padd_cdata *s = (padd_cdata *) para;
+   Int4    addpos;
 
    if (s->updyes)
    {
        int brow_save;
        
-       mylog("pos_add_callback in\n");
+       mylog("pos_add_callback in ret=%d\n", ret);
        brow_save = s->stmt->bind_row; 
-       s->stmt->bind_row = s->irow; 
-       ret = irow_insert(ret, s->stmt, s->qstmt, s->res->num_total_rows);
+       s->stmt->bind_row = s->irow;
+       if (QR_get_cursor(s->res))
+           addpos = -(Int4)(s->res->ad_count + 1);
+       else
+           addpos = QR_get_num_total_tuples(s->res); 
+       ret = irow_insert(ret, s->stmt, s->qstmt, addpos);
        s->stmt->bind_row = brow_save;
    }
-   s->updyes = FALSE; 
+   s->updyes = FALSE;
+   if (ret != SQL_SUCCESS)
+       SC_error_copy(s->stmt, s->qstmt, TRUE);
    PGAPI_FreeStmt((HSTMT) s->qstmt, SQL_DROP);
+   s->qstmt = NULL;
    if (SQL_SUCCESS == ret && s->res->keyset)
    {
-       int global_ridx = s->res->num_total_rows - 1;
+       int global_ridx = QR_get_num_total_tuples(s->res) - 1;
        ConnectionClass *conn = SC_get_conn(s->stmt);
+       Int4    kres_ridx;
+       UWORD   status = SQL_ROW_ADDED;
 
        if (CC_is_in_trans(conn))
+           status |= CURS_SELF_ADDING;
+       else
+           status |= CURS_SELF_ADDED;
+       kres_ridx = GIdx2KResIdx(global_ridx, s->stmt, s->res);
+       if (kres_ridx >= 0 || kres_ridx < (Int4)s->res->num_cached_keys)
        {
-
-           AddRollback(conn, s->res, global_ridx, NULL);
-           s->res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDING);
+           s->res->keyset[kres_ridx].status = status;
        }
-       else
-           s->res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDED);
    }
-
+#if (ODBCVER >= 0x0300)
    if (s->irdflds->rowStatusArray)
    {
        switch (ret)
@@ -2743,6 +4036,7 @@ pos_add_callback(RETCODE retcode, void *para)
                s->irdflds->rowStatusArray[s->irow] = ret;
        }
    }
+#endif /* ODBCVER */
 
    return ret;
 }
@@ -2751,6 +4045,7 @@ RETCODE
 SC_pos_add(StatementClass *stmt,
           UWORD irow)
 {
+   CSTR    func = "SC_pos_add";
    int         num_cols,
                add_cols,
                i;
@@ -2768,33 +4063,34 @@ SC_pos_add(StatementClass *stmt,
    UInt4       offset;
    Int4        *used, bind_size = opts->bind_size;
    Int4        fieldtype;
+   int     func_cs_count = 0;
 
    mylog("POS ADD fi=%x ti=%x\n", fi, stmt->ti);
    s.stmt = stmt;
    s.irow = irow;
    if (!(s.res = SC_get_Curres(s.stmt)))
    {
-       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_add.");
+       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_add.", func);
        return SQL_ERROR;
    }
-   if (!s.stmt->ti)
-       parse_statement(s.stmt);    /* not preferable */
+   if (SC_update_not_ready(stmt))
+       parse_statement(s.stmt, TRUE);  /* not preferable */
    if (!s.stmt->updatable)
    {
        s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-       SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
+       SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
        return SQL_ERROR;
    }
    s.irdflds = SC_get_IRDF(s.stmt);
    num_cols = s.irdflds->nfields;
    conn = SC_get_conn(s.stmt);
-   if (s.stmt->ti[0]->schema[0])
-       sprintf(addstr, "insert into \"%s\".\"%s\" (", s.stmt->ti[0]->schema, s.stmt->ti[0]->name);
+   if (NAME_IS_VALID(s.stmt->ti[0]->schema_name))
+       sprintf(addstr, "insert into \"%s\".\"%s\" (", SAFE_NAME(s.stmt->ti[0]->schema_name), SAFE_NAME(s.stmt->ti[0]->table_name));
    else
-       sprintf(addstr, "insert into \"%s\" (", s.stmt->ti[0]->name);
+       sprintf(addstr, "insert into \"%s\" (", SAFE_NAME(s.stmt->ti[0]->table_name));
    if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
    {
-       SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error");
+       SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error", func);
        return SQL_ERROR;
    }
    if (opts->row_offset_ptr)
@@ -2805,6 +4101,7 @@ SC_pos_add(StatementClass *stmt,
    apdopts = SC_get_APDF(s.qstmt);
    apdopts->param_bind_type = opts->bind_size;
    apdopts->param_offset_ptr = opts->row_offset_ptr;
+   SC_set_delegate(s.stmt, s.qstmt);
    ci = &(conn->connInfo);
    for (i = add_cols = 0; i < num_cols; i++)
    {
@@ -2820,9 +4117,9 @@ SC_pos_add(StatementClass *stmt,
            {
                fieldtype = QR_get_field_type(s.res, i);
                if (add_cols)
-                   sprintf(addstr, "%s, \"%s\"", addstr, fi[i]->name);
+                   sprintf(addstr, "%s, \"%s\"", addstr, GET_NAME(fi[i]->column_name));
                else
-                   sprintf(addstr, "%s\"%s\"", addstr, fi[i]->name);
+                   sprintf(addstr, "%s\"%s\"", addstr, GET_NAME(fi[i]->column_name));
                PGAPI_BindParameter(hstmt,
                    (SQLUSMALLINT) ++add_cols,
                    SQL_PARAM_INPUT,
@@ -2832,13 +4129,15 @@ SC_pos_add(StatementClass *stmt,
                    (SQLSMALLINT) fi[i]->decimal_digits,
                    bindings[i].buffer,
                    bindings[i].buflen,
-                   (SQLINTEGER *) bindings[i].used);
+                   bindings[i].used);
            }
        }
        else
            mylog("%d null bind\n", i);
    }
    s.updyes = FALSE;
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   ENTER_INNER_CONN_CS(conn, func_cs_count); 
    if (add_cols > 0)
    {
        sprintf(addstr, "%s) values (", addstr);
@@ -2852,59 +4151,73 @@ SC_pos_add(StatementClass *stmt,
        strcat(addstr, ")");
        mylog("addstr=%s\n", addstr);
        s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow;
-       s.updyes = TRUE; 
+       s.updyes = TRUE;
        ret = PGAPI_ExecDirect(hstmt, addstr, SQL_NTS, 0);
-       if (ret == SQL_ERROR)
-       {
-           SC_error_copy(s.stmt, s.qstmt);
-       }
-       else if (ret == SQL_NEED_DATA)      /* must be fixed */
+       if (ret == SQL_NEED_DATA)
        {
            padd_cdata *cbdata = (padd_cdata *) malloc(sizeof(padd_cdata));
            memcpy(cbdata, &s, sizeof(padd_cdata));
-           s.stmt->execute_delegate = s.qstmt;
            enqueueNeedDataCallback(s.stmt, pos_add_callback, cbdata);
-           return ret;
+           goto cleanup;
        }
+       /* else if (ret != SQL_SUCCESS) this is unneccesary
+           SC_error_copy(s.stmt, s.qstmt, TRUE); */
    }
    else
    {
        ret = SQL_SUCCESS_WITH_INFO;
-       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "insert list null");
+       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "insert list null", func);
    }
 
    ret = pos_add_callback(ret, &s);
 
+cleanup:
+#undef return
+   CLEANUP_FUNC_CONN_CS(func_cs_count, conn);
    return ret;
 }
 
 /*
  * Stuff for updatable cursors end.
  */
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
 
 RETCODE
-SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx)
+SC_pos_refresh(StatementClass *stmt, UWORD irow , SQLULEN global_ridx)
 {
    RETCODE ret;
+#if (ODBCVER >= 0x0300)
    IRDFields   *irdflds = SC_get_IRDF(stmt);
-
+#endif /* ODBCVER */
    /* save the last_fetch_count */
    int     last_fetch = stmt->last_fetch_count;
    int     last_fetch2 = stmt->last_fetch_count_include_ommitted;
    int     bind_save = stmt->bind_row;
+   BOOL        tuple_reload = FALSE;
 
-#ifdef DRIVER_CURSOR_IMPLEMENT
    if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
-       SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
+       tuple_reload = TRUE;
+   else 
+   {
+       QResultClass    *res = SC_get_Curres(stmt);
+       if (res && res->keyset)
+       {
+           Int4 kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
+           if (kres_ridx >= 0 && kres_ridx < (Int4)QR_get_num_cached_tuples(res))
+           {
+               if (0 != (CURS_NEEDS_REREAD & res->keyset[kres_ridx].status))
+                   tuple_reload = TRUE;
+           }
+       }
+   }
+   if (tuple_reload)
+       SC_pos_reload(stmt, global_ridx, (UWORD *) 0, 0);
    stmt->bind_row = irow;
    ret = SC_fetch(stmt);
    /* restore the last_fetch_count */
    stmt->last_fetch_count = last_fetch;
    stmt->last_fetch_count_include_ommitted = last_fetch2;
    stmt->bind_row = bind_save;
-
+#if (ODBCVER >= 0x0300)
    if (irdflds->rowStatusArray)
    {
        switch (ret)
@@ -2921,6 +4234,7 @@ SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx)
                break;
        }
    }
+#endif /* ODBCVER */
 
    return SQL_SUCCESS;
 }
@@ -2942,7 +4256,8 @@ RETCODE spos_callback(RETCODE retcode, void *para)
    RETCODE ret;
    spos_cdata *s = (spos_cdata *) para;
    ConnectionClass *conn;
-   UDWORD  global_ridx;
+   SQLULEN global_ridx;
+   Int4    kres_ridx, pos_ridx;
 
    ret = retcode;
    if (s->need_data_callback)
@@ -2966,15 +4281,19 @@ RETCODE spos_callback(RETCODE retcode, void *para)
        global_ridx = RowIdx2GIdx(s->idx, s->stmt);
        if (SQL_ADD != s->fOption)
        {
-           if ((int) global_ridx >= s->res->num_total_rows)
+           if ((int) global_ridx >= QR_get_num_total_tuples(s->res))
                break;
-#ifdef DRIVER_CURSOR_IMPLEMENT
-           if (s->res->keyset) /* the row may be deleted and not in the rowset */
+           if (s->res->keyset)
            {
-               if (0 == (s->res->keyset[global_ridx].status & CURS_IN_ROWSET))
-                   continue;
+               kres_ridx = GIdx2KResIdx(global_ridx, s->stmt, s->res);
+               if (kres_ridx >= (Int4)s->res->num_cached_keys)
+                   break;
+               if (kres_ridx >= 0) /* the row may be deleted and not in the rowset */
+               {
+                   if (0 == (s->res->keyset[kres_ridx].status & CURS_IN_ROWSET))
+                       continue;
+               }
            }
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
        }
        if (s->nrow < s->start_row)
        {
@@ -2982,12 +4301,13 @@ RETCODE spos_callback(RETCODE retcode, void *para)
            continue;
        }   
        s->ridx = s->nrow;
-
+       pos_ridx = s->idx;
+#if (ODBCVER >= 0x0300)
        if (0 != s->irow || !s->opts->row_operation_ptr || s->opts->row_operation_ptr[s->nrow] == SQL_ROW_PROCEED)
        {
+#endif /* ODBCVER */
            switch (s->fOption)
            {
-#ifdef DRIVER_CURSOR_IMPLEMENT
                case SQL_UPDATE:
                    ret = SC_pos_update(s->stmt, s->nrow, global_ridx);
                    break;
@@ -2997,7 +4317,6 @@ RETCODE spos_callback(RETCODE retcode, void *para)
                case SQL_ADD:
                    ret = SC_pos_add(s->stmt, s->nrow);
                    break;
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
                case SQL_REFRESH:
                    ret = SC_pos_refresh(s->stmt, s->nrow, global_ridx);
                    break;
@@ -3012,26 +4331,36 @@ RETCODE spos_callback(RETCODE retcode, void *para)
                return ret;
            }
            s->processed++;
+#if (ODBCVER >= 0x0300)
        }
+#endif /* ODBCVER */
        if (SQL_ERROR != ret)
            s->nrow++;
    }
    conn = SC_get_conn(s->stmt);
+#ifdef _LEGACY_MODE_
    if (SQL_ERROR == ret)
        CC_abort(conn);
+#endif /* _LEGACY_MODE_ */
    if (s->auto_commit_needed)
-       PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_ON);
+       PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
    if (s->irow > 0)
    {
        if (SQL_ADD != s->fOption && s->ridx >= 0) /* for SQLGetData */
-       { 
-           s->stmt->currTuple = RowIdx2GIdx(s->ridx, s->stmt);
-           QR_set_position(s->res, s->ridx);
+       {
+           s->stmt->currTuple = RowIdx2GIdx(pos_ridx, s->stmt);
+           QR_set_position(s->res, pos_ridx);
        }
    }
    else if (SC_get_IRDF(s->stmt)->rowsFetched)
        *(SC_get_IRDF(s->stmt)->rowsFetched) = s->processed;
    s->res->recent_processed_row_count = s->stmt->diag_row_count = s->processed;
+inolog("processed=%d ret=%d rowset=%d", s->processed, ret, s->opts->size_of_rowset_odbc2);
+#if (ODBCVER >= 0x0300)
+inolog(",%d\n", s->opts->size_of_rowset);
+#else
+inolog("\n");
+#endif /* ODBCVER */
    return ret;
 }
  
@@ -3042,15 +4371,13 @@ RETCODE spos_callback(RETCODE retcode, void *para)
 RETCODE        SQL_API
 PGAPI_SetPos(
             HSTMT hstmt,
-            UWORD irow,
-            UWORD fOption,
-            UWORD fLock)
+            SQLSETPOSIROW irow,
+            SQLUSMALLINT fOption,
+            SQLUSMALLINT fLock)
 {
    CSTR func = "PGAPI_SetPos";
    RETCODE ret;
-#ifdef DRIVER_CURSOR_IMPLEMENT
-    ConnectionClass *conn;
-#endif
+   ConnectionClass *conn;
    int     num_cols, i, rowsetSize;
    GetDataClass    *gdata = NULL;
    spos_cdata  s;
@@ -3067,34 +4394,31 @@ PGAPI_SetPos(
    s.auto_commit_needed = FALSE;
    s.opts = SC_get_ARDF(s.stmt);
    gdata = SC_get_GDTI(s.stmt)->gdata;
-#ifdef DRIVER_CURSOR_IMPLEMENT
    mylog("%s fOption=%d irow=%d lock=%d currt=%d\n", func, s.fOption, s.irow, fLock, s.stmt->currTuple);
    if (s.stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
        ;
-   else
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
-   if (s.fOption != SQL_POSITION && s.fOption != SQL_REFRESH)
+   else if (s.fOption != SQL_POSITION && s.fOption != SQL_REFRESH)
    {
-       SC_set_error(s.stmt, STMT_NOT_IMPLEMENTED_ERROR, "Only SQL_POSITION/REFRESH is supported for PGAPI_SetPos");
-       SC_log_error(func, "", s.stmt);
+       SC_set_error(s.stmt, STMT_NOT_IMPLEMENTED_ERROR, "Only SQL_POSITION/REFRESH is supported for PGAPI_SetPos", func);
        return SQL_ERROR;
    }
 
    if (!(s.res = SC_get_Curres(s.stmt)))
    {
-       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_SetPos.");
-       SC_log_error(func, "", s.stmt);
+       SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_SetPos.", func);
        return SQL_ERROR;
    }
 
+#if (ODBCVER >= 0x0300)
    rowsetSize = (s.stmt->transition_status == 7 ? s.opts->size_of_rowset_odbc2 : s.opts->size_of_rowset);
-
+#else
+   rowsetSize = s.opts->size_of_rowset_odbc2;
+#endif /* ODBCVER */
    if (s.irow == 0) /* bulk operation */
    {
        if (SQL_POSITION == s.fOption)
        {
-           SC_set_error(s.stmt, STMT_INVALID_CURSOR_POSITION, "Bulk Position operations not allowed.");
-           SC_log_error(func, "", s.stmt);
+           SC_set_error(s.stmt, STMT_INVALID_CURSOR_POSITION, "Bulk Position operations not allowed.", func);
            return SQL_ERROR;
        }
        s.start_row = 0;
@@ -3104,12 +4428,10 @@ PGAPI_SetPos(
    {
        if (SQL_ADD != s.fOption && s.irow > s.stmt->last_fetch_count)
        {
-           SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "Row value out of range");
-           SC_log_error(func, "", s.stmt);
+           SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "Row value out of range", func);
            return SQL_ERROR;
        }
        s.start_row = s.end_row = s.irow - 1;
-       s.stmt->currTuple = s.stmt->rowset_start + irow - 1;
    }
 
    num_cols = QR_NumResultCols(s.res);
@@ -3118,7 +4440,6 @@ PGAPI_SetPos(
        for (i = 0; i < num_cols; i++)
            gdata[i].data_left = -1;
    ret = SQL_SUCCESS;
-#ifdef DRIVER_CURSOR_IMPLEMENT
    conn = SC_get_conn(s.stmt);
    switch (s.fOption)
    {
@@ -3126,13 +4447,21 @@ PGAPI_SetPos(
        case SQL_DELETE:
        case SQL_ADD:
            if (s.auto_commit_needed = CC_is_in_autocommit(conn), s.auto_commit_needed)
-               PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_OFF);
+               PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
+           break;
+       case SQL_POSITION:
            break;
    }
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
 
    s.need_data_callback = FALSE;
-   return spos_callback(SQL_SUCCESS, &s);
+#define    return  DONT_CALL_RETURN_FROM_HERE???
+   /* StartRollbackState(s.stmt); */
+   ret = spos_callback(SQL_SUCCESS, &s);
+#undef return
+   if (s.stmt->internal)
+       ret = DiscardStatementSvp(s.stmt, ret, FALSE);
+   return ret;
+
 #ifdef NOT_USED
    ridx = -1;
    for (i = nrow = 0, processed = 0; nrow <= end_row; i++)
@@ -3142,13 +4471,11 @@ PGAPI_SetPos(
        {
            if ((int) global_ridx >= res->num_total_rows)
                break;
-#ifdef DRIVER_CURSOR_IMPLEMENT
            if (res->keyset) /* the row may be deleted and not in the rowset */
            {
-               if (0 == (res->keyset[global_ridx].status & CURS_IN_ROWSET))
+               if (0 == (res->keyset[kres_ridx].status & CURS_IN_ROWSET))
                    continue;
            }
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
        }
        if (nrow < start_row)
        {
@@ -3156,12 +4483,12 @@ PGAPI_SetPos(
            continue;
        }
        ridx = nrow;
-       
+#if (ODBCVER >= 0x0300)
        if (0 != irow || !opts->row_operation_ptr || opts->row_operation_ptr[nrow] == SQL_ROW_PROCEED)
        {
+#endif /* ODBCVER */
            switch (fOption)
            {
-#ifdef DRIVER_CURSOR_IMPLEMENT
                case SQL_UPDATE:
                    ret = SC_pos_update(stmt, nrow, global_ridx);
                    break;
@@ -3171,7 +4498,6 @@ PGAPI_SetPos(
                case SQL_ADD:
                    ret = SC_pos_add(stmt, nrow);
                    break;
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
                case SQL_REFRESH:
                    ret = SC_pos_refresh(stmt, nrow, global_ridx);
                    break;
@@ -3181,13 +4507,17 @@ PGAPI_SetPos(
            processed++;
            if (SQL_ERROR == ret)
                break;
+#if (ODBCVER >= 0x0300)
        }
+#endif /* ODBCVER */
        nrow++;
    }
+#ifdef _LEGACY_MODE_
    if (SQL_ERROR == ret)
        CC_abort(conn);
+#endif /* _LEGACY_MODE_ */
    if (auto_commit_needed)
-       PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_ON);
+       PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
    if (irow > 0)
    {
        if (SQL_ADD != fOption && ridx >= 0) /* for SQLGetData */
@@ -3199,6 +4529,7 @@ PGAPI_SetPos(
    else if (SC_get_IRDF(stmt)->rowsFetched)
        *(SC_get_IRDF(stmt)->rowsFetched) = processed;
    res->recent_processed_row_count = stmt->diag_row_count = processed;
+inolog("rowset=%d processed=%d ret=%d\n", opts->rowset_size, processed, ret);
    return ret;
 #endif /* NOT_USED */ 
 }
@@ -3207,18 +4538,17 @@ PGAPI_SetPos(
 /*     Sets options that control the behavior of cursors. */
 RETCODE        SQL_API
 PGAPI_SetScrollOptions( HSTMT hstmt,
-               UWORD fConcurrency,
-               SDWORD crowKeyset,
-               UWORD crowRowset)
+               SQLUSMALLINT fConcurrency,
+               SQLLEN crowKeyset,
+               SQLUSMALLINT crowRowset)
 {
    CSTR func = "PGAPI_SetScrollOptions";
    StatementClass *stmt = (StatementClass *) hstmt;
 
    mylog("PGAPI_SetScrollOptions fConcurrency=%d crowKeyset=%d crowRowset=%d\n",
          fConcurrency, crowKeyset, crowRowset);
-   SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "SetScroll option not implemeted");
+   SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "SetScroll option not implemeted", func);
 
-   SC_log_error(func, "Function not implemented", hstmt);
    return SQL_ERROR;
 }
 
@@ -3226,15 +4556,15 @@ PGAPI_SetScrollOptions( HSTMT hstmt,
 /* Set the cursor name on a statement handle */
 RETCODE        SQL_API
 PGAPI_SetCursorName(
-                   HSTMT hstmt,
-                   UCHAR FAR * szCursor,
-                   SWORD cbCursor)
+               HSTMT hstmt,
+               const SQLCHAR FAR * szCursor,
+               SQLSMALLINT cbCursor)
 {
    CSTR func = "PGAPI_SetCursorName";
    StatementClass *stmt = (StatementClass *) hstmt;
    int         len;
 
-   mylog("PGAPI_SetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d\n", hstmt, szCursor, cbCursor);
+   mylog("PGAPI_SetCursorName: hstmt=%x, szCursor=%x, cbCursorMax=%d\n", hstmt, szCursor, cbCursor);
 
    if (!stmt)
    {
@@ -3244,14 +4574,7 @@ PGAPI_SetCursorName(
 
    len = (cbCursor == SQL_NTS) ? strlen(szCursor) : cbCursor;
 
-   if (len <= 0 || len > sizeof(stmt->cursor_name) - 1)
-   {
-       SC_set_error(stmt, STMT_INVALID_CURSOR_NAME, "Invalid Cursor Name");
-       SC_log_error(func, "", stmt);
-       return SQL_ERROR;
-   }
-
-   strncpy_null(stmt->cursor_name, szCursor, len + 1);
+   SET_NAME(stmt->cursor_name, make_string(szCursor, cbCursor, NULL, 0));
    return SQL_SUCCESS;
 }
 
@@ -3260,46 +4583,43 @@ PGAPI_SetCursorName(
 RETCODE        SQL_API
 PGAPI_GetCursorName(
                    HSTMT hstmt,
-                   UCHAR FAR * szCursor,
-                   SWORD cbCursorMax,
-                   SWORD FAR * pcbCursor)
+                   SQLCHAR FAR * szCursor,
+                   SQLSMALLINT cbCursorMax,
+                   SQLSMALLINT FAR * pcbCursor)
 {
    CSTR func = "PGAPI_GetCursorName";
    StatementClass *stmt = (StatementClass *) hstmt;
    int         len = 0;
    RETCODE     result;
 
-   mylog("PGAPI_GetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d, pcbCursor=%u\n", hstmt, szCursor, cbCursorMax, pcbCursor);
+   mylog("PGAPI_GetCursorName: hstmt=%x, szCursor=%x, cbCursorMax=%d, pcbCursor=%x\n", hstmt, szCursor, cbCursorMax, pcbCursor);
 
    if (!stmt)
    {
        SC_log_error(func, "", NULL);
        return SQL_INVALID_HANDLE;
    }
-
-   if (stmt->cursor_name[0] == '\0')
-   {
-       SC_set_error(stmt, STMT_NO_CURSOR_NAME, "No Cursor name available");
-       SC_log_error(func, "", stmt);
-       return SQL_ERROR;
-   }
-
    result = SQL_SUCCESS;
-   len = strlen(stmt->cursor_name);
+   len = strlen(SC_cursor_name(stmt));
 
    if (szCursor)
    {
-       strncpy_null(szCursor, stmt->cursor_name, cbCursorMax);
+       strncpy_null(szCursor, SC_cursor_name(stmt), cbCursorMax);
 
        if (len >= cbCursorMax)
        {
            result = SQL_SUCCESS_WITH_INFO;
-           SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetCursorName.");
+           SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetCursorName.", func);
        }
    }
 
    if (pcbCursor)
        *pcbCursor = len;
 
+   /*
+    * Because this function causes no db-access, there's
+    * no need to call DiscardStatementSvp()
+    */
+
    return result;
 }
diff --git a/setup.c b/setup.c
index 2be6aec8989a55e436ceb13f435055b8cb0f9af6..6cc3abe780c7b796f6d41cebd1c8d8ba1551035a 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -14,6 +14,7 @@
  */
 
 #include  "psqlodbc.h"
+
 #include  "connection.h"
 #include  <windowsx.h>
 #include  <string.h>
@@ -31,7 +32,7 @@ extern GLOBAL_VALUES  globals;
 /* Constants */
 #define MIN(x,y)     ((x) < (y) ? (x) : (y))
 
-#define MAXKEYLEN      (21+1)  /* Max keyword length */
+#define MAXKEYLEN      (32+1)  /* Max keyword length */
 #define MAXDESC            (255+1) /* Max description length */
 #define MAXDSNAME      (32+1)  /* Max data source name length */
 
@@ -305,6 +306,14 @@ ConfigDlgProc(HWND hdlg,
                    return TRUE;
            }
            break;
+       case WM_CTLCOLORSTATIC:
+           if (lParam == (LPARAM)GetDlgItem(hdlg, IDC_NOTICE_USER))
+           {
+               HBRUSH hBrush = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
+               SetTextColor((HDC)wParam, RGB(255, 0, 0));
+               return (long)hBrush;
+           }
+           break;
    }
 
    /* Message not processed */
@@ -345,7 +354,7 @@ ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg)
            else if (*lpsz == '=')
                break;          /* Valid key found */
        }
-       /* Determine the key */
+       /* Determine the key's index in the key table (-1 if not found) */
        cbKey = lpsz - lpszStart;
        if (cbKey < sizeof(aszKey))
        {
@@ -353,15 +362,13 @@ ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg)
            aszKey[cbKey] = '\0';
        }
 
-       /* Locate end of key value - added support for delimiter ; */
+       /* Locate end of key value */
        lpszStart = ++lpsz;
-       for (; *lpsz && *lpsz != ';'; lpsz++)
+       for (; *lpsz; lpsz++)
            ;
 
-       /* Determine the value */
-       cbKey = MIN(lpsz - lpszStart, MAXPGPATH);
-       _fmemcpy(value, lpszStart, cbKey);
-       value[cbKey] = '\0';
+       /* lpsetupdlg->aAttr[iElement].fSupplied = TRUE; */
+       _fmemcpy(value, lpszStart, MIN(lpsz - lpszStart + 1, MAXPGPATH));
 
        mylog("aszKey='%s', value='%s'\n", aszKey, value);
 
@@ -400,8 +407,9 @@ SetDSNAttributes(HWND hwndParent, LPSETUPDLG lpsetupdlg, DWORD *errcode)
        DWORD   err = SQL_ERROR;
        char    szMsg[SQL_MAX_MESSAGE_LENGTH];
 
+#if (ODBCVER >= 0x0300)
        ret = SQLInstallerError(1, &err, szMsg, sizeof(szMsg), NULL);
-
+#endif /* ODBCVER */
        if (hwndParent)
        {
            char        szBuf[MAXPGPATH];
diff --git a/socket.c b/socket.c
new file mode 100644 (file)
index 0000000..e11c393
--- /dev/null
+++ b/socket.c
@@ -0,0 +1,668 @@
+/*-------
+ * Module:         socket.c
+ *
+ * Description:        This module contains functions for low level socket
+ *                 operations (connecting/reading/writing to the backend)
+ *
+ * Classes:            SocketClass (Functions prefix: "SOCK_")
+ *
+ * API functions:  none
+ *
+ * Comments:       See "notice.txt" for copyright and license information.
+ *-------
+ */
+
+#include "socket.h"
+#include "loadlib.h"
+
+#include "connection.h"
+
+#ifndef WIN32
+#include <stdlib.h>
+#include <string.h>                /* for memset */
+#if defined(TM_IN_SYS_TIME)
+#include <sys/time.h>
+#endif /* defined(TM_IN_SYS_TIME) */
+#endif /* WIN32 */
+
+extern GLOBAL_VALUES globals;
+
+#define    SOCK_set_error(s, _no, _msg)    (s->errornumber = _no, s->errormsg = _msg, mylog("socket error=%d %s\n", _no, _msg))
+
+void
+SOCK_clear_error(SocketClass *self)
+{
+   self->errornumber = 0;
+   self->errormsg = NULL;
+}
+
+
+SocketClass *
+SOCK_Constructor(const ConnectionClass *conn)
+{
+   SocketClass *rv;
+
+   rv = (SocketClass *) malloc(sizeof(SocketClass));
+
+   if (rv != NULL)
+   {
+       rv->socket = (SOCKETFD) -1;
+       rv->via_libpq = FALSE;
+       rv->ssl = NULL;
+       rv->pqconn = NULL;
+       rv->pversion = 0;
+       rv->reslen = 0;
+       rv->buffer_filled_in = 0;
+       rv->buffer_filled_out = 0;
+       rv->buffer_read_in = 0;
+
+       if (rv)
+           rv->buffer_size = conn->connInfo.drivers.socket_buffersize;
+       else
+           rv->buffer_size = globals.socket_buffersize;
+       rv->buffer_in = (UCHAR *) malloc(rv->buffer_size);
+       if (!rv->buffer_in)
+       {
+           free(rv);
+           return NULL;
+       }
+
+       rv->buffer_out = (UCHAR *) malloc(rv->buffer_size);
+       if (!rv->buffer_out)
+       {
+           free(rv->buffer_in);
+           free(rv);
+           return NULL;
+       }
+       rv->sadr = NULL;
+       rv->errormsg = NULL;
+       rv->errornumber = 0;
+       rv->reverse = FALSE;
+   }
+   return rv;
+}
+
+
+void
+SOCK_Destructor(SocketClass *self)
+{
+   mylog("SOCK_Destructor\n");
+   if (!self)
+       return;
+   if (self->socket != -1)
+   {
+       if (self->pqconn)
+       {
+           if (self->via_libpq)
+           {
+               if (self->pqconn)
+                   PQfinish(self->pqconn);
+               UnloadDelayLoadedDLLs(NULL != self->ssl);
+           }
+           self->via_libpq = FALSE;
+           self->pqconn = NULL;
+           self->ssl = NULL;
+       }
+       else
+       {
+           SOCK_put_char(self, 'X');
+           if (PG_PROTOCOL_74 == self->pversion)
+               SOCK_put_int(self, 4, 4);
+           SOCK_flush_output(self);
+           closesocket(self->socket);
+       }
+   }
+
+   if (self->buffer_in)
+       free(self->buffer_in);
+
+   if (self->buffer_out)
+       free(self->buffer_out);
+   if (self->sadr && self->sadr != (struct sockaddr *) &(self->sadr_in))
+       free(self->sadr);
+
+   free(self);
+}
+
+
+char
+SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
+{
+#if defined (POSIX_MULTITHREAD_SUPPORT)
+   const int bufsz = 8192; 
+   char buf[bufsz];
+   int error = 0;
+   struct hostent host;
+   struct hostent* hp = &host;
+#else
+   struct hostent* hp;
+#endif /* POSIX_MULTITHREAD_SUPPORT */
+   struct sockaddr_in *in;
+#ifdef HAVE_UNIX_SOCKETS
+   struct sockaddr_un *un;
+#endif /* HAVE_UNIX_SOCKETS */
+   int family, sLen; 
+   unsigned long iaddr;
+
+   if (self->socket != -1)
+   {
+       SOCK_set_error(self, SOCKET_ALREADY_CONNECTED, "Socket is already connected");
+       return 0;
+   }
+
+
+   /*
+    * If it is a valid IP address, use it. Otherwise use hostname lookup.
+    */
+   if (hostname && hostname[0])
+   {
+       iaddr = inet_addr(hostname);
+       memset((char *) &(self->sadr_in), 0, sizeof(self->sadr_in));
+       in = &(self->sadr_in);
+       in->sin_family = family = AF_INET;
+       in->sin_port = htons(port);
+       sLen = sizeof(self->sadr_in);
+       if (iaddr == INADDR_NONE)
+       {
+#if defined (POSIX_MULTITHREAD_SUPPORT) 
+  #if defined (HAVE_GETIPNODEBYNAME) /* Free-BSD ? */
+           hp = getipnodebyname(hostname, AF_INET, 0, &error); 
+  #elif defined (PGS_REENTRANT_API_1) /* solaris, irix */
+           hp = gethostbyname_r(hostname, hp, buf, bufsz, &error);
+  #elif defined (PGS_REENTRANT_API_2) /* linux */
+           int result = 0;
+           result = gethostbyname_r(hostname, hp, buf, bufsz, &hp, &error);
+           if (result)
+               hp = NULL;
+  #else
+           hp = gethostbyname(hostname);
+  #endif /* HAVE_GETIPNODEBYNAME */
+#else
+           hp = gethostbyname(hostname);
+#endif /* POSIX_MULTITHREAD_SUPPORT */
+           if (hp == NULL)
+           {
+               SOCK_set_error(self, SOCKET_HOST_NOT_FOUND, "Could not resolve hostname.");
+               return 0;
+           }
+           memcpy(&(in->sin_addr), hp->h_addr, hp->h_length);
+#if defined (HAVE_GETIPNODEBYNAME)
+           freehostent(hp);
+#endif /* HAVE_GETIPNODEBYNAME */
+       }
+       else
+           memcpy(&(in->sin_addr), (struct in_addr *) & iaddr, sizeof(iaddr));
+       self->sadr = (struct sockaddr *) in;
+   }
+   else
+#ifdef HAVE_UNIX_SOCKETS
+   {
+       un = (struct sockaddr_un *) malloc(sizeof(struct sockaddr_un));
+       if (!un)
+       {
+           SOCK_set_error(self, SOCKET_COULD_NOT_CREATE_SOCKET, "coulnd't allocate memory for un.");
+           return 0;
+       }
+       un->sun_family = family = AF_UNIX;
+       /* passing NULL means that this only suports the pg default "/tmp" */
+       UNIXSOCK_PATH(un, port, ((char *) NULL));
+       sLen = UNIXSOCK_LEN(un);
+       self->sadr = (struct sockaddr *) un;
+   }
+#else
+   {
+       SOCK_set_error(self, SOCKET_HOST_NOT_FOUND, "Hostname isn't specified.");
+       return 0;
+   }
+#endif /* HAVE_UNIX_SOCKETS */
+
+   self->socket = socket(family, SOCK_STREAM, 0);
+   if (self->socket == -1)
+   {
+       SOCK_set_error(self, SOCKET_COULD_NOT_CREATE_SOCKET, "Could not create Socket.");
+       return 0;
+   }
+#ifdef TCP_NODELAY
+   if (family == AF_INET)
+   {
+       int i, len;
+
+       i = 1;
+       len = sizeof(i);
+       if (setsockopt(self->socket, IPPROTO_TCP, TCP_NODELAY, (char *) &i, len) < 0)
+       {
+           SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not set socket to NODELAY.");
+           closesocket(self->socket);
+           self->socket = (SOCKETFD) -1;
+           return 0;
+       }
+   }
+#endif /* TCP_NODELAY */
+
+   self->sadr_len = sLen;
+   if (connect(self->socket, self->sadr, sLen) < 0)
+   {
+       SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect to remote socket.");
+       closesocket(self->socket);
+       self->socket = (SOCKETFD) -1;
+       return 0;
+   }
+
+   return 1;
+}
+
+
+/*
+ * To handle EWOULDBLOCK etc (mainly for libpq non-blocking connection).
+ */
+#define    MAX_RETRY_COUNT 8
+static int SOCK_wait_for_ready(SocketClass *sock, BOOL output, int retry_count)
+{
+   int ret;
+   fd_set  fds;
+   struct  timeval tm;
+
+   do {
+       FD_ZERO(&fds);
+       FD_SET(sock->socket, &fds);
+       if (!output && sock->ssl)
+       {
+           tm.tv_sec = retry_count;
+           tm.tv_usec = 0;
+       }
+       ret = select(1, output ? NULL : &fds, output ? &fds : NULL, NULL, sock->ssl ? &tm : NULL);
+   } while (ret < 0 && EINTR == SOCK_ERRNO);
+   if (0 == ret && retry_count > MAX_RETRY_COUNT)
+   {
+       ret = -1;
+       SOCK_set_error(sock, output ? SOCKET_WRITE_TIMEOUT : SOCKET_READ_TIMEOUT, "SOCK_wait_for_ready timeout");
+   }
+   return ret;
+}
+/*
+ * The stuff for SSL.
+ */
+/* #include <openssl/ssl.h>*/
+#define SSL_ERROR_NONE         0
+#define SSL_ERROR_SSL          1
+#define SSL_ERROR_WANT_READ        2
+#define SSL_ERROR_WANT_WRITE       3
+#define SSL_ERROR_WANT_X509_LOOKUP 4
+#define SSL_ERROR_SYSCALL      5 /* look at error stack/return value/errno */
+#define SSL_ERROR_ZERO_RETURN      6
+#define SSL_ERROR_WANT_CONNECT     7
+#define SSL_ERROR_WANT_ACCEPT      8
+/*
+ * recv more than 1 bytes using SSL.
+ */
+static int SOCK_SSL_recv(SocketClass *sock, void *buffer, int len)
+{
+   CSTR    func = "SOCK_SSL_recv";
+   int n, err, retry_count = 0;
+
+retry:
+   n = SSL_read(sock->ssl, buffer, len);
+   err = SSL_get_error(sock->ssl, len);
+inolog("%s: %d get_error=%d Lasterror=%d\n", func, n, err, SOCK_ERRNO);
+   switch (err)
+   {
+       case    SSL_ERROR_NONE:
+           break;
+       case    SSL_ERROR_WANT_READ:
+           retry_count++;
+           if (SOCK_wait_for_ready(sock, FALSE, retry_count) >= 0)
+               goto retry;
+           n = -1;
+           break;
+       case    SSL_ERROR_WANT_WRITE:
+           goto retry;
+           break;
+       case    SSL_ERROR_SYSCALL:
+           if (-1 != n)
+           {
+               n = -1;
+               SOCK_ERRNO_SET(ECONNRESET);
+           }
+           break;
+       case    SSL_ERROR_SSL:
+       case    SSL_ERROR_ZERO_RETURN:
+           n = -1;
+           SOCK_ERRNO_SET(ECONNRESET);
+           break;
+       default:
+           n = -1;
+   }
+
+   return n;
+}
+
+/*
+ * send more than 1 bytes using SSL.
+ */
+static int SOCK_SSL_send(SocketClass *sock, void *buffer, int len)
+{
+   CSTR    func = "SOCK_SSL_send";
+   int n, err, retry_count = 0;
+
+retry:
+   n = SSL_write(sock->ssl, buffer, len);
+   err = SSL_get_error(sock->ssl, len);
+inolog("%s: %d get_error=%d Lasterror=%d\n", func,  n, err, SOCK_ERRNO);
+   switch (err)
+   {
+       case    SSL_ERROR_NONE:
+           break;
+       case    SSL_ERROR_WANT_READ:
+       case    SSL_ERROR_WANT_WRITE:
+           retry_count++;
+           if (SOCK_wait_for_ready(sock, TRUE, retry_count) >= 0)
+               goto retry;
+           n = -1;
+           break;
+       case    SSL_ERROR_SYSCALL:
+           if (-1 != n)
+           {
+               n = -1;
+               SOCK_ERRNO_SET(ECONNRESET);
+           }
+           break;
+       case    SSL_ERROR_SSL:
+       case    SSL_ERROR_ZERO_RETURN:
+           n = -1;
+           SOCK_ERRNO_SET(ECONNRESET);
+           break;
+       default:
+           n = -1;
+   }
+
+   return n;
+}
+
+
+int
+SOCK_get_id(SocketClass *self)
+{
+   int id;
+
+   if (self->reslen > 0)
+   {
+       mylog("SOCK_get_id has to eat %d bytes\n", self->reslen);
+       do
+       {
+           SOCK_get_next_byte(self);
+       } while (self->reslen > 0);
+   }
+   id = SOCK_get_next_byte(self);
+   self->reslen = 0;
+   return id;
+}
+
+void
+SOCK_get_n_char(SocketClass *self, char *buffer, int len)
+{
+   int         lf;
+
+   if (!self)
+       return;
+   if (!buffer)
+   {
+       SOCK_set_error(self, SOCKET_NULLPOINTER_PARAMETER, "get_n_char was called with NULL-Pointer");
+       return;
+   }
+
+   for (lf = 0; lf < len; lf++)
+       buffer[lf] = SOCK_get_next_byte(self);
+}
+
+
+void
+SOCK_put_n_char(SocketClass *self, char *buffer, int len)
+{
+   int         lf;
+
+   if (!self)
+       return;
+   if (!buffer)
+   {
+       SOCK_set_error(self, SOCKET_NULLPOINTER_PARAMETER, "put_n_char was called with NULL-Pointer");
+       return;
+   }
+
+   for (lf = 0; lf < len; lf++)
+       SOCK_put_next_byte(self, (UCHAR) buffer[lf]);
+}
+
+
+/*
+ * bufsize must include room for the null terminator
+ * will read at most bufsize-1 characters + null.
+ * returns TRUE if truncation occurs.
+ */
+BOOL
+SOCK_get_string(SocketClass *self, char *buffer, int bufsize)
+{
+   register int lf = 0;
+
+   for (lf = 0; lf < bufsize - 1; lf++)
+       if (!(buffer[lf] = SOCK_get_next_byte(self)))
+           return FALSE;
+
+   buffer[bufsize - 1] = '\0';
+   return TRUE;
+}
+
+
+void
+SOCK_put_string(SocketClass *self, const char *string)
+{
+   register int lf;
+   int         len;
+
+   len = strlen(string) + 1;
+
+   for (lf = 0; lf < len; lf++)
+       SOCK_put_next_byte(self, (UCHAR) string[lf]);
+}
+
+
+int
+SOCK_get_int(SocketClass *self, short len)
+{
+   if (!self)
+       return 0;
+   switch (len)
+   {
+       case 2:
+           {
+               unsigned short buf;
+
+               SOCK_get_n_char(self, (char *) &buf, len);
+               if (self->reverse)
+                   return buf;
+               else
+                   return ntohs(buf);
+           }
+
+       case 4:
+           {
+               unsigned int buf;
+
+               SOCK_get_n_char(self, (char *) &buf, len);
+               if (self->reverse)
+                   return buf;
+               else
+                   return ntohl(buf);
+           }
+
+       default:
+           SOCK_set_error(self, SOCKET_GET_INT_WRONG_LENGTH, "Cannot read ints of that length");
+           return 0;
+   }
+}
+
+
+void
+SOCK_put_int(SocketClass *self, int value, short len)
+{
+   unsigned int rv;
+
+   if (!self)
+       return;
+   switch (len)
+   {
+       case 2:
+           rv = self->reverse ? value : htons((unsigned short) value);
+           SOCK_put_n_char(self, (char *) &rv, 2);
+           return;
+
+       case 4:
+           rv = self->reverse ? value : htonl((unsigned int) value);
+           SOCK_put_n_char(self, (char *) &rv, 4);
+           return;
+
+       default:
+           SOCK_set_error(self, SOCKET_PUT_INT_WRONG_LENGTH, "Cannot write ints of that length");
+           return;
+   }
+}
+
+
+void
+SOCK_flush_output(SocketClass *self)
+{
+   int written, pos = 0, retry_count = 0;
+
+   if (!self)
+       return;
+   do
+   {
+       if (self->ssl)
+           written = SOCK_SSL_send(self, (char *) self->buffer_out + pos, self->buffer_filled_out);
+       else
+           written = send(self->socket, (char *) self->buffer_out + pos, self->buffer_filled_out, 0);
+       if (written < 0)
+       {
+           switch (SOCK_ERRNO)
+           {
+               case EINTR:
+                   continue;
+                   break;
+               case EWOULDBLOCK:
+                   retry_count++;
+                   if (SOCK_wait_for_ready(self, TRUE, retry_count) >= 0)
+                       continue;
+                   break;
+           }
+           SOCK_set_error(self, SOCKET_WRITE_ERROR, "Could not flush socket buffer.");
+           break;
+       }
+       pos += written;
+       self->buffer_filled_out -= written;
+   } while (self->buffer_filled_out > 0);
+}
+
+
+UCHAR
+SOCK_get_next_byte(SocketClass *self)
+{
+   int retry_count = 0;
+
+   if (!self)
+       return 0;
+   if (self->buffer_read_in >= self->buffer_filled_in)
+   {
+       /*
+        * there are no more bytes left in the buffer so reload the buffer
+        */
+       self->buffer_read_in = 0;
+retry:
+       if (self->ssl)
+           self->buffer_filled_in = SOCK_SSL_recv(self, (char *) self->buffer_in, self->buffer_size);
+       else
+           self->buffer_filled_in = recv(self->socket, (char *) self->buffer_in, self->buffer_size, 0);
+
+       mylog("read %d, global_socket_buffersize=%d\n", self->buffer_filled_in, self->buffer_size);
+
+       if (self->buffer_filled_in < 0)
+       {
+mylog("Lasterror=%d\n", SOCK_ERRNO);
+           switch (SOCK_ERRNO)
+           {
+               case    EINTR:
+                   goto retry;
+                   break;
+               case    EWOULDBLOCK:
+                   retry_count++;
+                   if (SOCK_wait_for_ready(self, FALSE, retry_count) >= 0)
+                       goto retry;
+                   break;
+           }
+           if (0 == self->errornumber)
+               SOCK_set_error(self, SOCKET_READ_ERROR, "Error while reading from the socket.");
+           self->buffer_filled_in = 0;
+           return 0;
+       }
+       if (self->buffer_filled_in == 0)
+       {
+           SOCK_set_error(self, SOCKET_CLOSED, "Socket has been closed.");
+           self->buffer_filled_in = 0;
+           return 0;
+       }
+   }
+   if (PG_PROTOCOL_74 == self->pversion)
+       self->reslen--;
+   return self->buffer_in[self->buffer_read_in++];
+}
+
+void
+SOCK_put_next_byte(SocketClass *self, UCHAR next_byte)
+{
+   int bytes_sent, pos = 0, retry_count = 0;
+
+   if (!self)
+       return;
+   self->buffer_out[self->buffer_filled_out++] = next_byte;
+
+   if (self->buffer_filled_out == self->buffer_size)
+   {
+       /* buffer is full, so write it out */
+       do
+       {
+           if (self->ssl)
+               bytes_sent = SOCK_SSL_send(self, (char *) self->buffer_out + pos, self->buffer_filled_out);
+           else
+               bytes_sent = send(self->socket, (char *) self->buffer_out + pos, self->buffer_filled_out, 0);
+           if (bytes_sent < 0)
+           {
+               switch (SOCK_ERRNO)
+               {
+                   case    EINTR:
+                       continue;
+                   case    EWOULDBLOCK:
+                       retry_count++;
+                       if (SOCK_wait_for_ready(self, TRUE, retry_count) >= 0)
+                           continue;
+               }
+               if (0 == self->errornumber)
+                   SOCK_set_error(self, SOCKET_WRITE_ERROR, "Error while writing to the socket.");
+               break;
+           }
+           pos += bytes_sent;
+           self->buffer_filled_out -= bytes_sent;
+       } while (self->buffer_filled_out > 0);
+   }
+}
+
+int
+SOCK_get_response_length(SocketClass *self)
+{
+   int     leng = -1;
+
+   if (PG_PROTOCOL_74 == self->pversion)
+   {
+       leng = SOCK_get_int(self, 4) - 4;
+       self->reslen = leng;
+   }
+
+   return leng;
+}
diff --git a/socket.h b/socket.h
new file mode 100644 (file)
index 0000000..30b8911
--- /dev/null
+++ b/socket.h
@@ -0,0 +1,155 @@
+/* File:           socket.h
+ *
+ * Description:        See "socket.c"
+ *
+ * Comments:       See "notice.txt" for copyright and license information.
+ *
+ */
+
+#ifndef __SOCKET_H__
+#define __SOCKET_H__
+
+#include "psqlodbc.h"
+#include <errno.h>
+
+#ifndef WIN32
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define closesocket(xxx) close(xxx)
+#define SOCKETFD int
+
+#ifndef          INADDR_NONE
+#ifndef _IN_ADDR_T
+#define _IN_ADDR_T
+typedef unsigned int in_addr_t;
+#endif /* _IN_ADDR_T */
+#define INADDR_NONE ((in_addr_t)-1)
+#endif /* _IN_ADDR_NONE */
+
+#define SOCK_ERRNO errno
+#define SOCK_ERRNO_SET(e)  (errno = e)
+#ifdef HAVE_SYS_UN_H
+#define HAVE_UNIX_SOCKETS
+#endif /* HAVE_SYS_UN_H */
+#else
+#include <winsock.h>
+#include <libpq-fe.h>
+#include <openssl/ssl.h>
+#define SOCKETFD SOCKET
+#define SOCK_ERRNO     (WSAGetLastError())
+#define SOCK_ERRNO_SET(e)  WSASetLastError(e)
+#ifndef    EWOULDBLOCK
+#define    EWOULDBLOCK WSAEWOULDBLOCK
+#endif /* EWOULDBLOCK */
+#ifndef    ECONNRESET
+#define    ECONNRESET  WSAECONNRESET
+#endif /* ECONNRESET */
+#endif /* WIN32 */
+
+#define SOCKET_ALREADY_CONNECTED       1
+#define SOCKET_HOST_NOT_FOUND          2
+#define SOCKET_COULD_NOT_CREATE_SOCKET     3
+#define SOCKET_COULD_NOT_CONNECT       4
+#define SOCKET_READ_ERROR          5
+#define SOCKET_WRITE_ERROR         6
+#define SOCKET_NULLPOINTER_PARAMETER       7
+#define SOCKET_PUT_INT_WRONG_LENGTH        8
+#define SOCKET_GET_INT_WRONG_LENGTH        9
+#define SOCKET_CLOSED              10
+#define SOCKET_READ_TIMEOUT            11
+#define SOCKET_WRITE_TIMEOUT           12
+
+
+struct SocketClass_
+{
+
+   int         buffer_size;
+   int         buffer_filled_in;
+   int         buffer_filled_out;
+   int         buffer_read_in;
+   UCHAR *buffer_in;
+   UCHAR *buffer_out;
+
+   SOCKETFD    socket;
+   unsigned int    pversion;
+   int     reslen;
+
+   char        *errormsg;
+   int     errornumber;
+   struct sockaddr *sadr; /* Used for handling connections for cancel */
+   int     sadr_len;
+   struct sockaddr_in sadr_in; /* Used for INET connections */
+   /* SSL stuff */
+   void        *ssl;       /* libpq ssl */
+   void        *pqconn;    /* libpq PGConn */
+   BOOL        via_libpq;  /* using libpq library ? */
+
+   char        reverse;        /* used to handle Postgres 6.2 protocol
+                                * (reverse byte order) */
+
+};
+
+#define SOCK_get_char(self)        (SOCK_get_next_byte(self))
+#define SOCK_put_char(self, c) (SOCK_put_next_byte(self, c))
+
+
+/* error functions */
+#define SOCK_get_errcode(self) (self ? self->errornumber : SOCKET_CLOSED)
+#define SOCK_get_errmsg(self)  (self ? self->errormsg : "socket closed")
+
+/*
+ * code taken from postgres libpq et al.
+ */
+#ifndef WIN32
+#define DEFAULT_PGSOCKET_DIR   "/tmp"
+#define UNIXSOCK_PATH(sun, port, defpath) \
+   snprintf((sun)->sun_path, sizeof((sun)->sun_path), "%s/.s.PGSQL.%d", \
+       ((defpath) && *(defpath) != '\0') ? (defpath) : \
+           DEFAULT_PGSOCKET_DIR, \
+           (port))
+
+/*
+ * We do this because sun_len is in BSD's struct, while others don't.
+ * We never actually set BSD's sun_len, and I can't think of a
+ * platform-safe way of doing it, but the code still works. bjm
+ */
+#ifndef    offsetof
+#define offsetof(type, field)  ((long) &((type *)0)->field)
+#endif /* offsetof */
+#if defined(SUN_LEN)
+#define UNIXSOCK_LEN(sun) SUN_LEN(sun)
+#else
+#define UNIXSOCK_LEN(sun) \
+   (strlen((sun)->sun_path) + offsetof(struct sockaddr_un, sun_path))
+#endif /* SUN_LEN */
+#endif /* WIN32 */
+/*
+ * END code taken from postgres libpq et al.
+ */
+
+
+/* Socket prototypes */
+SocketClass *SOCK_Constructor(const ConnectionClass *conn);
+void       SOCK_Destructor(SocketClass *self);
+char       SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname);
+int        SOCK_get_id(SocketClass *self);
+void       SOCK_get_n_char(SocketClass *self, char *buffer, int len);
+void       SOCK_put_n_char(SocketClass *self, char *buffer, int len);
+BOOL       SOCK_get_string(SocketClass *self, char *buffer, int bufsize);
+void       SOCK_put_string(SocketClass *self, const char *string);
+int            SOCK_get_int(SocketClass *self, short len);
+void       SOCK_put_int(SocketClass *self, int value, short len);
+void       SOCK_flush_output(SocketClass *self);
+UCHAR      SOCK_get_next_byte(SocketClass *self);
+void       SOCK_put_next_byte(SocketClass *self, UCHAR next_byte);
+int        SOCK_get_response_length(SocketClass *self);
+void       SOCK_clear_error(SocketClass *self);
+UInt4      SOCK_skip_n_bytes(SocketClass *self, UInt4 skip_length);
+
+#endif /* __SOCKET_H__ */
index ce115361a35632360d317421177e2e0903fd57fd..7d606610b57c2001df048de7ed29e0fa8f25ea2f 100644 (file)
  *-------
  */
 
+#ifndef    _WIN32_WINNT
+#define    _WIN32_WINNT    0x0400
+#endif /* _WIN32_WINNT */
+
 #include "statement.h"
+
 #include "bind.h"
 #include "connection.h"
 #include "qresult.h"
@@ -39,41 +44,113 @@ static struct
 {
    {
        STMT_TYPE_SELECT, "SELECT"
-   },
-   {
+   }
+   ,{
        STMT_TYPE_INSERT, "INSERT"
-   },
-   {
+   }
+   ,{
        STMT_TYPE_UPDATE, "UPDATE"
-   },
-   {
+   }
+   ,{
        STMT_TYPE_DELETE, "DELETE"
-   },
-   {
+   }
+   ,{
+       STMT_TYPE_PROCCALL, "{"
+   }
+   ,{
+       STMT_TYPE_SET, "SET"
+   }
+   ,{
+       STMT_TYPE_RESET, "RESET"
+   }
+   ,{
        STMT_TYPE_CREATE, "CREATE"
-   },
-   {
-       STMT_TYPE_ALTER, "ALTER"
-   },
-   {
+   }
+   ,{
+       STMT_TYPE_DECLARE, "DECLARE"
+   }
+   ,{
+       STMT_TYPE_FETCH, "FETCH"
+   }
+   ,{
+       STMT_TYPE_MOVE, "MOVE"
+   }
+   ,{
+       STMT_TYPE_CLOSE, "CLOSE"
+   }
+   ,{
+       STMT_TYPE_PREPARE, "PREPARE"
+   }
+   ,{
+       STMT_TYPE_EXECUTE, "EXECUTE"
+   }
+   ,{
+       STMT_TYPE_EXECUTE, "DEALLOCATE"
+   }
+   ,{
        STMT_TYPE_DROP, "DROP"
-   },
-   {
+   }
+   ,{
+       STMT_TYPE_START, "BEGIN"
+   }
+   ,{
+       STMT_TYPE_START, "START"
+   }
+   ,{
+       STMT_TYPE_TRANSACTION, "SAVEPOINT"
+   }
+   ,{
+       STMT_TYPE_TRANSACTION, "RELEASE"
+   }
+   ,{
+       STMT_TYPE_TRANSACTION, "COMMIT"
+   }
+   ,{
+       STMT_TYPE_TRANSACTION, "END"
+   }
+   ,{
+       STMT_TYPE_TRANSACTION, "ROLLBACK"
+   }
+   ,{
+       STMT_TYPE_TRANSACTION, "ABORT"
+   }
+   ,{
+       STMT_TYPE_LOCK, "LOCK"
+   }
+   ,{
+       STMT_TYPE_ALTER, "ALTER"
+   }
+   ,{
        STMT_TYPE_GRANT, "GRANT"
-   },
-   {
+   }
+   ,{
        STMT_TYPE_REVOKE, "REVOKE"
-   },
-   {
-       STMT_TYPE_PROCCALL, "{"
-   },
-   {
-       STMT_TYPE_LOCK, "LOCK"
-   },
-   {
-       STMT_TYPE_BEGIN, "BEGIN"
-   },
-   {
+   }
+   ,{
+       STMT_TYPE_COPY, "COPY"
+   }
+   ,{
+       STMT_TYPE_ANALYZE, "ANALYZE"
+   }
+   ,{
+       STMT_TYPE_NOTIFY, "NOTIFY"
+   }
+   ,{
+       STMT_TYPE_EXPLAIN, "EXPLAIN"
+   }
+   ,{
+       STMT_TYPE_SPECIAL, "VACUUM"
+   }
+   ,{
+       STMT_TYPE_SPECIAL, "REINDEX"
+   }
+   ,{
+       STMT_TYPE_SPECIAL, "CLUSTER"
+   }
+   ,{
+       STMT_TYPE_SPECIAL, "CHECKPOINT"
+   }
+   ,{
        0, NULL
    }
 };
@@ -97,22 +174,20 @@ PGAPI_AllocStmt(HDBC hdbc,
        return SQL_INVALID_HANDLE;
    }
 
-   stmt = SC_Constructor();
+   stmt = SC_Constructor(conn);
 
-   mylog("**** PGAPI_AllocStmt: hdbc = %u, stmt = %u\n", hdbc, stmt);
+   mylog("**** PGAPI_AllocStmt: hdbc = %x, stmt = %x\n", hdbc, stmt);
 
    if (!stmt)
    {
-       CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "No more memory to allocate a further SQL-statement");
+       CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "No more memory to allocate a further SQL-statement", func);
        *phstmt = SQL_NULL_HSTMT;
-       CC_log_error(func, "", conn);
        return SQL_ERROR;
    }
 
    if (!CC_add_statement(conn, stmt))
    {
-       CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of connections exceeded.");
-       CC_log_error(func, "", conn);
+       CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of connections exceeded.", func);
        SC_Destructor(stmt);
        *phstmt = SQL_NULL_HSTMT;
        return SQL_ERROR;
@@ -136,12 +211,12 @@ PGAPI_AllocStmt(HDBC hdbc,
 
 RETCODE        SQL_API
 PGAPI_FreeStmt(HSTMT hstmt,
-              UWORD fOption)
+              SQLUSMALLINT fOption)
 {
    CSTR func = "PGAPI_FreeStmt";
    StatementClass *stmt = (StatementClass *) hstmt;
 
-   mylog("%s: entering...hstmt=%u, fOption=%d\n", func, hstmt, fOption);
+   mylog("%s: entering...hstmt=%x, fOption=%d\n", func, hstmt, fOption);
 
    if (!stmt)
    {
@@ -161,22 +236,24 @@ PGAPI_FreeStmt(HSTMT hstmt,
 
            if (!CC_remove_statement(conn, stmt))
            {
-               SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
-               SC_log_error(func, "", stmt);
+               SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.", func);
                return SQL_ERROR;       /* stmt may be executing a
                                         * transaction */
            }
 
            /* Free any cursors and discard any result info */
-           if (res = SC_get_Result(stmt), res)
-           {
-               if(SC_is_fetchcursor(stmt))
-                   SC_set_handle(stmt,res);
-               QR_Destructor(res);
-               SC_set_Result(stmt,  NULL);
-           }
+           res = SC_get_Result(stmt);
+           QR_Destructor(res);
+           SC_init_Result(stmt);
        }
 
+       if (stmt->execute_delegate)
+       {
+           PGAPI_FreeStmt(stmt->execute_delegate, SQL_DROP);
+           stmt->execute_delegate = NULL;
+       }
+       if (stmt->execute_parent)
+           stmt->execute_parent->execute_delegate = NULL;
        /* Destroy the statement and free any results, cursors, etc. */
        SC_Destructor(stmt);
    }
@@ -189,10 +266,13 @@ PGAPI_FreeStmt(HSTMT hstmt,
         * itself in place (it can be executed again)
         */
        stmt->transition_status = 0;
+       if (stmt->execute_delegate)
+       {
+           PGAPI_FreeStmt(stmt->execute_delegate, SQL_DROP);
+           stmt->execute_delegate = NULL;
+       }
        if (!SC_recycle_statement(stmt))
        {
-           /* errormsg passed in above */
-           SC_log_error(func, "", stmt);
            return SQL_ERROR;
        }
    }
@@ -200,8 +280,7 @@ PGAPI_FreeStmt(HSTMT hstmt,
        SC_free_params(stmt, STMT_FREE_PARAMS_ALL);
    else
    {
-       SC_set_error(stmt, STMT_OPTION_OUT_OF_RANGE_ERROR, "Invalid option passed to PGAPI_FreeStmt.");
-       SC_log_error(func, "", stmt);
+       SC_set_error(stmt, STMT_OPTION_OUT_OF_RANGE_ERROR, "Invalid option passed to PGAPI_FreeStmt.", func);
        return SQL_ERROR;
    }
 
@@ -209,19 +288,6 @@ PGAPI_FreeStmt(HSTMT hstmt,
 }
 
 
-/*
- * For Declare/Fetch, setting the parameters to close the cursor.
- */
-void 
-SC_set_handle(StatementClass *self,QResultClass *res)
-{
-   res->conn = self->hdbc;
-   if(!res->cursor)
-       res->cursor = malloc(sizeof(self->cursor_name));
-   strcpy(res->cursor,self->cursor_name);
-}
-
-
 /*
  * StatementClass implementation
  */
@@ -236,36 +302,55 @@ InitializeStatementOptions(StatementOptions *opt)
    opt->cursor_type = SQL_CURSOR_FORWARD_ONLY;
    opt->retrieve_data = SQL_RD_ON;
    opt->use_bookmarks = SQL_UB_OFF;
+#if (ODBCVER >= 0x0300)
    opt->metadata_id = SQL_FALSE;
+#endif /* ODBCVER */
+}
+
+static void SC_clear_parse_status(StatementClass *self, ConnectionClass *conn)
+{
+   self->parse_status = STMT_PARSE_NONE;
+   if (PG_VERSION_LT(conn, 7.2))
+   {
+       SC_set_checked_hasoids(self, TRUE);
+       self->num_key_fields = PG_NUM_NORMAL_KEYS;
+   }
 }
 
+static void SC_init_discard_output_params(StatementClass *self)
+{
+   ConnectionClass *conn = SC_get_conn(self);
 
+   if (!conn)  return;
+   self->discard_output_params = 0;
+   if (!conn->connInfo.use_server_side_prepare)
+       self->discard_output_params = 1;
+}
 StatementClass *
-SC_Constructor(void)
+SC_Constructor(ConnectionClass *conn)
 {
    StatementClass *rv;
 
-   mylog("SC_Constructor: entering ...\n");
    rv = (StatementClass *) malloc(sizeof(StatementClass));
    if (rv)
    {
-       mylog("SC_Constructor: created stmt = %u\n",rv);
-       rv->hdbc = NULL;        /* no connection associated yet */
+       rv->hdbc = conn;
        rv->phstmt = NULL;
        rv->result = NULL;
        rv->curres = NULL;
-       rv->manual_result = TRUE;
-       rv->prepare = FALSE;
-       rv->prepared = FALSE;
+       rv->catalog_result = FALSE;
+       rv->prepare = NON_PREPARE_STATEMENT;
+       rv->prepared = NOT_YET_PREPARED;
        rv->status = STMT_ALLOCATED;
        rv->internal = FALSE;
+       rv->plan_name = NULL;
        rv->transition_status = 0;
+       rv->multi_statement = -1; /* unknown */
        rv->num_params = -1; /* unknown */
 
        rv->__error_message = NULL;
        rv->__error_number = 0;
-       rv->errormsg_created = FALSE;
-       rv->__sqlstate[0] = '\0';
+       rv->pgerror = NULL;
 
        rv->statement = NULL;
        rv->stmt_with_params = NULL;
@@ -275,7 +360,7 @@ SC_Constructor(void)
        rv->statement_type = STMT_TYPE_UNKNOWN;
 
        rv->currTuple = -1;
-       rv->rowset_start = -1;
+       SC_set_rowset_start(rv, -1, FALSE);
        rv->current_col = -1;
        rv->bind_row = 0;
        rv->last_fetch_count = rv->last_fetch_count_include_ommitted = 0;
@@ -289,12 +374,16 @@ SC_Constructor(void)
        rv->put_data = FALSE;
 
        rv->lobj_fd = -1;
-       rv->cursor_name[0] = '\0';
+       INIT_NAME(rv->cursor_name);
 
        /* Parse Stuff */
        rv->ti = NULL;
        rv->ntab = 0;
-       rv->parse_status = STMT_PARSE_NONE;
+       rv->num_key_fields = -1; /* unknown */
+       SC_clear_parse_status(rv, conn);
+       rv->proc_return = -1;
+       SC_init_discard_output_params(rv);
+       rv->cancel_info = 0;
 
        /* Clear Statement Options -- defaults will be set in AllocStmt */
        memset(&rv->options, 0, sizeof(StatementOptions));
@@ -310,11 +399,12 @@ SC_Constructor(void)
        rv->pre_executing = FALSE;
        rv->inaccurate_result = FALSE;
        rv->miscinfo = 0;
+       rv->rbonerr = 0;
        rv->updatable = FALSE;
-       rv->error_recsize = -1;
        rv->diag_row_count = 0;
        rv->stmt_time = 0;
        rv->execute_delegate = NULL;
+       rv->execute_parent = NULL;
        rv->allocated_callbacks = 0;
        rv->num_callbacks = 0;
        rv->callbacks = NULL;
@@ -328,14 +418,15 @@ SC_Constructor(void)
 char
 SC_Destructor(StatementClass *self)
 {
+   CSTR func   = "SC_Destrcutor";
    QResultClass    *res = SC_get_Result(self);
 
    if (!self)  return FALSE;
-   mylog("SC_Destructor: self=%u, self->result=%u, self->hdbc=%u\n", self, res, self->hdbc);
+   mylog("SC_Destructor: self=%x, self->result=%x, self->hdbc=%x\n", self, res, self->hdbc);
    SC_clear_error(self);
    if (STMT_EXECUTING == self->status)
    {
-       SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
+       SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.", func);
        return FALSE;
    }
 
@@ -348,38 +439,34 @@ SC_Destructor(StatementClass *self)
    }
 
    SC_initialize_stmts(self, TRUE);
-   SC_free_params(self, STMT_FREE_PARAMS_ALL);
 
         /* Free the parsed table information */
    if (self->ti)
    {
-       int i;
-
-       for (i = 0; i < self->ntab; i++)
-           if (self->ti[i])
-               free(self->ti[i]);
+       TI_Destructor(self->ti, self->ntab);
 
        free(self->ti);
        self->ti = NULL;
    }
 
+   NULL_THE_NAME(self->cursor_name);
    /* Free the parsed field information */
    DC_Destructor((DescriptorClass *) SC_get_ARDi(self));
    DC_Destructor((DescriptorClass *) SC_get_APDi(self));
    DC_Destructor((DescriptorClass *) SC_get_IRDi(self));
    DC_Destructor((DescriptorClass *) SC_get_IPDi(self));
+   GDATA_unbind_cols(SC_get_GDTI(self), TRUE);
+   PDATA_free_params(SC_get_PDTI(self), STMT_FREE_PARAMS_ALL);
    
    if (self->__error_message)
        free(self->__error_message);
+   if (self->pgerror)
+       ER_Destructor(self->pgerror);
    cancelNeedDataState(self);
    if (self->callbacks)
        free(self->callbacks);
-    
-   GDATA_unbind_cols(SC_get_GDTI(self), TRUE);
 
    DELETE_STMT_CS(self);
-   if (self->pdata_info.pdata != 0)
-       free(self->pdata_info.pdata);
    free(self);
 
    mylog("SC_Destructor: EXIT\n");
@@ -426,19 +513,61 @@ statement_type(const char *statement)
        if (!strnicmp(statement, Statement_Type[i].s, strlen(Statement_Type[i].s)))
            return Statement_Type[i].type;
 
-   /* determine START TRANSACTION */
-   if (!strnicmp(statement, "START", 5))
-   {
-       statement += 5;
-       /* ignore whitespace in query string */
-       while (*statement && isspace((UCHAR) *statement))
-           statement++;
-       if (!strnicmp(statement, "TRANSACTION", 11))
-           return STMT_TYPE_BEGIN;
-   }
    return STMT_TYPE_OTHER;
 }
 
+void
+SC_set_planname(StatementClass *stmt, const char *plan_name)
+{
+   if (stmt->plan_name)
+       free(stmt->plan_name);
+   if (plan_name && plan_name[0])
+       stmt->plan_name = strdup(plan_name);
+   else
+       stmt->plan_name = NULL;
+}
+
+void
+SC_set_rowset_start(StatementClass *stmt, SQLLEN start, BOOL valid_base)
+{
+   QResultClass    *res = SC_get_Curres(stmt);
+   Int4    incr = start - stmt->rowset_start;
+
+inolog("%x->SC_set_rowstart %d->%d(%s) ", stmt, stmt->rowset_start, start, valid_base ? "valid" : "unknown");
+   if (res != NULL)
+   {
+       BOOL    valid = QR_has_valid_base(res);
+inolog(":QR is %s", QR_has_valid_base(res) ? "valid" : "unknown");
+
+       if (valid)
+       {
+           if (valid_base)
+               QR_inc_rowstart_in_cache(res, incr);
+           else
+               QR_set_no_valid_base(res);
+       }
+       else if (valid_base)
+       {   
+           QR_set_has_valid_base(res);
+           if (start < 0)
+               QR_set_rowstart_in_cache(res, -1);
+           else
+               QR_set_rowstart_in_cache(res, 0);
+       }
+       if (!QR_get_cursor(res))
+           res->key_base = start;
+inolog(":QR result=%d(%s)", QR_get_rowstart_in_cache(res), QR_has_valid_base(res) ? "valid" : "unknown");
+   }
+   stmt->rowset_start = start;
+inolog(":stmt result=%d\n", stmt->rowset_start);
+}
+void
+SC_inc_rowset_start(StatementClass *stmt, SQLLEN inc)
+{
+   SQLLEN  start = stmt->rowset_start + inc;
+   
+   SC_set_rowset_start(stmt, start, TRUE);
+}
 int
 SC_set_current_col(StatementClass *stmt, int col)
 {
@@ -455,32 +584,30 @@ void
 SC_set_prepared(StatementClass *stmt, BOOL prepared)
 {
    if (prepared == stmt->prepared)
-       return;
-   if (!prepared)
+       ;
+   else if (NOT_YET_PREPARED == prepared && PREPARED_PERMANENTLY == stmt->prepared)
    {
        ConnectionClass *conn = SC_get_conn(stmt);
 
        if (conn && CONN_CONNECTED == conn->status)
        {
-           char    plannm[32];
-
-           sprintf(plannm, "_PLAN%p", stmt);
            if (CC_is_in_error_trans(conn))
            {
-               CC_mark_a_plan_to_discard(conn, plannm);
+               CC_mark_a_object_to_discard(conn, 's',  stmt->plan_name);
            }
            else
            {
                QResultClass    *res;
                char dealloc_stmt[128];
 
-               sprintf(dealloc_stmt, "DEALLOCATE \"%s\"", plannm);
-               res = CC_send_query(conn, dealloc_stmt, NULL, 0);
-               if (res)
-                   QR_Destructor(res);
+               sprintf(dealloc_stmt, "DEALLOCATE \"%s\"", stmt->plan_name);
+               res = CC_send_query(conn, dealloc_stmt, NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL);
+               QR_Destructor(res);
            } 
        }
    }
+   if (NOT_YET_PREPARED == prepared)
+       SC_set_planname(stmt, NULL);
    stmt->prepared = prepared;
 }
 
@@ -504,11 +631,13 @@ SC_initialize_stmts(StatementClass *self, BOOL initializeOriginal)
            free(self->execute_statement);
            self->execute_statement = NULL;
        }
-       self->prepare = FALSE;
-       SC_set_prepared(self, FALSE);
+       self->prepare = NON_PREPARE_STATEMENT;
+       SC_set_prepared(self, NOT_YET_PREPARED);
        self->statement_type = STMT_TYPE_UNKNOWN; /* unknown */
-       self->status = STMT_READY;
+       self->multi_statement = -1; /* unknown */
        self->num_params = -1; /* unknown */
+       self->proc_return = -1; /* unknown */
+       SC_init_discard_output_params(self);
    }
    if (self->stmt_with_params)
    {
@@ -528,26 +657,26 @@ BOOL  SC_opencheck(StatementClass *self, const char *func)
 {
    QResultClass    *res;
 
+   if (!self)
+       return FALSE;
    if (self->status == STMT_EXECUTING)
    {
-       SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
+           SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.", func);
        return TRUE;
    }
    /*
-    * We get here if a statement is prepared and executed to get the metadata.
+    * We can dispose the result of PREMATURE execution any time.
     */
    if (self->prepare && self->status == STMT_PREMATURE)
    {
        mylog("SC_opencheck: self->prepare && self->status == STMT_PREMATURE\n");
        return FALSE;
    }
-   
-   if (res = SC_get_Curres(self), NULL != res)
+   if (res = SC_get_Result(self), NULL != res)
    {
        if (res->backend_tuples)
        {
-           SC_set_error(self, STMT_SEQUENCE_ERROR, "The cursor is open.");
-           SC_log_error(func, "", self);
+               SC_set_error(self, STMT_SEQUENCE_ERROR, "The cursor is open.", func);
            return TRUE;
        }
    }
@@ -573,19 +702,21 @@ SC_initialize_and_recycle(StatementClass *self)
 char
 SC_recycle_statement(StatementClass *self)
 {
+   CSTR    func = "SC_recycle_statement";
    ConnectionClass *conn;
    QResultClass    *res;
 
-   mylog("recycle statement: self= %u\n", self);
+   mylog("%s: self= %x\n", func, self);
 
    SC_clear_error(self);
    /* This would not happen */
    if (self->status == STMT_EXECUTING)
    {
-       SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
+       SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.", func);
        return FALSE;
    }
 
+   conn = SC_get_conn(self);
    switch (self->status)
    {
        case STMT_ALLOCATED:
@@ -602,9 +733,7 @@ SC_recycle_statement(StatementClass *self)
             * start of a transaction. If so, we have to rollback that
             * transaction.
             */
-           conn = SC_get_conn(self);
-           if (CC_is_in_trans(conn) && !CC_is_in_autocommit(conn) && 
-               !CC_is_in_manual_trans(conn))
+           if (!CC_is_in_autocommit(conn) && CC_is_in_trans(conn))
            {
                if (SC_is_pre_executable(self) && !conn->connInfo.disallow_premature)
                    CC_abort(conn);
@@ -615,51 +744,58 @@ SC_recycle_statement(StatementClass *self)
            break;
 
        default:
-           SC_set_error(self, STMT_INTERNAL_ERROR, "An internal error occured while recycling statements");
+           SC_set_error(self, STMT_INTERNAL_ERROR, "An internal error occured while recycling statements", func);
            return FALSE;
    }
 
-        /* Free the parsed table information */
-   if (self->ti)
+   if (NOT_YET_PREPARED == self->prepared)
    {
-       int i;
+           /* Free the parsed table information */
+       if (self->ti)
+       {
+           TI_Destructor(self->ti, self->ntab);
+           free(self->ti);
+           self->ti = NULL;
+           self->ntab = 0;
+       }
+       /* Free the parsed field information */
+       DC_Destructor((DescriptorClass *) SC_get_IRD(self));
 
-       for (i = 0; i < self->ntab; i++)
-           if (self->ti[i])
-               free(self->ti[i]);
-       self->ti = NULL;
-       self->ntab = 0;
+inolog("SC_clear_parse_status\n");
+       SC_clear_parse_status(self, conn);
+       self->updatable = FALSE;
    }
-   /* Free the parsed field information */
-   DC_Destructor((DescriptorClass *) SC_get_IRD(self));
-
-   self->parse_status = STMT_PARSE_NONE;
-   self->updatable = FALSE;
 
    /* Free any cursors */
    if (res = SC_get_Result(self), res)
    {
-       if(SC_is_fetchcursor(self))
-           SC_set_handle(self,res);
-       QR_Destructor(res);
-       SC_set_Result(self, NULL);
+       if (PREPARED_PERMANENTLY == self->prepared)
+           QR_close_result(res, FALSE);
+       else
+       {
+           QR_Destructor(res);
+           SC_init_Result(self);
+       }
    }
    self->inaccurate_result = FALSE;
+   self->miscinfo = 0;
+   /* self->rbonerr = 0; Never clear the bits here */
 
    /*
     * Reset only parameters that have anything to do with results
     */
    self->status = STMT_READY;
-   self->manual_result = TRUE;     /* very important */
+   self->catalog_result = FALSE;   /* not very important */
+
    self->currTuple = -1;
-   self->rowset_start = -1;
+   SC_set_rowset_start(self, -1, FALSE);
    SC_set_current_col(self, -1);
    self->bind_row = 0;
+inolog("%s statement=%x ommitted=0\n", func, self);
    self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
 
    self->__error_message = NULL;
    self->__error_number = 0;
-   self->errormsg_created = FALSE;
 
    self->lobj_fd = -1;
 
@@ -671,6 +807,7 @@ SC_recycle_statement(StatementClass *self)
    SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY);
    SC_initialize_stmts(self, FALSE);
    cancelNeedDataState(self);
+   self->cancel_info = 0;
    /*
     *  reset the current attr setting to the original one.
     */
@@ -684,12 +821,19 @@ SC_recycle_statement(StatementClass *self)
 }
 
 
-/* Pre-execute a statement (SQLPrepare/SQLDescribeCol) */
-void
+/*
+ * Pre-execute a statement (for SQLPrepare/SQLDescribeCol) 
+ */
+Int4   /* returns # of fields if successful */
 SC_pre_execute(StatementClass *self)
 {
+   Int4        num_fields = -1;
+   QResultClass    *res;
    mylog("SC_pre_execute: status = %d\n", self->status);
 
+   res = SC_get_Curres(self);
+   if (res && (num_fields = QR_NumResultCols(res)) > 0)
+       return num_fields;
    if (self->status == STMT_READY)
    {
        mylog("              preprocess: status = READY\n");
@@ -698,31 +842,49 @@ SC_pre_execute(StatementClass *self)
        if (self->statement_type == STMT_TYPE_SELECT)
        {
            char        old_pre_executing = self->pre_executing;
-           RETCODE     ret;
 
-           self->pre_executing = TRUE;
-           self->inaccurate_result = FALSE;
-
-           ret = PGAPI_Execute(self, 0);
+           decideHowToPrepare(self);
+           self->inaccurate_result = TRUE;
+           switch (SC_get_prepare_method(self))
+           {
+               case USING_PARSE_REQUEST:
+                   if (SQL_SUCCESS != prepareParameters(self))
+                       return num_fields;
+                   break;
+               case USING_UNNAMED_PARSE_REQUEST:
+                   if (SQL_SUCCESS != prepareParameters(self))
+                       return num_fields;
+                   self->status = STMT_PREMATURE;
+                   break;
+               default:
+                   self->pre_executing = TRUE;
+                   self->inaccurate_result = FALSE;
+                   PGAPI_Execute(self, 0);
 
-           self->pre_executing = old_pre_executing;
+                   self->pre_executing = old_pre_executing;
 
-           if (self->status == STMT_FINISHED &&
-               (SQL_SUCCESS == ret ||
-                SQL_SUCCESS_WITH_INFO == ret))
+                   if (self->status == STMT_FINISHED)
+                   {
+                       mylog("              preprocess: after status = FINISHED, so set PREMATURE\n");
+                       self->status = STMT_PREMATURE;
+                   }
+           }
+           if (res = SC_get_Curres(self), NULL != res)
            {
-               mylog("              preprocess: after status = FINISHED, so set PREMATURE\n");
-               self->status = STMT_PREMATURE;
+               num_fields = QR_NumResultCols(res);
+               return num_fields;
            }
        }
        if (!SC_is_pre_executable(self))
        {
            SC_set_Result(self, QR_Constructor());
-           QR_set_status(SC_get_Result(self), PGRES_TUPLES_OK);
+           QR_set_rstatus(SC_get_Result(self), PGRES_TUPLES_OK);
            self->inaccurate_result = TRUE;
            self->status = STMT_PREMATURE;
+           num_fields = 0;
        }
    }
+   return num_fields;
 }
 
 
@@ -749,148 +911,379 @@ SC_unbind_cols(StatementClass *self)
 void
 SC_clear_error(StatementClass *self)
 {
+   QResultClass    *res;
+
    self->__error_number = 0;
    if (self->__error_message)
+   {
        free(self->__error_message);
-   self->__error_message = NULL;
-   self->errormsg_created = FALSE;
-   self->errorpos = 0;
-   self->error_recsize = -1;
+       self->__error_message = NULL;
+   }
+   if (self->pgerror)
+   {
+       ER_Destructor(self->pgerror);
+       self->pgerror = NULL;
+   }
    self->diag_row_count = 0;
+   if (res = SC_get_Curres(self), res)
+   {
+       QR_set_message(res, NULL);
+       QR_set_notice(res, NULL);
+       res->sqlstate[0] = '\0';
+   }
+   CC_clear_error(SC_get_conn(self));
 }
 
 
 /*
- * This function creates an error msg which is the concatenation
+ * This function creates an error info which is the concatenation
  * of the result, statement, connection, and socket messages.
  */
-char *
-SC_create_errormsg(const StatementClass *self)
+
+/* Map sql commands to statement types */
+static struct
+{
+   int number;
+   const   char    * ver3str;
+   const   char    * ver2str;
+}  Statement_sqlstate[] =
+
+{
+   { STMT_ERROR_IN_ROW, "01S01", "01S01" },
+   { STMT_OPTION_VALUE_CHANGED, "01S02", "01S02" },
+   { STMT_ROW_VERSION_CHANGED,  "01001", "01001" }, /* data changed */
+   { STMT_POS_BEFORE_RECORDSET, "01S06", "01S06" },
+   { STMT_TRUNCATED, "01004", "01004" }, /* data truncated */
+   { STMT_INFO_ONLY, "00000", "00000" }, /* just information that is returned, no error */
+
+   { STMT_OK,  "00000", "00000" }, /* OK */
+   { STMT_EXEC_ERROR, "HY000", "S1000" }, /* also a general error */
+   { STMT_STATUS_ERROR, "HY010", "S1010" },
+   { STMT_SEQUENCE_ERROR, "HY010", "S1010" }, /* Function sequence error */
+   { STMT_NO_MEMORY_ERROR, "HY001", "S1001" }, /* memory allocation failure */
+   { STMT_COLNUM_ERROR, "07009", "S1002" }, /* invalid column number */
+   { STMT_NO_STMTSTRING, "HY001", "S1001" }, /* having no stmtstring is also a malloc problem */
+   { STMT_ERROR_TAKEN_FROM_BACKEND, "HY000", "S1000" }, /* general error */
+   { STMT_INTERNAL_ERROR, "HY000", "S1000" }, /* general error */
+   { STMT_STILL_EXECUTING, "HY010", "S1010" },
+   { STMT_NOT_IMPLEMENTED_ERROR, "HYC00", "S1C00" }, /* == 'driver not 
+                             * capable' */
+   { STMT_BAD_PARAMETER_NUMBER_ERROR, "07009", "S1093" },
+   { STMT_OPTION_OUT_OF_RANGE_ERROR, "HY092", "S1092" },
+   { STMT_INVALID_COLUMN_NUMBER_ERROR, "07009", "S1002" },
+   { STMT_RESTRICTED_DATA_TYPE_ERROR, "07006", "07006" },
+   { STMT_INVALID_CURSOR_STATE_ERROR, "07005", "24000" },
+   { STMT_CREATE_TABLE_ERROR, "42S01", "S0001" }, /* table already exists */
+   { STMT_NO_CURSOR_NAME, "S1015", "S1015" },
+   { STMT_INVALID_CURSOR_NAME, "34000", "34000" },
+   { STMT_INVALID_ARGUMENT_NO, "HY024", "S1009" }, /* invalid argument value */
+   { STMT_ROW_OUT_OF_RANGE, "HY107", "S1107" },
+   { STMT_OPERATION_CANCELLED, "HY008", "S1008" },
+   { STMT_INVALID_CURSOR_POSITION, "HY109", "S1109" },
+   { STMT_VALUE_OUT_OF_RANGE, "HY019", "22003" },
+   { STMT_OPERATION_INVALID, "HY011", "S1011" },
+   { STMT_PROGRAM_TYPE_OUT_OF_RANGE, "?????", "?????" }, 
+   { STMT_BAD_ERROR, "08S01", "08S01" }, /* communication link failure */
+   { STMT_INVALID_OPTION_IDENTIFIER, "HY092", "HY092" },
+   { STMT_RETURN_NULL_WITHOUT_INDICATOR, "22002", "22002" },
+   { STMT_INVALID_DESCRIPTOR_IDENTIFIER, "HY091", "HY091" },
+   { STMT_OPTION_NOT_FOR_THE_DRIVER, "HYC00", "HYC00" },
+   { STMT_FETCH_OUT_OF_RANGE, "HY106", "S1106" },
+   { STMT_COUNT_FIELD_INCORRECT, "07002", "07002" },
+   { STMT_INVALID_NULL_ARG, "HY009", "S1009" }
+};
+
+static PG_ErrorInfo *
+SC_create_errorinfo(const StatementClass *self)
 {
    QResultClass *res = SC_get_Curres(self);
-   ConnectionClass *conn = self->hdbc;
-   int         pos;
-   BOOL            detailmsg = FALSE;
-   char             msg[4096];
+   ConnectionClass *conn = SC_get_conn(self);
+   Int4    errornum;
+   int     pos;
+   BOOL        resmsg = FALSE, detailmsg = FALSE, msgend = FALSE;
+   char        msg[4096], *wmsg;
+   char        *ermsg = NULL, *sqlstate = NULL;
+   PG_ErrorInfo    *pgerror;
+
+   if (self->pgerror)
+       return self->pgerror;
+   errornum = self->__error_number;
+   if (errornum == 0)
+       return  NULL;
 
    msg[0] = '\0';
-
-   if (res && res->message)
+   if (res)
    {
-       strncpy(msg, res->message, sizeof(msg));
-       detailmsg = TRUE;
+       if (res->sqlstate[0])
+           sqlstate = res->sqlstate;
+       if (res->message)
+       {
+           strncpy(msg, res->message, sizeof(msg));
+           detailmsg = resmsg = TRUE;
+       }
+       if (msg[0])
+           ermsg = msg;
+       else if (QR_get_notice(res))
+       {
+           char *notice = QR_get_notice(res);
+           int len = strlen(notice);
+           if (len < sizeof(msg))
+           {
+               memcpy(msg, notice, len);
+               msg[len] = '\0';
+               ermsg = msg;
+           }
+           else
+           {
+               ermsg = notice;
+               msgend = TRUE;
+           }
+       }
    }
-   else if (SC_get_errormsg(self))
-       strncpy(msg, SC_get_errormsg(self), sizeof(msg));
-
-   if (!msg[0] && res && QR_get_notice(res))
+   if (!msgend && (wmsg = SC_get_errormsg(self)) && wmsg[0])
    {
-       char *notice = QR_get_notice(res);
-       int len = strlen(notice);
-       if (len < sizeof(msg))
+       pos = strlen(msg);
+
+       if (detailmsg)
        {
-           memcpy(msg, notice, len);
-           msg[len] = '\0';
+           msg[pos++] = ';';
+           msg[pos++] = '\n';
        }
-       else
-           return strdup(notice);
+       strncpy(msg + pos, wmsg, sizeof(msg) - pos);
+       ermsg = msg;
+       detailmsg = TRUE;
    }
-   if (conn)
+
+   if (conn && !msgend)
    {
-       if (!detailmsg && CC_get_errormsg(conn) && (CC_get_errormsg(conn))[0] != '\0')
+       SocketClass *sock = conn->sock;
+
+       if (!resmsg && (wmsg = CC_get_errormsg(conn)) && wmsg[0] != '\0')
        {
            pos = strlen(msg);
-           sprintf(&msg[pos], ";\n%s", CC_get_errormsg(conn));
+           snprintf(&msg[pos], sizeof(msg) - pos, ";\n%s", CC_get_errormsg(conn));
        }
 
+       if (sock && sock->errormsg && sock->errormsg[0] != '\0')
+       {
+           pos = strlen(msg);
+           snprintf(&msg[pos], sizeof(msg) - pos, ";\n%s", sock->errormsg);
+       }
+       ermsg = msg;
    }
+   pgerror = ER_Constructor(self->__error_number, ermsg);
+   if (sqlstate)
+       strcpy(pgerror->sqlstate, sqlstate);
+   else if (conn)
+   {
+       if (conn->sqlstate[0])
+           strcpy(pgerror->sqlstate, conn->sqlstate);
+       else
+       {
+               EnvironmentClass *env = (EnvironmentClass *) conn->henv;
+
+           errornum -= LOWEST_STMT_ERROR;
+               if (errornum < 0 ||
+               errornum >= sizeof(Statement_sqlstate) / sizeof(Statement_sqlstate[0]))
+               errornum = 1 - LOWEST_STMT_ERROR;
+               strcpy(pgerror->sqlstate, EN_is_odbc3(env) ?
+               Statement_sqlstate[errornum].ver3str : 
+               Statement_sqlstate[errornum].ver2str);
+       }
+   } 
 
-   return msg[0] ? strdup(msg) : NULL;
+   return pgerror;
 }
 
 
-void
-SC_set_error(StatementClass *self, int number, const char *message)
+StatementClass *SC_get_ancestor(StatementClass *stmt)
 {
-   if (self->__error_message)
-       free(self->__error_message);
-   self->__error_number = number;
-   self->__error_message = message ? strdup(message) : NULL;
+   StatementClass  *child = stmt, *parent;
+
+inolog("SC_get_ancestor in stmt=%x\n", stmt);
+   for (child = stmt, parent = child->execute_parent; parent; child = parent, parent = child->execute_parent)
+   {
+       inolog("parent=%x\n", parent);
+   }
+   return child;
 }
+void SC_reset_delegate(RETCODE retcode, StatementClass *stmt)
+{
+   StatementClass  *delegate = stmt->execute_delegate;
 
+   if (!delegate)
+       return;
+   PGAPI_FreeStmt(delegate, SQL_DROP);
+}
 
 void
-SC_set_errormsg(StatementClass *self, const char *message)
+SC_set_error(StatementClass *self, int number, const char *message, const char *func)
 {
    if (self->__error_message)
        free(self->__error_message);
+   self->__error_number = number;
    self->__error_message = message ? strdup(message) : NULL;
+   if (func && number != STMT_OK && number != STMT_INFO_ONLY)
+       SC_log_error(func, "", self);
 }
 
 
 void
-SC_error_copy(StatementClass *self, const StatementClass *from)
+SC_set_errormsg(StatementClass *self, const char *message)
 {
    if (self->__error_message)
        free(self->__error_message);
-   self->__error_number = from->__error_number;
-   self->__error_message = from->__error_message ? strdup(from->__error_message) : NULL;
+   self->__error_message = message ? strdup(message) : NULL;
 }
 
 
 void
-SC_full_error_copy(StatementClass *self, const StatementClass *from)
+SC_replace_error_with_res(StatementClass *self, int number, const char *message, const QResultClass *from_res, BOOL check)
 {
-   if (self->__error_message)
-       free(self->__error_message);
-   self->__error_number = from->__error_number;
-   self->__error_message = SC_create_errormsg(from);
-   self->errormsg_created = TRUE;
+   QResultClass    *self_res;
+   BOOL    repstate;
+
+inolog("SC_set_error_from_res %x->%x check=%d\n", from_res ,self, check);
+   if (check)
+   {
+       if (0 == number)            return;
+       if (0 > number &&       /* SQL_SUCCESS_WITH_INFO */
+           0 < self->__error_number)
+           return;
+   }
+   self->__error_number = number;
+   if (!check || message)
+   {
+       if (self->__error_message)
+           free(self->__error_message);
+       self->__error_message = message ? strdup(message) : NULL;
+   }
+   if (self->pgerror)
+   {
+       ER_Destructor(self->pgerror);
+       self->pgerror = NULL;
+   }
+   self_res = SC_get_Curres(self);
+   if (!self_res) return;
+   if (self_res == from_res)   return;
+   QR_add_message(self_res, QR_get_message(from_res));
+   QR_add_notice(self_res, QR_get_notice(from_res));
+   repstate = FALSE;
+   if (!check)
+       repstate = TRUE;
+   else if (from_res->sqlstate[0])
+   {
+       if (!self_res->sqlstate[0] || strncmp(self_res->sqlstate, "00", 2) == 0)
+           repstate = TRUE;
+       else if (strncmp(from_res->sqlstate, "01", 2) >= 0)
+           repstate = TRUE;
+   }
+   if (repstate)
+       strcpy(self_res->sqlstate, from_res->sqlstate);
 }
 
-char
-SC_get_error(StatementClass *self, int *number, char **message)
+void
+SC_error_copy(StatementClass *self, const StatementClass *from, BOOL check)
 {
-   char    rv, *msgcrt;
+   QResultClass    *self_res, *from_res;
+   BOOL    repstate;
 
-   /* Create a very informative errormsg if it hasn't been done yet. */
-   if (!self->errormsg_created)
+inolog("SC_error_copy %x->%x check=%d\n", from ,self, check);
+   if (self == from)   return;
+   if (check)
+   {
+       if (0 == from->__error_number)  /* SQL_SUCCESS */
+           return;
+       if (0 > from->__error_number && /* SQL_SUCCESS_WITH_INFO */
+           0 < self->__error_number)
+           return;
+   }
+   self->__error_number = from->__error_number;
+   if (!check || from->__error_message)
    {
-       msgcrt = SC_create_errormsg(self);
        if (self->__error_message)
            free(self->__error_message);
-       self->__error_message = msgcrt; 
-       self->errormsg_created = TRUE;
-       self->errorpos = 0;
-       self->error_recsize = -1;
+       self->__error_message = from->__error_message ? strdup(from->__error_message) : NULL;
    }
-
-   if (SC_get_errornumber(self))
+   if (self->pgerror)
    {
-       *number = SC_get_errornumber(self);
-       *message = self->__error_message;
+       ER_Destructor(self->pgerror);
+       self->pgerror = NULL;
    }
-
-   rv = (SC_get_errornumber(self) != 0);
-
-   return rv;
+   self_res = SC_get_Curres(self);
+   from_res = SC_get_Curres(from);
+   if (!self_res || !from_res)
+       return;
+   QR_add_message(self_res, QR_get_message(from_res));
+   QR_add_notice(self_res, QR_get_notice(from_res));
+   repstate = FALSE;
+   if (!check)
+       repstate = TRUE;
+   else if (from_res->sqlstate[0])
+   {
+       if (!self_res->sqlstate[0] || strncmp(self_res->sqlstate, "00", 2) == 0)
+           repstate = TRUE;
+       else if (strncmp(from_res->sqlstate, "01", 2) >= 0)
+           repstate = TRUE;
+   }
+   if (repstate)
+       strcpy(self_res->sqlstate, from_res->sqlstate);
 }
 
+
 void
-SC_set_sqlstate(StatementClass *self, const char *sqlstate)
+SC_full_error_copy(StatementClass *self, const StatementClass *from, BOOL allres)
 {
-    if (sqlstate)
-        snprintf(self->__sqlstate, SQLSTATE_LENGTH, "%s", sqlstate);
-    else
-        self->__sqlstate[0] = '\0';
+   PG_ErrorInfo        *pgerror;
+
+inolog("SC_full_error_copy %x->%x\n", from ,self);
+   if (self->__error_message)
+   {
+       free(self->__error_message);
+       self->__error_message = NULL;
+   }
+   if (from->__error_message)
+       self->__error_message = strdup(from->__error_message);
+   self->__error_number = from->__error_number;
+   if (from->pgerror)
+   {
+       if (self->pgerror)
+           ER_Destructor(self->pgerror);
+       self->pgerror = ER_Dup(from->pgerror);
+       return;
+   }
+   else if (!allres)
+       return;
+   pgerror = SC_create_errorinfo(from);
+   if (!pgerror->__error_message[0])
+   {
+       ER_Destructor(pgerror);
+       return;
+   } 
+   if (self->pgerror)
+       ER_Destructor(self->pgerror);
+   self->pgerror = pgerror;
 }
 
-char *
-SC_get_sqlstate(StatementClass *self)
+/*              Returns the next SQL error information. */
+RETCODE         SQL_API
+PGAPI_StmtError(   SQLHSTMT    hstmt,
+       SQLSMALLINT RecNumber,
+       SQLCHAR FAR * szSqlState,
+       SQLINTEGER FAR * pfNativeError,
+       SQLCHAR FAR * szErrorMsg,
+       SQLSMALLINT cbErrorMsgMax,
+       SQLSMALLINT FAR * pcbErrorMsg,
+       UWORD flag)
 {
-    return self->__sqlstate;
-}
+   /* CC: return an error of a hdesc  */
+   StatementClass *stmt = (StatementClass *) hstmt;
 
+   stmt->pgerror = SC_create_errorinfo(stmt);
+   return ER_ReturnError(&(stmt->pgerror), RecNumber, szSqlState,
+       pfNativeError, szErrorMsg, cbErrorMsgMax,
+       pcbErrorMsg, flag);
+}
 
 time_t
 SC_get_time(StatementClass *stmt)
@@ -906,10 +1299,10 @@ SC_get_time(StatementClass *stmt)
  * just the current row number.  But it could be more sophisticated
  * someday, such as mapping a key to a 32 bit value
  */
-UInt4
+SQLULEN
 SC_get_bookmark(StatementClass *self)
 {
-   return (self->currTuple + 1);
+   return SC_make_bookmark(self->currTuple);
 }
 
 
@@ -920,92 +1313,52 @@ SC_fetch(StatementClass *self)
    QResultClass *res = SC_get_Curres(self);
    ARDFields   *opts;
    GetDataInfo *gdata;
-   int         retval,
-               result;
+   int     retval;
+   RETCODE     result;
 
    Int2        num_cols,
                lf;
    Oid         type;
    char       *value;
-   char        fetch[128];
-
-   QueryInfo   qi;
-   UDWORD      qflag = 0;
    ColumnInfoClass *coli;
    BindInfoClass   *bookmark;
 
    /* TupleField *tupleField; */
    ConnInfo   *ci = &(SC_get_conn(self)->connInfo);
 
+inolog("%s statement=%x ommitted=0\n", func, self);
    self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
-
-   /* Issue the fetch query here in case of declare fetch for subsequent rows */
-   if (SC_is_fetchcursor(self) && ((self->currTuple % ci->drivers.fetch_max) >= QR_get_num_total_tuples(res) - 1))
-   {
-       qi.result_in = NULL;
-       qi.cursor = self->cursor_name;
-       qi.row_size = ci->drivers.fetch_max;
-       sprintf(fetch, "fetch %d in %s",ci->drivers.fetch_max ,self->cursor_name);
-
-        /* Cleanup the QR. We need to kill off the cursor first, or this willcrash */
-
-        if (self->result->cursor)
-        {
-            free(self->result->cursor);
-            self->result->cursor = NULL;
-        }
-
-        if (self->result)
-        {
-            QR_Destructor(self->result);
-            self->result = NULL;
-        }
-
-        /* Finished cleanup */
-
-        res = CC_send_query(self->hdbc, fetch, &qi, qflag);
-       SC_set_Result(self,res);
-   }
-
    coli = QR_get_fields(res);  /* the column info */
-   mylog("manual_result = %d, use_declarefetch = %d\n", self->manual_result, ci->drivers.use_declarefetch);
 
-   if (self->manual_result)
+   mylog("fetch_cursor=%d, %x->total_read=%d\n", SC_is_fetchcursor(self), res, res->num_total_read);
+
+   if (!SC_is_fetchcursor(self))
    {
-       if(!SC_is_fetchcursor(self))
+       if (self->currTuple >= (Int4) QR_get_num_total_tuples(res) - 1 ||
+           (self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1))
        {
-           if (self->currTuple >= QR_get_num_total_tuples(res) - 1 ||
-               (self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1))
-           {
-               /*
-                * if at the end of the tuples, return "no data found" and set
-                * the cursor past the end of the result set
-                */
-               self->currTuple = QR_get_num_total_tuples(res);
-               return SQL_NO_DATA_FOUND;
-           }
-       }
-       else
-       {
-           if ((((self->currTuple + 1) % ci->drivers.fetch_max) >= QR_get_num_total_tuples(res)) &&
-               QR_get_num_total_tuples(res) < ci->drivers.fetch_max)
-           {
-               SC_no_fetchcursor(self);
-               self->currTuple = QR_get_num_total_tuples(res);
-               return SQL_NO_DATA_FOUND;
-           }
+           /*
+            * if at the end of the tuples, return "no data found" and set
+            * the cursor past the end of the result set
+            */
+           self->currTuple = QR_get_num_total_tuples(res);
+           return SQL_NO_DATA_FOUND;
        }
 
-       mylog("**** SC_fetch: manual_result\n");
+       mylog("**** SC_fetch: non-cursor_result\n");
        (self->currTuple)++;
    }
    else
    {
        /* read from the cache or the physical next tuple */
-       retval = QR_next_tuple(res);
+       retval = QR_next_tuple(res, self);
        if (retval < 0)
        {
            mylog("**** SC_fetch: end_tuples\n");
+           if (QR_get_cursor(res) &&
+               SQL_CURSOR_FORWARD_ONLY == self->options.cursor_type &&
+               QR_once_reached_eof(res))
+               QR_close(res);
            return SQL_NO_DATA_FOUND;
        }
        else if (retval > 0)
@@ -1013,28 +1366,41 @@ SC_fetch(StatementClass *self)
        else
        {
            mylog("SC_fetch: error\n");
-           SC_set_error(self, STMT_EXEC_ERROR, "Error fetching next row");
-           SC_log_error(func, "", self);
+           SC_set_error(self, STMT_EXEC_ERROR, "Error fetching next row", func);
            return SQL_ERROR;
        }
    }
-
-#ifdef DRIVER_CURSOR_IMPLEMENT
-   if (res->haskeyset)
+   if (QR_haskeyset(res))
    {
-       UWORD   pstatus = res->keyset[self->currTuple].status;
-       if (0 != (pstatus & (CURS_SELF_DELETING | CURS_SELF_DELETED)))
-           return SQL_SUCCESS_WITH_INFO;
-       if (SQL_ROW_DELETED != (pstatus & KEYSET_INFO_PUBLIC) &&
-           0 != (pstatus & CURS_OTHER_DELETED))
-           return SQL_SUCCESS_WITH_INFO;
+       Int4    kres_ridx;
+
+       kres_ridx = GIdx2KResIdx(self->currTuple, self, res);
+       if (kres_ridx >= 0 && kres_ridx < res->num_cached_keys)
+       {
+           UWORD   pstatus = res->keyset[kres_ridx].status;
+inolog("SC_ pstatus[%d]=%x fetch_count=%d\n", kres_ridx, pstatus, self->last_fetch_count);
+           if (0 != (pstatus & (CURS_SELF_DELETING | CURS_SELF_DELETED)))
+               return SQL_SUCCESS_WITH_INFO;
+           if (SQL_ROW_DELETED != (pstatus & KEYSET_INFO_PUBLIC) &&
+                   0 != (pstatus & CURS_OTHER_DELETED))
+               return SQL_SUCCESS_WITH_INFO;
+           if (0 != (CURS_NEEDS_REREAD & pstatus))
+           {
+               UWORD   qcount;
+
+               result = SC_pos_reload(self, self->currTuple, &qcount, 0);
+               if (SQL_ERROR == result)
+                   return result;
+               pstatus &= ~CURS_NEEDS_REREAD;
+           }
+       }
    }
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
 
    num_cols = QR_NumPublicResultCols(res);
 
    result = SQL_SUCCESS;
    self->last_fetch_count++;
+inolog("%s: stmt=%x ommitted++\n", func, self);
    self->last_fetch_count_include_ommitted++;
 
    opts = SC_get_ARDF(self);
@@ -1049,11 +1415,11 @@ SC_fetch(StatementClass *self)
        char        buf[32];
        UInt4   offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
 
-       sprintf(buf, "%ld", (long int) SC_get_bookmark(self));
+       sprintf(buf, "%ld", SC_get_bookmark(self));
        SC_set_current_col(self, -1);
-       result = copy_and_convert_field(self, 0, buf, SQL_C_ULONG,
-                       bookmark->buffer + offset, 0,
-                       (SDWORD *) (bookmark->used ? bookmark->used + (offset >> 2) : NULL));
+       result = copy_and_convert_field(self, 0, buf,
+            SQL_C_ULONG, bookmark->buffer + offset, 0,
+           bookmark->used ? bookmark->used + (offset >> 2) : NULL);
    }
 
    if (self->options.retrieve_data == SQL_RD_OFF)      /* data isn't required */
@@ -1063,7 +1429,7 @@ SC_fetch(StatementClass *self)
        extend_getdata_info(gdata, opts->allocated, TRUE);
    for (lf = 0; lf < num_cols; lf++)
    {
-       mylog("fetch: cols=%d, lf=%d, opts = %u, opts->bindings = %u, buffer[] = %u\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer);
+       mylog("fetch: cols=%d, lf=%d, opts = %x, opts->bindings = %x, buffer[] = %x\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer);
 
        /* reset for SQLGetData */
        gdata->gdata[lf].data_left = -1;
@@ -1077,19 +1443,13 @@ SC_fetch(StatementClass *self)
 
            mylog("type = %d\n", type);
 
-           if (self->manual_result)
-           {
-               if ((ci->drivers.use_declarefetch) && (self->currTuple >= QR_get_num_total_tuples(res)))
-                   value = QR_get_value_manual(res, (self->currTuple >= ci->drivers.fetch_max) ? (self->currTuple % ci->drivers.fetch_max) : self->currTuple, lf);
-                       else
-                   value = QR_get_value_manual(res, self->currTuple, lf);
-               mylog("manual_result\n");
-           }
-           else if (SC_is_fetchcursor(self))
+           if (SC_is_fetchcursor(self))
                value = QR_get_value_backend(res, lf);
            else
            {
-               int curt = GIdx2ResultIdx(self->currTuple, self, res);
+               int curt = GIdx2CacheIdx(self->currTuple, self, res);
+inolog("base=%d curr=%d st=%d\n", QR_get_rowstart_in_cache(res), self->currTuple, SC_get_rowset_start(self));
+inolog("curt=%d\n", curt);
                value = QR_get_value_backend_row(res, curt, lf);
            }
 
@@ -1105,19 +1465,17 @@ SC_fetch(StatementClass *self)
                    break;      /* OK, do next bound column */
 
                case COPY_UNSUPPORTED_TYPE:
-                   SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.");
-                   SC_log_error(func, "", self);
+                   SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.", func);
                    result = SQL_ERROR;
                    break;
 
                case COPY_UNSUPPORTED_CONVERSION:
-                   SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.");
-                   SC_log_error(func, "", self);
+                   SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.", func);
                    result = SQL_ERROR;
                    break;
 
                case COPY_RESULT_TRUNCATED:
-                   SC_set_error(self, STMT_TRUNCATED, "Fetched item was truncated.");
+                   SC_set_error(self, STMT_TRUNCATED, "Fetched item was truncated.", func);
                    qlog("The %dth item was truncated\n", lf + 1);
                    qlog("The buffer size = %d", opts->bindings[lf].buflen);
                    qlog(" and the value is '%s'\n", value);
@@ -1126,7 +1484,6 @@ SC_fetch(StatementClass *self)
 
                    /* error msg already filled in */
                case COPY_GENERAL_ERROR:
-                   SC_log_error(func, "", self);
                    result = SQL_ERROR;
                    break;
 
@@ -1135,8 +1492,7 @@ SC_fetch(StatementClass *self)
                    break;
 
                default:
-                   SC_set_error(self, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.");
-                   SC_log_error(func, "", self);
+                   SC_set_error(self, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.", func);
                    result = SQL_ERROR;
                    break;
            }
@@ -1146,7 +1502,6 @@ SC_fetch(StatementClass *self)
    return result;
 }
 
-#define    return  DONT_CALL_RETURN_FROM_HERE???
 
 RETCODE
 SC_execute(StatementClass *self)
@@ -1161,9 +1516,8 @@ SC_execute(StatementClass *self)
    QueryInfo   qi;
    ConnInfo   *ci;
    UDWORD      qflag = 0;
-   BOOL        is_in_trans;
-   int     func_cs_count = 0;
-
+   BOOL        is_in_trans, issue_begin, has_out_para;
+   int     func_cs_count = 0, i;
 
    conn = SC_get_conn(self);
    ci = &(conn->connInfo);
@@ -1178,31 +1532,54 @@ SC_execute(StatementClass *self)
     * 2) we are in autocommit off state and the statement isn't of type
     * OTHER.
     */
+#define    return  DONT_CALL_RETURN_FROM_HERE???
    ENTER_INNER_CONN_CS(conn, func_cs_count);
    if (CONN_EXECUTING == conn->status)
    {
-       SC_set_error(self, STMT_SEQUENCE_ERROR, "Connection is already in use.");
+       SC_set_error(self, STMT_SEQUENCE_ERROR, "Connection is already in use.", func);
        mylog("%s: problem with connection\n", func);
        goto cleanup;
    }
    is_in_trans = CC_is_in_trans(conn);
-   if (!self->internal && !is_in_trans &&
-       (SC_is_fetchcursor(self) ||
-        (!CC_is_in_autocommit(conn) && self->statement_type != STMT_TYPE_BEGIN)))
+   /* issue BEGIN ? */
+   issue_begin = TRUE;
+   if (self->internal || is_in_trans)
+       issue_begin = FALSE;
+   else if (CC_is_in_autocommit(conn) &&
+        (!SC_is_fetchcursor(self)
+       /* || SC_is_with_hold(self) thiw would lose the performance */
+        ))
+       issue_begin = FALSE;
+   else
    {
-       mylog("   about to begin a transaction on statement = %u\n", self);
+       switch (self->statement_type)
+       {
+           case STMT_TYPE_START:
+           case STMT_TYPE_SPECIAL:
+               issue_begin = FALSE;
+               break;
+       }
+   }
+   if (issue_begin)
+   {
+       mylog("   about to begin a transaction on statement = %x\n", self);
        if (PG_VERSION_GE(conn, 7.1))
            qflag |= GO_INTO_TRANSACTION;
-       else if (!CC_begin(conn))
-       {
-           SC_set_error(self, STMT_EXEC_ERROR, "Could not begin a transaction");
+                else if (!CC_begin(conn))
+                {
+           SC_set_error(self, STMT_EXEC_ERROR, "Could not begin a transaction", func);
            goto cleanup;
-       }
+                }
    }
 
    oldstatus = conn->status;
+   /* self->status = STMT_EXECUTING; */
+   if (!SC_SetExecuting(self, TRUE))
+   {
+       SC_set_error(self, STMT_OPERATION_CANCELLED, "Cancel Reuest Accepted", func);
+       goto cleanup;
+   }
    conn->status = CONN_EXECUTING;
-   self->status = STMT_EXECUTING;
 
    /* If it's a SELECT statement, use a cursor. */
 
@@ -1211,15 +1588,46 @@ SC_execute(StatementClass *self)
     * statement
     */
    /* in copy_statement... */
-   if (self->statement_type == STMT_TYPE_SELECT)
+   if (PREPARED_PERMANENTLY == self->prepared &&
+       PROTOCOL_74(ci))
+   {
+       char    *plan_name = self->plan_name;
+
+       if (issue_begin)
+           CC_begin(conn);
+       res = SC_get_Result(self);
+inolog("get_Result=%x\n", res);
+       if (!plan_name)
+           plan_name = "";
+       if (!SendBindRequest(self, plan_name))
+       {
+           if (SC_get_errornumber(self) <= 0)
+               SC_set_error(self, STMT_EXEC_ERROR, "Bind request error", func);
+           goto cleanup;
+       }
+       if (!SendExecuteRequest(self, plan_name, 0))
+       {
+           if (SC_get_errornumber(self) <= 0)
+               SC_set_error(self, STMT_EXEC_ERROR, "Execute request error", func);
+           goto cleanup;
+       }
+       if (!(res = SendSyncAndReceive(self, res, "bind_and_execute")))
+       {
+           if (SC_get_errornumber(self) <= 0)
+               SC_set_error(self, STMT_EXEC_ERROR, "Could not receive he response, communication down ??", func);
+           CC_on_abort(conn, CONN_DEAD);
+           goto cleanup;
+       }
+   }
+   else if (self->statement_type == STMT_TYPE_SELECT)
    {
        char        fetch[128];
        qflag |= (SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency ? CREATE_KEYSET : 0); 
 
-       mylog("       Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name);
+       mylog("       Sending SELECT statement on stmt=%x, cursor_name='%s' qflag=%d,%d\n", self, SC_cursor_name(self), qflag, self->options.scroll_concurrency);
 
        /* send the declare/select */
-       res = CC_send_query(conn, self->stmt_with_params, NULL, qflag);
+       res = CC_send_query(conn, self->stmt_with_params, NULL, qflag, SC_get_ancestor(self));
        if (SC_is_fetchcursor(self) && res != NULL &&
            QR_command_maybe_successful(res))
        {
@@ -1231,7 +1639,7 @@ SC_execute(StatementClass *self)
             * back
             */
            qi.result_in = NULL;
-           qi.cursor = self->cursor_name;
+           qi.cursor = SC_cursor_name(self);
            qi.row_size = ci->drivers.fetch_max;
 
            /*
@@ -1241,17 +1649,19 @@ SC_execute(StatementClass *self)
             * will correct for any discrepancies in sizes and adjust the
             * cache accordingly.
             */
-           sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name);
+           sprintf(fetch, "fetch %d in \"%s\"", qi.row_size, SC_cursor_name(self));
 
-           res = CC_send_query(conn, fetch, &qi, qflag);
+           res = CC_send_query(conn, fetch, &qi, qflag, SC_get_ancestor(self));
+           if (SC_is_with_hold(self))
+               QR_set_withhold(res);
        }
        mylog("     done sending the query:\n");
    }
    else
    {
        /* not a SELECT statement so don't use a cursor */
-       mylog("      it's NOT a select statement: stmt=%u\n", self);
-       res = CC_send_query(conn, self->stmt_with_params, NULL, qflag);
+       mylog("      it's NOT a select statement: stmt=%x\n", self);
+       res = CC_send_query(conn, self->stmt_with_params, NULL, qflag, SC_get_ancestor(self));
 
        /*
         * We shouldn't send COMMIT. Postgres backend does the autocommit
@@ -1287,24 +1697,18 @@ SC_execute(StatementClass *self)
        else
            SC_set_errornumber(self, was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND);
 
-       if (QR_command_fatal(res) && PQstatus(conn->pgconn) == CONNECTION_BAD)
-           SC_set_errornumber(self, STMT_BAD_ERROR);
-
-       if (SC_get_errornumber(self) == STMT_ERROR_TAKEN_FROM_BACKEND)
-           SC_set_sqlstate(self, CC_get_sqlstate(conn));
-
        /* set cursor before the first tuple in the list */
        self->currTuple = -1;
        SC_set_current_col(self, -1);
-       self->rowset_start = -1;
+       SC_set_rowset_start(self, -1, FALSE);
 
        /* issue "ABORT" when query aborted */
        if (QR_get_aborted(res))
        {
-           if (!self->internal && CC_is_in_trans(conn) && CC_is_in_autocommit(conn) && !CC_is_in_manual_trans(conn))
+#ifdef _LEGACY_MODE_
+           if (!self->internal)
                CC_abort(conn);
-           else
-               QR_set_aborted(res, FALSE);
+#endif /* _LEGACY_MODE */
        }
        else
        {
@@ -1323,20 +1727,55 @@ SC_execute(StatementClass *self)
                if (opts->bindings == NULL)
                {
                    QR_Destructor(res);
-                   SC_set_error(self, STMT_NO_MEMORY_ERROR,"Could not get enough free memory to store the binding information");
+                   SC_set_error(self, STMT_NO_MEMORY_ERROR,"Could not get enough free memory to store the binding information", func);
                    goto cleanup;
                }
            }
+
+inolog("!!%x->SC_is_concat_pre=%x res=%x\n", self, self->miscinfo, res);
+           /*
+            * special handling of result for keyset driven cursors.             * Use the columns info of the 1st query and
+            * user the keyset info of the 2nd query.
+            */
+           if (SQL_CURSOR_KEYSET_DRIVEN == self->options.cursor_type &&
+               SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency &&
+               !SC_is_fetchcursor(self))
+           {
+               if (tres = res->next, tres)
+               {
+                   if (tres->fields)
+                       CI_Destructor(tres->fields);
+                   tres->fields = res->fields;
+                   res->fields = NULL;
+                   tres->num_fields = res->num_fields;
+                   res->next = NULL;
+                   QR_Destructor(res);
+                   SC_init_Result(self);
+                   SC_set_Result(self, tres);
+                   res = tres;
+               }
+           }
+           /* skip the result of PREPARE in 'PREPARE ..:EXECUTE ..' call */
+           else if (SC_is_concat_prepare_exec(self))
+           {
+               tres = res->next;
+inolog("res->next=%x\n", tres);
+               res->next = NULL;
+               SC_set_Result(self, tres);
+               res = tres;
+               SC_set_prepared(self, PREPARED_PERMANENTLY);
+               SC_no_concat_prepare_exec(self);
+           }
        }
    }
    else
    {
        /* Bad Error -- The error message will be in the Connection */
-       if (!conn->pgconn)
-       SC_set_error(self, STMT_BAD_ERROR, CC_get_errormsg(conn));
+       if (!conn->sock)
+           SC_set_error(self, STMT_BAD_ERROR, CC_get_errormsg(conn), func);
        else if (self->statement_type == STMT_TYPE_CREATE)
        {
-           SC_set_error(self, STMT_CREATE_TABLE_ERROR, "Error creating the table");
+           SC_set_error(self, STMT_CREATE_TABLE_ERROR, "Error creating the table", func);
 
            /*
             * This would allow the table to already exists, thus
@@ -1347,14 +1786,18 @@ SC_execute(StatementClass *self)
        }
        else
        {
-           SC_set_error(self, STMT_EXEC_ERROR, CC_get_errormsg(conn));
+           SC_set_error(self, STMT_EXEC_ERROR, CC_get_errormsg(conn), func);
        }
 
-       if (!self->internal && CC_is_in_trans(conn) && CC_is_in_autocommit(conn) && !CC_is_in_manual_trans(conn))
+#ifdef _LEGACY_MODE_
+       if (!self->internal)
            CC_abort(conn);
+#endif /* _LEGACY_MODE_ */
    }
    if (!SC_get_Result(self))
        SC_set_Result(self, res);
+   else if (res == SC_get_Result(self))
+       ;
    else
    {
        QResultClass    *last;
@@ -1364,39 +1807,65 @@ SC_execute(StatementClass *self)
    }
 
    ipdopts = SC_get_IPDF(self);
+   has_out_para = FALSE;
    if (self->statement_type == STMT_TYPE_PROCCALL &&
        (SC_get_errornumber(self) == STMT_OK ||
-        SC_get_errornumber(self) == STMT_INFO_ONLY) &&
-       ipdopts->parameters &&
-       ipdopts->parameters[0].paramType == SQL_PARAM_OUTPUT)
-   {                           /* get the return value of the procedure
-                                * call */
+        SC_get_errornumber(self) == STMT_INFO_ONLY))
+   {
+       Int2    io, out;
+       has_out_para = (CountParameters(self, NULL, &io, &out) > 0);
+   }
+   if (has_out_para)
+   {   /* get the return value of the procedure call */
        RETCODE     ret;
        HSTMT       hstmt = (HSTMT) self;
 
+       self->bind_row = 0;
        ret = SC_fetch(hstmt);
+inolog("!!SC_fetch return =%d\n", ret);
        if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
        {
            APDFields   *apdopts = SC_get_APDF(self);
-
-           ret = PGAPI_GetData(hstmt, 1,
-                       apdopts->parameters[0].CType,
-                       apdopts->parameters[0].buffer,
-                       apdopts->parameters[0].buflen,
-                       (SDWORD *) apdopts->parameters[0].used);
-           if (ret != SQL_SUCCESS)
+           UInt4   offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0;
+           ARDFields   *ardopts = SC_get_ARDF(self);
+           const ParameterInfoClass    *apara;
+           const ParameterImplClass    *ipara;
+           int save_bind_size = ardopts->bind_size, gidx, num_p;
+
+           ardopts->bind_size = apdopts->param_bind_type;
+           num_p = self->num_params;
+           if (ipdopts->allocated < num_p)
+               num_p = ipdopts->allocated;
+           for (i = 0, gidx = 0; i < num_p; i++)
            {
-               SC_set_error(self, STMT_EXEC_ERROR, "GetData to Procedure return failed.");
+               ipara = ipdopts->parameters + i;
+               if (ipara->paramType == SQL_PARAM_OUTPUT ||
+                   ipara->paramType == SQL_PARAM_INPUT_OUTPUT)
+               {
+                   apara = apdopts->parameters + i;    
+                   ret = PGAPI_GetData(hstmt, gidx + 1, apara->CType, apara->buffer + offset, apara->buflen, apara->used ? apara->used + (offset >> 2) : NULL);
+                   if (ret != SQL_SUCCESS)
+                   {
+                       SC_set_error(self, STMT_EXEC_ERROR, "GetData to Procedure return failed.", func);
+                       break;
+                   }
+                   gidx++;
+               }
            }
+           ardopts->bind_size = save_bind_size; /* restore */
        }
        else
        {
-           SC_set_error(self, STMT_EXEC_ERROR, "SC_fetch to get a Procedure return failed.");
+           SC_set_error(self, STMT_EXEC_ERROR, "SC_fetch to get a Procedure return failed.", func);
        }
    }
-#undef return
 cleanup:
+#undef return
+   SC_SetExecuting(self, FALSE);
    CLEANUP_FUNC_CONN_CS(func_cs_count, conn);
+   if (CONN_DOWN != conn->status)
+       conn->status = oldstatus;
+   /* self->status = STMT_FINISHED; */
    if (SC_get_errornumber(self) == STMT_OK)
        return SQL_SUCCESS;
    else if (SC_get_errornumber(self) == STMT_INFO_ONLY)
@@ -1404,8 +1873,10 @@ cleanup:
    else
    {
        if (!SC_get_errormsg(self) || !SC_get_errormsg(self)[0])
+       {
            SC_set_errormsg(self, "Error while executing the query");
-       SC_log_error(func, "", self);
+           SC_log_error(func, NULL, self);
+       }
        return SQL_ERROR;
    }
 }
@@ -1415,10 +1886,9 @@ int enqueueNeedDataCallback(StatementClass *stmt, NeedDataCallfunc func, void *d
 {
    if (stmt->num_callbacks >= stmt->allocated_callbacks)
    {
-       SC_REALLOC_return_with_error(stmt->callbacks, NeedDataCallback,
+       stmt->callbacks = (NeedDataCallback *) realloc(stmt->callbacks,
            sizeof(NeedDataCallback) * (stmt->allocated_callbacks +
-               CALLBACK_ALLOC_ONCE), stmt,
-            "Couldn't alloc callbacks", -1) 
+               CALLBACK_ALLOC_ONCE));
        stmt->allocated_callbacks += CALLBACK_ALLOC_ONCE;
    }
    stmt->callbacks[stmt->num_callbacks].func = func;
@@ -1463,12 +1933,13 @@ void    cancelNeedDataState(StatementClass *stmt)
        if (stmt->callbacks[i].data)
            free(stmt->callbacks[i].data);
    }
-   stmt->execute_delegate = NULL;
+   SC_reset_delegate(SQL_ERROR, stmt);
 }
 
 void
 SC_log_error(const char *func, const char *desc, const StatementClass *self)
 {
+   const   char *head;
 #ifdef PRN_NULLCHECK
 #define nullcheck(a) (a ? a : "(NULL)")
 #endif
@@ -1479,34 +1950,46 @@ SC_log_error(const char *func, const char *desc, const StatementClass *self)
        const APDFields *apdopts = SC_get_APDF(self);
        int rowsetSize;
 
+#if (ODBCVER >= 0x0300)
        rowsetSize = (7 == self->transition_status ? opts->size_of_rowset_odbc2 : opts->size_of_rowset);
-
-       qlog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, sqlstate=%s, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__sqlstate), nullcheck(self->__error_message));
-       mylog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, sqlstate=%s, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__sqlstate), nullcheck(self->__error_message));
-       qlog("                 ------------------------------------------------------------\n");
-       qlog("                 hdbc=%u, stmt=%u, result=%u\n", self->hdbc, self, res);
-       qlog("                 manual_result=%d, prepare=%d, internal=%d\n", self->manual_result, self->prepare, self->internal);
-       qlog("                 bindings=%u, bindings_allocated=%d\n", opts->bindings, opts->allocated);
-       qlog("                 parameters=%u, parameters_allocated=%d\n", apdopts->parameters, apdopts->allocated);
-       qlog("                 statement_type=%d, statement='%s'\n", self->statement_type, nullcheck(self->statement));
-       qlog("                 stmt_with_params='%s'\n", nullcheck(self->stmt_with_params));
-       qlog("                 data_at_exec=%d, current_exec_param=%d, put_data=%d\n", self->data_at_exec, self->current_exec_param, self->put_data);
-       qlog("                 currTuple=%d, current_col=%d, lobj_fd=%d\n", self->currTuple, self->current_col, self->lobj_fd);
-       qlog("                 maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->options.maxRows, rowsetSize, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency);
-       qlog("                 cursor_name='%s'\n", nullcheck(self->cursor_name));
-
-       qlog("                 ----------------QResult Info -------------------------------\n");
-
-       if (res)
+#else
+       rowsetSize = opts->size_of_rowset_odbc2;
+#endif /* ODBCVER */
+       if (SC_get_errornumber(self) <= 0)
+           head = "STATEMENT WARNING";
+       else
        {
-           qlog("                 fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn);
-           qlog("                 fetch_count=%d, num_total_rows=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->num_total_rows, res->num_fields, nullcheck(res->cursor));
-           qlog("                 message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice));
-           qlog("                 status=%d, inTuples=%d\n", res->status, res->inTuples);
+           head = "STATEMENT ERROR";
+           qlog("%s: func=%s, desc='%s', errnum=%d, errmsg='%s'\n",head, func, desc, self->__error_number, nullcheck(self->__error_message));
        }
+       mylog("%s: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", head, func, desc, self->__error_number, nullcheck(self->__error_message));
+       if (SC_get_errornumber(self) > 0)
+       {
+           qlog("                 ------------------------------------------------------------\n");
+           qlog("                 hdbc=%x, stmt=%x, result=%x\n", self->hdbc, self, res);
+           qlog("                 prepare=%d, internal=%d\n", self->prepare, self->internal);
+           qlog("                 bindings=%x, bindings_allocated=%d\n", opts->bindings, opts->allocated);
+           qlog("                 parameters=%x, parameters_allocated=%d\n", apdopts->parameters, apdopts->allocated);
+           qlog("                 statement_type=%d, statement='%s'\n", self->statement_type, nullcheck(self->statement));
+           qlog("                 stmt_with_params='%s'\n", nullcheck(self->stmt_with_params));
+           qlog("                 data_at_exec=%d, current_exec_param=%d, put_data=%d\n", self->data_at_exec, self->current_exec_param, self->put_data);
+           qlog("                 currTuple=%d, current_col=%d, lobj_fd=%d\n", self->currTuple, self->current_col, self->lobj_fd);
+           qlog("                 maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->options.maxRows, rowsetSize, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency);
+           qlog("                 cursor_name='%s'\n", SC_cursor_name(self));
+
+           qlog("                 ----------------QResult Info -------------------------------\n");
+
+           if (res)
+           {
+               qlog("                 fields=%x, backend_tuples=%x, tupleField=%d, conn=%x\n", res->fields, res->backend_tuples, res->tupleField, res->conn);
+               qlog("                 fetch_count=%d, num_total_rows=%d, num_fields=%d, cursor='%s'\n", res->fetch_number, QR_get_num_total_tuples(res), res->num_fields, nullcheck(QR_get_cursor(res)));
+               qlog("                 message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice));
+               qlog("                 status=%d, inTuples=%d\n", QR_get_rstatus(res), QR_is_fetching_tuples(res));
+           }
 
-       /* Log the connection error if there is one */
-       CC_log_error(func, desc, self->hdbc);
+           /* Log the connection error if there is one */
+           CC_log_error(func, desc, self->hdbc);
+       }
    }
    else
    {
@@ -1515,3 +1998,426 @@ SC_log_error(const char *func, const char *desc, const StatementClass *self)
    }
 #undef PRN_NULLCHECK
 }
+
+/*
+ * Extended Query 
+ */
+
+BOOL
+SendBindRequest(StatementClass *stmt, const char *plan_name)
+{
+   CSTR    func = "SendBindRequest";
+   ConnectionClass *conn = SC_get_conn(stmt);
+   SocketClass *sock = conn->sock;
+
+   mylog("%s: plan_name=%s\n", func, plan_name);
+   if (!BuildBindRequest(stmt, plan_name))
+       return FALSE;
+
+   return TRUE;
+}
+
+QResultClass *SendSyncAndReceive(StatementClass *stmt, QResultClass *res, const char *comment)
+{
+   CSTR func = "SendSyncAndReceive";
+   ConnectionClass *conn = SC_get_conn(stmt);
+   SocketClass *sock = conn->sock;
+   char        id;
+   Int4        response_length;
+   UInt4       oid;
+   int     num_p, num_io_params;
+   int     i;
+   Int2        num_discard_params, paramType;
+   BOOL        rcvend = FALSE, msg_truncated;
+   char        msgbuffer[ERROR_MSG_LENGTH + 1];
+   IPDFields   *ipdopts;
+   QResultClass    *newres = NULL;
+
+   if (CC_is_in_trans(conn) && !SC_accessed_db(stmt))
+   { 
+       if (SQL_ERROR == SetStatementSvp(stmt))
+       {
+           SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal savepoint error in SendSynAndReceive", func);
+           return FALSE;
+       }
+   }
+
+   SOCK_put_char(sock, 'S');   /* Sync message */
+   SOCK_put_int(sock, 4, 4);
+   SOCK_flush_output(sock);
+
+   if (!res)
+       newres = res = QR_Constructor();
+   for (;!rcvend;)
+   {
+       id = SOCK_get_id(sock);
+       if ((SOCK_get_errcode(sock) != 0) || (id == EOF))
+       {
+           SC_set_error(stmt, CONNECTION_NO_RESPONSE, "No response rom the backend", func);
+
+           mylog("%s: 'id' - %s\n", func, SC_get_errormsg(stmt));
+           CC_on_abort(conn, CONN_DEAD);
+           QR_Destructor(newres);
+           return NULL;
+       }
+inolog("desc id=%c", id);
+       response_length = SOCK_get_response_length(sock);
+inolog(" response_length=%d\n", response_length);
+       switch (id)
+       {
+           case 'C':
+               SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+               mylog("command response=%s\n", msgbuffer);
+               QR_set_command(res, msgbuffer);
+               if (QR_is_fetching_tuples(res))
+               {
+                   QR_set_no_fetching_tuples(res);
+                   /* in case of FETCH, Portal Suspend never arrives */
+                   if (strnicmp(msgbuffer, "SELECT", 6) == 0)
+                   {
+                       mylog("%s: reached eof now\n", func);
+                       QR_set_reached_eof(res);
+                   }
+               }
+               break;
+           case 'E': /* ErrorMessage */
+               msg_truncated = handle_error_message(conn, msgbuffer, sizeof(msgbuffer), res->sqlstate, comment, res);
+
+               rcvend = TRUE;
+               break;
+           case 'N': /* Notice */
+               msg_truncated = handle_notice_message(conn, msgbuffer, sizeof(msgbuffer), res->sqlstate, comment, res);
+               break;
+           case '1': /* ParseComplete */
+               if (stmt->plan_name)
+                   SC_set_prepared(stmt, PREPARED_PERMANENTLY);
+               else
+                   SC_set_prepared(stmt, PREPARED_TEMPORARILY);
+               break;
+           case '2': /* BindComplete */
+               QR_set_fetching_tuples(res);
+               break;
+           case '3': /* CloseComplete */
+               QR_set_no_fetching_tuples(res);
+               break;
+           case 'Z': /* ReadyForQuery */
+               rcvend = TRUE;
+               EatReadyForQuery(conn);
+               break;
+           case 't': /* ParameterDesription */
+               num_p = SOCK_get_int(sock, 2);
+inolog("num_params=%d info=%d\n", stmt->num_params, num_p);
+               num_discard_params = 0;
+               if (stmt->discard_output_params)
+                   CountParameters(stmt, NULL, NULL, &num_discard_params);
+               if (num_discard_params < stmt->proc_return)
+                   num_discard_params = stmt->proc_return;
+               if (num_p + num_discard_params != (int) stmt->num_params)
+               {
+                   mylog("ParamInfo unmatch num_params=%d! info=%d+discard=%d\n", stmt->num_params, num_p, num_discard_params);
+                   stmt->num_params = (Int2) num_p + num_discard_params;
+               }
+               ipdopts = SC_get_IPDF(stmt);
+               extend_iparameter_bindings(ipdopts, stmt->num_params);
+               if (stmt->discard_output_params)
+               {
+                   for (i = stmt->proc_return; i < stmt->num_params; i++)
+                   {
+                       paramType = ipdopts->parameters[i].paramType;
+                       if (SQL_PARAM_OUTPUT == paramType)
+                           continue;
+                       oid = SOCK_get_int(sock, 4);
+                       ipdopts->parameters[i].PGType = oid;
+                   }
+               }
+               else
+               {
+                   for (i = 0; i < num_p; i++)
+                   {
+                       paramType = ipdopts->parameters[i].paramType;   
+                       oid = SOCK_get_int(sock, 4);
+                       if (SQL_PARAM_OUTPUT != paramType ||
+                           PG_TYPE_VOID != oid)
+                           ipdopts->parameters[i + stmt->proc_return].PGType = oid;
+                   }
+               }
+               break;
+           case 'T': /* RowDesription */
+               QR_set_conn(res, conn);
+               if (CI_read_fields(res->fields, conn))
+               {
+                   Int2    dummy1, dummy2;
+                   int cidx;
+
+                   QR_set_rstatus(res, PGRES_FIELDS_OK);
+                   res->num_fields = CI_get_num_fields(res->fields);
+                   if (QR_haskeyset(res))
+                       res->num_fields -= res->num_key_fields;
+                   num_io_params = CountParameters(stmt, NULL, &dummy1, &dummy2);
+                   if (stmt->proc_return > 0 ||
+                       num_io_params > 0)
+                   {
+                       ipdopts = SC_get_IPDF(stmt);
+                       extend_iparameter_bindings(ipdopts, stmt->num_params);
+                       for (i = 0, cidx = 0; i < stmt->num_params; i++)
+                       {
+                           if (i < stmt->proc_return)
+                               ipdopts->parameters[i].paramType = SQL_PARAM_OUTPUT;
+                           paramType =ipdopts->parameters[i].paramType;
+                           if (SQL_PARAM_OUTPUT == paramType ||
+                               SQL_PARAM_INPUT_OUTPUT == paramType)
+                           {
+inolog("!![%d].PGType %u->%u\n", i, ipdopts->parameters[i].PGType, res->fields->adtid[cidx]);
+                               ipdopts->parameters[i].PGType = res->fields->adtid[cidx];
+                               cidx++;
+                           }
+                       }
+                   }
+               }
+               else
+               {
+                   QR_set_rstatus(res, PGRES_BAD_RESPONSE);
+                   QR_set_message(res, "Error reading field information");
+                   rcvend = TRUE;
+               }
+               break;
+           case 'B': /* Binary data */
+           case 'D': /* ASCII data */
+               QR_get_tupledata(res, id == 'B');
+               break;
+           case 'S': /* parameter status */
+               getParameterValues(conn);
+               break;
+           case 's':   /* portal suspend */
+               QR_set_no_fetching_tuples(res);
+               break;
+           default:
+               break;
+       }
+   }
+   return res;
+}
+
+BOOL
+SendParseRequest(StatementClass *stmt, const char *plan_name, const char *query)
+{
+   CSTR    func = "SendParseRequest";
+   ConnectionClass *conn = SC_get_conn(stmt);
+   SocketClass *sock = conn->sock;
+   unsigned long   pileng, leng;
+
+   mylog("%s: plan_name=%s query=%s\n", func, plan_name, query);
+   if (CC_is_in_trans(conn) && !SC_accessed_db(stmt))
+   { 
+       if (SQL_ERROR == SetStatementSvp(stmt))
+       {
+           SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal savepoint error in SendParseRequest", func);
+           return FALSE;
+       }
+   }
+   SOCK_put_char(sock, 'P');
+   if (SOCK_get_errcode(sock) != 0)
+   {
+       CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send P request to backend", func);
+       CC_on_abort(conn, CONN_DEAD);
+       return FALSE;
+   }
+
+   pileng = sizeof(Int2);
+   if (!stmt->discard_output_params)
+       pileng += sizeof(UInt4) * (stmt->num_params - stmt->proc_return); 
+   leng = strlen(plan_name) + 1 + strlen(query) + 1 + pileng;
+   SOCK_put_int(sock, leng + 4, 4);
+inolog("parse leng=%d\n", leng);
+   SOCK_put_string(sock, plan_name);
+   SOCK_put_string(sock, query);
+   SOCK_put_int(sock, stmt->num_params - stmt->proc_return, sizeof(Int2)); /* number of parameters unspecified */
+   if (!stmt->discard_output_params)
+   {
+       int i;
+       IPDFields   *ipdopts = SC_get_IPDF(stmt);
+
+       for (i = stmt->proc_return; i < stmt->num_params; i++)
+       {
+           if (i < ipdopts->allocated &&
+               SQL_PARAM_OUTPUT == ipdopts->parameters[i].paramType)
+               SOCK_put_int(sock, PG_TYPE_VOID, sizeof(UInt4));
+           else
+               SOCK_put_int(sock, 0, sizeof(UInt4));
+       }
+   }
+
+   return TRUE;
+}
+
+BOOL
+SendDescribeRequest(StatementClass *stmt, const char *plan_name)
+{
+   CSTR    func = "SendDescribeRequest";
+   ConnectionClass *conn = SC_get_conn(stmt);
+   SocketClass *sock = conn->sock;
+   unsigned long   leng;
+   BOOL        sockerr = FALSE;
+
+   mylog("%s:plan_name=%s\n", func, plan_name);
+   if (CC_is_in_trans(conn) && !SC_accessed_db(stmt))
+   {
+       if (SQL_ERROR == SetStatementSvp(stmt))
+       {
+           SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal savepoint error", func);
+           return FALSE;
+       }
+   }
+   SOCK_put_char(sock, 'D');
+   if (SOCK_get_errcode(sock) != 0)
+       sockerr = TRUE;
+   if (!sockerr)
+   {
+       leng = 1 + strlen(plan_name) + 1;
+       SOCK_put_int(sock, leng + 4, 4);
+       if (SOCK_get_errcode(sock) != 0)
+           sockerr = TRUE;
+   }
+   if (!sockerr)
+   {
+inolog("describe leng=%d\n", leng);
+       SOCK_put_char(sock, 'S');
+       if (SOCK_get_errcode(sock) != 0)
+           sockerr = TRUE;
+   }
+   if (!sockerr)
+   {
+       SOCK_put_string(sock, plan_name);
+       if (SOCK_get_errcode(sock) != 0)
+           sockerr = TRUE;
+   }
+   if (sockerr)
+   {
+       CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send D Request to backend", func);
+       CC_on_abort(conn, CONN_DEAD);
+       return FALSE;
+   }
+
+   return TRUE;
+}
+
+BOOL
+SendExecuteRequest(StatementClass *stmt, const char *plan_name, UInt4 count)
+{
+   CSTR    func = "SendExecuteRequest";
+   ConnectionClass *conn;
+   SocketClass *sock;
+   unsigned long   leng;
+
+   if (!stmt)  return FALSE;
+   if (conn = SC_get_conn(stmt), !conn)    return FALSE;
+   if (sock = conn->sock, !sock)   return FALSE;
+
+   mylog("%s: plan_name=%s count=%d\n", func, plan_name, count);
+   if (CC_is_in_trans(conn) && !SC_accessed_db(stmt))
+   {
+       if (SQL_ERROR == SetStatementSvp(stmt))
+       {
+           SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal savepoint error", func);
+           return FALSE;
+       }
+   }
+   SOCK_put_char(sock, 'E');
+   if (SOCK_get_errcode(sock) != 0)
+   {
+       CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send D Request to backend", func);
+       CC_on_abort(conn, CONN_DEAD);
+       return FALSE;
+   }
+
+   leng = strlen(plan_name) + 1 + 4;
+   SOCK_put_int(sock, leng + 4, 4);
+inolog("execute leng=%d\n", leng);
+   SOCK_put_string(sock, plan_name);
+   SOCK_put_int(sock, count, 4);
+
+   return TRUE;
+}
+
+BOOL   SendSyncRequest(ConnectionClass *conn)
+{
+   SocketClass *sock = conn->sock;
+
+   SOCK_put_char(sock, 'S');   /* Sync message */
+   SOCK_put_int(sock, 4, 4);
+   SOCK_flush_output(sock);
+
+   return TRUE;
+}
+
+enum {
+   CancelRequestSet    = 1L
+   ,CancelRequestAccepted  = (1L << 1)
+   ,CancelCompleted    = (1L << 2)
+};
+/* commonly used for short term lock */
+#if defined(WIN_MULTITHREAD_SUPPORT)
+extern  CRITICAL_SECTION        common_cs;
+#elif defined(POSIX_MULTITHREAD_SUPPORT)
+extern  pthread_mutex_t         common_cs;
+#endif /* WIN_MULTITHREAD_SUPPORT */
+BOOL   SC_IsExecuting(const StatementClass *self)
+{
+   BOOL    ret;
+   ENTER_COMMON_CS; /* short time blocking */
+   ret = (STMT_EXECUTING == self->status);
+   LEAVE_COMMON_CS;
+   return ret;
+}
+BOOL   SC_SetExecuting(StatementClass *self, BOOL on)
+{
+   BOOL    exeSet = FALSE; 
+   ENTER_COMMON_CS; /* short time blocking */
+   if (on)
+   {
+       if (0 == (self->cancel_info & CancelRequestSet))
+       {
+           self->status = STMT_EXECUTING;
+           exeSet = TRUE;
+       }
+   }
+   else
+   {
+       self->cancel_info = 0;
+       self->status = STMT_FINISHED;
+       exeSet = TRUE;
+   }   
+   LEAVE_COMMON_CS;
+   return exeSet;
+}
+BOOL   SC_SetCancelRequest(StatementClass *self)
+{
+   BOOL    enteredCS = FALSE;
+
+   ENTER_COMMON_CS;
+   if (0 != (self->cancel_info & CancelCompleted))
+       ;
+   else if (STMT_EXECUTING == self->status)
+   {
+       self->cancel_info |= CancelRequestSet;
+   }
+   else
+   {
+       /* try to acquire */
+       if (TRY_ENTER_STMT_CS(self))
+           enteredCS = TRUE;
+       else
+           self->cancel_info |= CancelRequestSet;
+   }   
+   LEAVE_COMMON_CS;
+   return enteredCS;
+}
+BOOL   SC_AcceptedCancelRequest(const StatementClass *self)
+{
+   BOOL    shouldCancel = FALSE;
+   ENTER_COMMON_CS;
+   if (0 != (self->cancel_info & (CancelRequestSet | CancelRequestAccepted | CancelCompleted)))
+       shouldCancel = TRUE;
+   LEAVE_COMMON_CS;
+   return shouldCancel;
+}
index 8e8270dcb112581f46f5b41c584cf199e60d6421..f30b9a25adcbd4516e4209b1074b4b21ae8b508f 100644 (file)
@@ -12,6 +12,7 @@
 #include "psqlodbc.h"
 #include <time.h>
 
+#include "pgtypes.h"
 #include "bind.h"
 #include "descriptor.h"
 
@@ -19,7 +20,6 @@
 #include <pthread.h>
 #endif
 
-
 typedef enum
 {
    STMT_ALLOCATED,             /* The statement handle is allocated, but
@@ -36,68 +36,97 @@ typedef enum
    STMT_FINISHED,              /* statement execution has finished */
    STMT_EXECUTING              /* statement execution is still going on */
 } STMT_Status;
-
-#define STMT_ROW_VERSION_CHANGED                   (-4)
-#define STMT_POS_BEFORE_RECORDSET                  (-3)
-#define STMT_TRUNCATED                         (-2)
-#define STMT_INFO_ONLY                         (-1)    /* not an error message,
-                                                        * just a notification
-                                                        * to be returned by
-                                                        * SQLError */
-#define STMT_OK                                    0       /* will be interpreted
-                                                        * as "no error pending" */
-#define STMT_EXEC_ERROR                            1
-#define STMT_STATUS_ERROR                      2
-#define STMT_SEQUENCE_ERROR                        3
-#define STMT_NO_MEMORY_ERROR                   4
-#define STMT_COLNUM_ERROR                      5
-#define STMT_NO_STMTSTRING                     6
-#define STMT_ERROR_TAKEN_FROM_BACKEND          7
-#define STMT_INTERNAL_ERROR                        8
-#define STMT_STILL_EXECUTING                   9
-#define STMT_NOT_IMPLEMENTED_ERROR             10
-#define STMT_BAD_PARAMETER_NUMBER_ERROR            11
-#define STMT_OPTION_OUT_OF_RANGE_ERROR         12
-#define STMT_INVALID_COLUMN_NUMBER_ERROR       13
-#define STMT_RESTRICTED_DATA_TYPE_ERROR            14
-#define STMT_INVALID_CURSOR_STATE_ERROR            15
-#define STMT_OPTION_VALUE_CHANGED              16
-#define STMT_CREATE_TABLE_ERROR                    17
-#define STMT_NO_CURSOR_NAME                        18
-#define STMT_INVALID_CURSOR_NAME               19
-#define STMT_INVALID_ARGUMENT_NO               20
-#define STMT_ROW_OUT_OF_RANGE                  21
-#define STMT_OPERATION_CANCELLED               22
-#define STMT_INVALID_CURSOR_POSITION           23
-#define STMT_VALUE_OUT_OF_RANGE                    24
-#define STMT_OPERATION_INVALID                 25
-#define STMT_PROGRAM_TYPE_OUT_OF_RANGE         26
-#define STMT_BAD_ERROR                         27
-#define STMT_INVALID_OPTION_IDENTIFIER                 28
-#define STMT_RETURN_NULL_WITHOUT_INDICATOR             29
-#define STMT_ERROR_IN_ROW                      30
-#define STMT_INVALID_DESCRIPTOR_IDENTIFIER             31
-#define STMT_OPTION_NOT_FOR_THE_DRIVER                 32
-#define STMT_FETCH_OUT_OF_RANGE                        33
-#define STMT_COUNT_FIELD_INCORRECT                 34
+/*
+ *     ERROR status code
+ *
+ *     The code for warnings must be minus
+ *     and  LOWEST_STMT_ERROR must be set to
+ *     the least code number.
+ *     The code for STMT_OK is 0 and error
+ *     codes follow after it.
+ */    
+enum {
+   LOWEST_STMT_ERROR       =       (-6)
+   /* minus values mean warning returns */
+   ,STMT_ERROR_IN_ROW      =       (-6)
+   ,STMT_OPTION_VALUE_CHANGED  =       (-5)
+   ,STMT_ROW_VERSION_CHANGED   =       (-4)
+   ,STMT_POS_BEFORE_RECORDSET  =       (-3)
+   ,STMT_TRUNCATED         =       (-2)
+   ,STMT_INFO_ONLY         =       (-1)
+               /* not an error message,
+                * just a notification
+                * to be returned by
+                * SQLError
+                */
+   ,STMT_OK            =       0
+   ,STMT_EXEC_ERROR
+   ,STMT_STATUS_ERROR
+   ,STMT_SEQUENCE_ERROR
+   ,STMT_NO_MEMORY_ERROR
+   ,STMT_COLNUM_ERROR
+   ,STMT_NO_STMTSTRING
+   ,STMT_ERROR_TAKEN_FROM_BACKEND
+   ,STMT_INTERNAL_ERROR
+   ,STMT_STILL_EXECUTING
+   ,STMT_NOT_IMPLEMENTED_ERROR
+   ,STMT_BAD_PARAMETER_NUMBER_ERROR
+   ,STMT_OPTION_OUT_OF_RANGE_ERROR 
+   ,STMT_INVALID_COLUMN_NUMBER_ERROR
+   ,STMT_RESTRICTED_DATA_TYPE_ERROR
+   ,STMT_INVALID_CURSOR_STATE_ERROR
+   ,STMT_CREATE_TABLE_ERROR
+   ,STMT_NO_CURSOR_NAME
+   ,STMT_INVALID_CURSOR_NAME
+   ,STMT_INVALID_ARGUMENT_NO
+   ,STMT_ROW_OUT_OF_RANGE
+   ,STMT_OPERATION_CANCELLED
+   ,STMT_INVALID_CURSOR_POSITION
+   ,STMT_VALUE_OUT_OF_RANGE
+   ,STMT_OPERATION_INVALID
+   ,STMT_PROGRAM_TYPE_OUT_OF_RANGE
+   ,STMT_BAD_ERROR
+   ,STMT_INVALID_OPTION_IDENTIFIER
+   ,STMT_RETURN_NULL_WITHOUT_INDICATOR
+   ,STMT_INVALID_DESCRIPTOR_IDENTIFIER
+   ,STMT_OPTION_NOT_FOR_THE_DRIVER
+   ,STMT_FETCH_OUT_OF_RANGE
+   ,STMT_COUNT_FIELD_INCORRECT
+   ,STMT_INVALID_NULL_ARG
+};
 
 /* statement types */
 enum
 {
-   STMT_TYPE_UNKNOWN = -2,
-   STMT_TYPE_OTHER = -1,
-   STMT_TYPE_SELECT = 0,
-   STMT_TYPE_INSERT,
-   STMT_TYPE_UPDATE,
-   STMT_TYPE_DELETE,
-   STMT_TYPE_CREATE,
-   STMT_TYPE_ALTER,
-   STMT_TYPE_DROP,
-   STMT_TYPE_GRANT,
-   STMT_TYPE_REVOKE,
-   STMT_TYPE_PROCCALL,
-   STMT_TYPE_LOCK,
-   STMT_TYPE_BEGIN
+   STMT_TYPE_UNKNOWN = -2
+   ,STMT_TYPE_OTHER = -1
+   ,STMT_TYPE_SELECT = 0
+   ,STMT_TYPE_INSERT
+   ,STMT_TYPE_UPDATE
+   ,STMT_TYPE_DELETE
+   ,STMT_TYPE_CREATE
+   ,STMT_TYPE_ALTER
+   ,STMT_TYPE_DROP
+   ,STMT_TYPE_GRANT
+   ,STMT_TYPE_REVOKE
+   ,STMT_TYPE_PROCCALL
+   ,STMT_TYPE_LOCK
+   ,STMT_TYPE_TRANSACTION
+   ,STMT_TYPE_CLOSE
+   ,STMT_TYPE_FETCH
+   ,STMT_TYPE_PREPARE
+   ,STMT_TYPE_EXECUTE
+   ,STMT_TYPE_DEALLOCATE
+   ,STMT_TYPE_ANALYZE
+   ,STMT_TYPE_NOTIFY
+   ,STMT_TYPE_EXPLAIN
+   ,STMT_TYPE_SET
+   ,STMT_TYPE_RESET
+   ,STMT_TYPE_DECLARE
+   ,STMT_TYPE_MOVE
+   ,STMT_TYPE_COPY
+   ,STMT_TYPE_START
+   ,STMT_TYPE_SPECIAL
 };
 
 #define STMT_UPDATE(stmt)  (stmt->statement_type > STMT_TYPE_SELECT)
@@ -106,10 +135,15 @@ enum
 /* Parsing status */
 enum
 {
-   STMT_PARSE_NONE = 0,
-   STMT_PARSE_COMPLETE,
-   STMT_PARSE_INCOMPLETE,
-   STMT_PARSE_FATAL
+   STMT_PARSE_NONE = 0
+   ,STMT_PARSE_COMPLETE    /* the driver parsed the statement */
+   ,STMT_PARSE_INCOMPLETE
+   ,STMT_PARSE_FATAL
+   ,STMT_PARSE_MASK = 3L
+   ,STMT_PARSED_OIDS = (1L << 2)
+   ,STMT_FOUND_KEY = (1L << 3)
+   ,STMT_HAS_ROW_DESCRIPTION = (1L << 4) /* already got the col info */
+   ,STMT_REFLECTED_ROW_DESCRIPTION = (1L << 5)
 };
 
 /* Result style */
@@ -120,6 +154,8 @@ enum
    STMT_FETCH_EXTENDED
 };
 
+#define    PG_NUM_NORMAL_KEYS  2
+
 typedef    RETCODE (*NeedDataCallfunc)(RETCODE, void *);
 typedef    struct
 {
@@ -151,75 +187,76 @@ struct StatementClass_
    STMT_Status status;
    char       *__error_message;
    int         __error_number;
-   char        __sqlstate[SQLSTATE_LENGTH];
+   PG_ErrorInfo    *pgerror;
 
-   Int4        currTuple;      /* current absolute row number (GetData,
-                                * SetPos, SQLFetch) */
+   SQLLEN      currTuple;  /* current absolute row number (GetData,
+                        * SetPos, SQLFetch) */
    GetDataInfo gdata_info;
-   int         save_rowset_size;       /* saved rowset size in case of
-                                        * change/FETCH_NEXT */
-   Int4            rowset_start;   /* start of rowset (an absolute row
+   int     save_rowset_size;   /* saved rowset size in case of
+                            * change/FETCH_NEXT */
+   SQLLEN      rowset_start;   /* start of rowset (an absolute row
                                 * number) */
-   int         bind_row;       /* current offset for Multiple row/column
-                                * binding */
-   int         last_fetch_count;       /* number of rows retrieved in
-                                        * last fetch/extended fetch */
-   int         current_col;    /* current column for GetData -- used to
-                                * handle multiple calls */
-   int         lobj_fd;        /* fd of the current large object */
+   Int2        bind_row;   /* current offset for Multiple row/column
+                        * binding */
+   Int2        current_col;    /* current column for GetData -- used to
+                        * handle multiple calls */
+   int     last_fetch_count;   /* number of rows retrieved in
+                        * last fetch/extended fetch */
+   int     lobj_fd;        /* fd of the current large object */
 
    char       *statement;      /* if non--null pointer to the SQL
-                                * statement that has been executed */
-
-   TABLE_INFO **ti;
-   int         ntab;
-
-   int         parse_status;
-
-   int         statement_type; /* According to the defines above */
-   int         data_at_exec;   /* Number of params needing SQLPutData */
-   int         current_exec_param;     /* The current parameter for
-                                        * SQLPutData */
+                    * statement that has been executed */
+
+   TABLE_INFO  **ti;
+   Int2        ntab;
+   Int2        num_key_fields;
+   char        parse_status;
+   char        proc_return;
+   Int2        statement_type; /* According to the defines above */
+   int     data_at_exec;   /* Number of params needing SQLPutData */
+   int     current_exec_param;     /* The current parameter for
+                            * SQLPutData */
    PutDataInfo pdata_info;
-
    char        put_data;       /* Has SQLPutData been called yet? */
-
-   char        errormsg_created;       /* has an informative error msg
-                                        * been created?  */
-   char        manual_result;  /* Is the statement result manually built? */
-   char        prepare;        /* is this statement a prepared statement ? */
-   char        prepared;       /* is this statement already
-                        * prepared at the server ? */
-   char        internal;       /* Is this statement being called
-                                * internally? */
+                       /* been created ? */
+   char        catalog_result;  /* Is this a result of catalog function ? */
+   char        prepare;    /* is this statement a prepared statement ? */
+   char        prepared;   /* is this statement already
+                    * prepared at the server ? */
+   char        internal;   /* Is this statement being called
+                            * internally ? */
 
    char        transition_status;  /* Transition status */
-   char        cursor_name[MAX_CURSOR_LEN + 1];
-
-   Int2        num_params;     /* number of parameters */
-   char       *stmt_with_params;       /* statement after parameter
-                                        * substitution */
-   int         stmt_size_limit;
-   int         exec_start_row;
-   int         exec_end_row;
-   int         exec_current_row;
+   char        multi_statement; /* -1:unknown 0:single 1:multi */
+   char        rbonerr;     /* rollback on error */
+   char        discard_output_params;   /* discard output parameters on parse stage */
+   char        cancel_info;     /* cancel information */
+   pgNAME      cursor_name;
+   char        *plan_name;
+   Int2        num_params;
+
+   char        *stmt_with_params;  /* statement after parameter
+                            * substitution */
+   int     stmt_size_limit;
+   int     exec_start_row;
+   int     exec_end_row;
+   int     exec_current_row;
 
    char        pre_executing;  /* This statement is prematurely executing */
-   char        inaccurate_result;      /* Current status is PREMATURE but
-                                        * result is inaccurate */
+   char        inaccurate_result;  /* Current status is PREMATURE but
+                        * result is inaccurate */
    char        miscinfo;
    char        updatable;
-   SWORD       errorpos;
-   SWORD       error_recsize;
-   Int4        diag_row_count;
+   SQLLEN      diag_row_count;
    char        *load_statement; /* to (re)load updatable individual rows */
    char        *execute_statement; /* to execute the prepared plans */
    Int4        from_pos;   
    Int4        where_pos;
-   Int4        last_fetch_count_include_ommitted;
+   SQLLEN      last_fetch_count_include_ommitted;
    time_t      stmt_time;
    /* SQL_NEED_DATA Callback list */
    StatementClass  *execute_delegate;
+   StatementClass  *execute_parent;
    UInt2       allocated_callbacks;
    UInt2       num_callbacks;
    NeedDataCallback    *callbacks;
@@ -232,7 +269,16 @@ struct StatementClass_
 };
 
 #define SC_get_conn(a)   (a->hdbc)
-#define SC_set_Result(a, b)  (a->result = a->curres = b)
+#define SC_init_Result(a)  (a->result = a->curres = NULL, mylog("SC_init_Result(%x)", a))
+#define SC_set_Result(a, b) \
+do { \
+   if (b != a->result) \
+   { \
+       mylog("SC_set_Result(%x, %x)", a, b); \
+       QR_Destructor(a->result); \
+       a->result = a->curres = b; \
+   } \
+} while (0)
 #define SC_get_Result(a)  (a->result)
 #define SC_set_Curres(a, b)  (a->curres = b)
 #define SC_get_Curres(a)  (a->curres)
@@ -254,108 +300,187 @@ struct StatementClass_
 #define    SC_get_errornumber(a) (a->__error_number)
 #define    SC_set_errornumber(a, n) (a->__error_number = n)
 #define    SC_get_errormsg(a) (a->__error_message)
-#define    SC_is_lower_case(a, b) (a->options.metadata_id || b->connInfo.lower_case_identifier)
+#define    SC_get_errormsg(a) (a->__error_message)
+#define    SC_get_prepare_method(a) (a->prepare & (~PREPARE_STATEMENT))
+
+#define    SC_parsed_status(a) (a->parse_status & STMT_PARSE_MASK)
+#define    SC_set_parse_status(a, s) (a->parse_status |= s)
+#define    SC_update_not_ready(a)  (SC_parsed_status(a) == STMT_PARSE_NONE || 0 == (a->parse_status & STMT_PARSED_OIDS))
+#define    SC_update_ready(a)  (SC_parsed_status(a) == STMT_PARSE_COMPLETE && 0 != (a->parse_status & STMT_FOUND_KEY) && a->updatable)
+#define    SC_set_checked_hasoids(a, b)    (a->parse_status |= (STMT_PARSED_OIDS | (b ? STMT_FOUND_KEY : 0)))
+#define    SC_checked_hasoids(a)   (0 != (a->parse_status & STMT_PARSED_OIDS))
+#define    SC_set_delegate(p, c) (p->execute_delegate = c, c->execute_parent = p)
+
+#define    SC_cursor_is_valid(s)   (NAME_IS_VALID(s->cursor_name))
+#define    SC_cursor_name(s)   (SAFE_NAME(s->cursor_name))
+
+void   SC_reset_delegate(RETCODE, StatementClass *);
+StatementClass *SC_get_ancestor(StatementClass *);
+
+#if (ODBCVER >= 0x0300)
+#define    SC_is_lower_case(a, b) (a->options.metadata_id, b->connInfo.lower_case_identifier)
+#else
+#define    SC_is_lower_case(a, b) (b->connInfo.lower_case_identifier)
+#endif /* ODBCVER */
 
 #define    SC_MALLOC_return_with_error(t, tp, s, a, m, r) \
+do { \
+   if (t = (tp *) malloc(s), NULL == t) \
    { \
-       if (t = (tp *) malloc(s), NULL == t) \
-       { \
-           SC_set_error(a, STMT_NO_MEMORY_ERROR, m); \
-           return r; \
-       } \
-   }
+       SC_set_error(a, STMT_NO_MEMORY_ERROR, m, "SC_MALLOC"); \
+       return r; \
+   } \
+} while (0)
 #define    SC_REALLOC_return_with_error(t, tp, s, a, m, r) \
+do { \
+   if (t = (tp *) realloc(t, s), NULL == t) \
    { \
-       if (t = (tp *) realloc(t, s), NULL == t) \
-       { \
-           SC_set_error(a, STMT_NO_MEMORY_ERROR, m); \
-           return r; \
-       } \
-   }
+       SC_set_error(a, STMT_NO_MEMORY_ERROR, m, "SC_REALLOC"); \
+       return r; \
+   } \
+} while (0)
 
 /* options for SC_free_params() */
 #define STMT_FREE_PARAMS_ALL               0
 #define STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY 1
 
+/* prepare state */
+enum {
+     NON_PREPARE_STATEMENT = 0
+   , PREPARE_STATEMENT = 1
+   , PREPARE_BY_THE_DRIVER = (1L << 1)
+   , USING_PREPARE_COMMAND = (2L << 1)
+   , USING_PARSE_REQUEST = (3L << 1)
+   , USING_UNNAMED_PARSE_REQUEST = (4L << 1)
+};
+
+/* prepared state */
+enum
+{
+   NOT_YET_PREPARED = 0
+   ,PREPARED_PERMANENTLY = 1
+   ,PREPARED_TEMPORARILY = 2
+};
+
 /* misc info */
 #define SC_set_pre_executable(a) (a->miscinfo |= 1L)
 #define SC_no_pre_executable(a) (a->miscinfo &= ~1L)
 #define SC_is_pre_executable(a) ((a->miscinfo & 1L) != 0)
-#define SC_set_fetchcursor(a)  (a->miscinfo |= 2L)
-#define SC_no_fetchcursor(a)   (a->miscinfo &= ~2L)
-#define SC_is_fetchcursor(a)   ((a->miscinfo & 2L) != 0)
-#define SC_set_prepare_before_exec(a)  (a->miscinfo |= 4L)
-#define SC_no_prepare_before_exec(a)   (a->miscinfo &= ~4L)
-#define SC_is_prepare_before_exec(a)   ((a->miscinfo & 4L) != 0)
+#define SC_set_fetchcursor(a)  (a->miscinfo |= (1L << 1))
+#define SC_no_fetchcursor(a)   (a->miscinfo &= ~(1L << 1))
+#define SC_is_fetchcursor(a)   ((a->miscinfo & (1L << 1)) != 0)
+#define SC_set_concat_prepare_exec(a)  (a->miscinfo |= (1L << 2))
+#define SC_no_concat_prepare_exec(a)   (a->miscinfo &= ~(1L << 2))
+#define SC_is_concat_prepare_exec(a)   ((a->miscinfo & (1L << 2)) != 0)
+#define SC_set_with_hold(a)    (a->miscinfo |= (1L << 3))
+#define SC_set_without_hold(a) (a->miscinfo &= ~(1L << 3))
+#define SC_is_with_hold(a) ((a->miscinfo & (1L << 3)) != 0)
+#define SC_miscinfo_clear(a)   (a->miscinfo &= (1L << 3))
+
+#define SC_start_stmt(a)   (a->rbonerr = 0)
+#define SC_start_tc_stmt(a)    (a->rbonerr = (1L << 1))
+#define SC_is_tc_stmt(a)   ((a->rbonerr & (1L << 1)) != 0)
+#define SC_start_rb_stmt(a)    (a->rbonerr = (1L << 2))
+#define SC_is_rb_stmt(a)   ((a->rbonerr & (1L << 2)) != 0)
+#define SC_set_accessed_db(a)  (a->rbonerr |= (1L << 3))
+#define SC_accessed_db(a)  ((a->rbonerr & (1L << 3)) != 0)
+#define SC_start_rbpoint(a)    (a->rbonerr |= (1L << 4))
+#define SC_started_rbpoint(a)  ((a->rbonerr & (1L << 4)) != 0)
+
 
 /* For Multi-thread */
 #if defined(WIN_MULTITHREAD_SUPPORT)
 #define INIT_STMT_CS(x)        InitializeCriticalSection(&((x)->cs))
 #define ENTER_STMT_CS(x)   EnterCriticalSection(&((x)->cs))
+#define TRY_ENTER_STMT_CS(x)   TryEnterCriticalSection(&((x)->cs))
 #define LEAVE_STMT_CS(x)   LeaveCriticalSection(&((x)->cs))
 #define DELETE_STMT_CS(x)  DeleteCriticalSection(&((x)->cs))
 #elif defined(POSIX_THREADMUTEX_SUPPORT)
 #define INIT_STMT_CS(x)        pthread_mutex_init(&((x)->cs),0)
 #define ENTER_STMT_CS(x)   pthread_mutex_lock(&((x)->cs))
+#define TRY_ENTER_STMT_CS(x)   (0 == pthread_mutex_trylock(&((x)->cs)))
 #define LEAVE_STMT_CS(x)   pthread_mutex_unlock(&((x)->cs))
 #define DELETE_STMT_CS(x)  pthread_mutex_destroy(&((x)->cs))
 #else
 #define INIT_STMT_CS(x)
-#define ENTER_STMT_CS(x)   ((void)(0))
-#define LEAVE_STMT_CS(x)   ((void)(0))
+#define ENTER_STMT_CS(x)
+#define TRY_ENTER_STMT_CS(x)   (1)
+#define LEAVE_STMT_CS(x)
 #define DELETE_STMT_CS(x)
 #endif /* WIN_MULTITHREAD_SUPPORT */
 /* Statement prototypes */
-StatementClass *SC_Constructor(void);
-void       SC_set_handle(StatementClass *self,QResultClass *res);
+StatementClass *SC_Constructor(ConnectionClass *);
 void       InitializeStatementOptions(StatementOptions *opt);
 char       SC_Destructor(StatementClass *self);
 BOOL       SC_opencheck(StatementClass *self, const char *func);
 RETCODE        SC_initialize_and_recycle(StatementClass *self);
 int        statement_type(const char *statement);
-char       parse_statement(StatementClass *stmt);
-void       SC_pre_execute(StatementClass *self);
+char       parse_statement(StatementClass *stmt, BOOL);
+Int4       SC_pre_execute(StatementClass *self);
 char       SC_unbind_cols(StatementClass *self);
 char       SC_recycle_statement(StatementClass *self);
 
 void       SC_clear_error(StatementClass *self);
-void       SC_set_error(StatementClass *self, int errnum, const char *msg);
+void       SC_set_error(StatementClass *self, int errnum, const char *msg, const char *func);
 void       SC_set_errormsg(StatementClass *self, const char *msg);
-void       SC_error_copy(StatementClass *self, const StatementClass *from);
-void       SC_full_error_copy(StatementClass *self, const StatementClass *from);
-char       SC_get_error(StatementClass *self, int *number, char **message);
-char       *SC_create_errormsg(const StatementClass *self);
-void       SC_set_sqlstate(StatementClass *self, const char *sqlstate);
-char       *SC_get_sqlstate(StatementClass *self);
+void       SC_error_copy(StatementClass *self, const StatementClass *from, BOOL);
+void       SC_full_error_copy(StatementClass *self, const StatementClass *from, BOOL);
+void       SC_replace_error_with_res(StatementClass *self, int errnum, const char *msg, const QResultClass*, BOOL);
 void       SC_set_prepared(StatementClass *self, BOOL);
+void       SC_set_planname(StatementClass *self, const char *plan_name);
+void       SC_set_rowset_start(StatementClass *self, SQLLEN, BOOL);
+void       SC_inc_rowset_start(StatementClass *self, SQLLEN);
 RETCODE        SC_initialize_stmts(StatementClass *self, BOOL);
 RETCODE        SC_execute(StatementClass *self);
 RETCODE        SC_fetch(StatementClass *self);
 void       SC_free_params(StatementClass *self, char option);
 void       SC_log_error(const char *func, const char *desc, const StatementClass *self);
 time_t     SC_get_time(StatementClass *self);
-UInt4      SC_get_bookmark(StatementClass *self);
-RETCODE        SC_pos_update(StatementClass *self, UWORD irow, UDWORD index);
-RETCODE        SC_pos_delete(StatementClass *self, UWORD irow, UDWORD index);
-RETCODE        SC_pos_refresh(StatementClass *self, UWORD irow, UDWORD index);
+SQLULEN        SC_get_bookmark(StatementClass *self);
+RETCODE        SC_pos_reload(StatementClass *self, SQLULEN index, UWORD *, Int4);
+RETCODE        SC_pos_update(StatementClass *self, UWORD irow, SQLULEN index);
+RETCODE        SC_pos_delete(StatementClass *self, UWORD irow, SQLULEN index);
+RETCODE        SC_pos_refresh(StatementClass *self, UWORD irow, SQLULEN index);
 RETCODE        SC_pos_add(StatementClass *self, UWORD irow);
 int        SC_set_current_col(StatementClass *self, int col);
 
+BOOL   SC_IsExecuting(const StatementClass *self);
+BOOL   SC_SetExecuting(StatementClass *self, BOOL on);
+BOOL   SC_SetCancelRequest(StatementClass *self);
+BOOL   SC_AcceptedCancelRequest(const StatementClass *self);
+
 DescriptorClass    *SC_set_ARD(StatementClass *stmt, DescriptorClass *desc);
 DescriptorClass    *SC_set_APD(StatementClass *stmt, DescriptorClass *desc);
 int        enqueueNeedDataCallback(StatementClass *self, NeedDataCallfunc, void *);
 RETCODE        dequeueNeedDataCallback(RETCODE, StatementClass *self);
 void       cancelNeedDataState(StatementClass *self);
-
+int        StartRollbackState(StatementClass *self);
+RETCODE        SetStatementSvp(StatementClass *self);
+RETCODE        DiscardStatementSvp(StatementClass *self, RETCODE, BOOL errorOnly);
+
+BOOL       SendParseRequest(StatementClass *self, const char *name,
+               const char *query);
+BOOL       SendDescribeRequest(StatementClass *self, const char *name);
+BOOL       SendBindRequest(StatementClass *self, const char *name);
+BOOL       BuildBindRequest(StatementClass *stmt, const char *name);
+BOOL       SendExecuteRequest(StatementClass *stmt, const char *portal, UInt4 count);
+QResultClass   *SendSyncAndReceive(StatementClass *stmt, QResultClass *res, const char *comment);
 /*
  * Macros to convert global index <-> relative index in resultset/rowset
  */
 /* a global index to the relative index in a rowset */
+#define    SC_get_rowset_start(stmt) (stmt->rowset_start)
 #define    GIdx2RowIdx(gidx, stmt) (gidx - stmt->rowset_start)
 /* a global index to the relative index in a resultset(not a rowset) */
-#define    GIdx2ResultIdx(gidx, stmt, res) ((stmt->rowset_start < 0) ? res->base : gidx - stmt->rowset_start + res->base)
+#define    GIdx2CacheIdx(gidx, s, r)   (gidx - (QR_has_valid_base(r) ? (s->rowset_start - r->base) : 0))
+#define    GIdx2KResIdx(gidx, s, r)    (gidx - (QR_has_valid_base(r) ? (s->rowset_start - r->key_base) : 0))
 /* a relative index in a rowset to the global index */
 #define    RowIdx2GIdx(ridx, stmt) (ridx + stmt->rowset_start)
 /* a relative index in a resultset to the global index */
-#define    ResultIdx2GIdx(ridx, stmt, res) (ridx - res->base + stmt->rowset_start)
-#endif
+#define    CacheIdx2GIdx(ridx, stmt, res)  (ridx - res->base + stmt->rowset_start)
+#define    KResIdx2GIdx(ridx, stmt, res)   (ridx - res->key_base + stmt->rowset_start)
+
+#define    BOOKMARK_SHIFT  1
+#define    SC_make_bookmark(b) ((b < 0) ? (b) : (b + BOOKMARK_SHIFT))
+#define    SC_resolve_bookmark(b)  ((b < 0) ? (b) : (b - BOOKMARK_SHIFT))
+#endif /* __STATEMENT_H__ */
diff --git a/tuple.c b/tuple.c
index 839b8d773c3a7b0a02c5b99940f09496db6ce04f..deb471656db0a04c85156889efcac67ef06110a3 100644 (file)
--- a/tuple.c
+++ b/tuple.c
@@ -34,9 +34,14 @@ set_tuplefield_null(TupleField *tuple_field)
 void
 set_tuplefield_string(TupleField *tuple_field, const char *string)
 {
-   tuple_field->len = strlen(string);
-   tuple_field->value = malloc(strlen(string) + 1);
-   strcpy(tuple_field->value, string);
+   if (string)
+   {
+       tuple_field->len = strlen(string);
+       tuple_field->value = malloc(strlen(string) + 1);
+       strcpy(tuple_field->value, string);
+   }
+   else
+       set_tuplefield_null(tuple_field);
 }
 
 
@@ -58,7 +63,7 @@ set_tuplefield_int4(TupleField *tuple_field, Int4 value)
 {
    char        buffer[15];
 
-   sprintf(buffer, "%ld", (long int) value);
+   sprintf(buffer, "%ld", value);
 
    tuple_field->len = strlen(buffer) + 1;
    /* +1 ... is this correct (better be on the save side-...) */
diff --git a/tuple.h b/tuple.h
index d4f4f9800f568bbc851f467e6933d12863c1d918..cb3c61a5895dada20266f90495cce0321f8bd15b 100644 (file)
--- a/tuple.h
+++ b/tuple.h
@@ -2,9 +2,9 @@
  *
  * Description:        See "tuple.c"
  *
- * Important NOTE: The TupleField structure is used both to hold backend data and
- *                 manual result set data.  The "set_" functions and the TupleNode
*                 structure are only used for manual result sets by info routines.
+ * Important NOTE: The TupleField structure is used both to hold backend
+           data and manual result set data. The "set_" functions
          are only used for manual result sets by info routines.
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
@@ -22,14 +22,6 @@ struct TupleField_
    void       *value;          /* an array representing the value */
 };
 
-/* Used ONLY for manual result sets */
-struct TupleNode_
-{
-   struct TupleNode_ *prev,
-              *next;
-   TupleField  tuple[1];
-};
-
 /* keyset(TID + OID) info */
 struct KeySet_
 {
@@ -41,9 +33,10 @@ struct KeySet_
 /* Rollback(index + original TID) info */
 struct Rollback_
 {
-   UDWORD  index;
+   DWORD   index;
    UDWORD  blocknum;
    UWORD   offset;
+   UWORD   option;
 };
 #define    KEYSET_INFO_PUBLIC  0x07
 #define    CURS_SELF_ADDING    (1L << 3)
@@ -68,5 +61,7 @@ void      set_tuplefield_null(TupleField *tuple_field);
 void       set_tuplefield_string(TupleField *tuple_field, const char *string);
 void       set_tuplefield_int2(TupleField *tuple_field, Int2 value);
 void       set_tuplefield_int4(TupleField *tuple_field, Int4 value);
+int    ClearCachedRows(TupleField *tuple, int num_fields, int num_rows);
+int    ReplaceCachedRows(TupleField *otuple, const TupleField *ituple, int num_fields, int num_rows);
 
 #endif
index 40cb78e4bba7ea98158e5263d902839271204d08..47fdc886d7ae1f93da45a699b1c0a7e4afbca48d 100644 (file)
--- a/version.h
+++ b/version.h
@@ -4,15 +4,13 @@
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * Note:            The version number should also be updated in :
- *                  psqlodbc.rc, configure.ac and installer/make.bat
  */
 
 #ifndef __VERSION_H__
 #define __VERSION_H__
 
-#define POSTGRESDRIVERVERSION      "08.01.0200"
-#define POSTGRES_RESOURCE_VERSION  "08.01.0200\0"
-#define PG_DRVFILE_VERSION     8,1,2,0
+#define POSTGRESDRIVERVERSION      "07.03.0262"
+#define POSTGRES_RESOURCE_VERSION  "07.03.0262\0"
+#define PG_DRVFILE_VERSION     7,3,2,62 
 
 #endif
diff --git a/win32_30w.mak b/win32_30w.mak
new file mode 100644 (file)
index 0000000..c402dbd
--- /dev/null
@@ -0,0 +1,598 @@
+#
+# File:            win32_30w.mak
+#
+# Description:     psqlodbc35w Unicode version Makefile for Win32.
+#
+# Configurations:  Unicode30Debug, Unicode30
+# Build Types:     ALL, CLEAN
+# Usage:       NMAKE /f win32_30.mak CFG=[Unicode30 | Unicode30Debug] [ALL | CLEAN]
+#
+# Comments:        Created by Dave Page, 2001-02-12
+#
+
+!MESSAGE Building the PostgreSQL Unicode 3.0 Driver for Win32...
+!MESSAGE
+!IF "$(CFG)" == ""
+CFG=Unicode30
+!MESSAGE No configuration specified. Defaulting to Unicode30.
+!MESSAGE
+!ENDIF 
+
+!IF "$(CFG)" != "Unicode30" && "$(CFG)" != "Unicode30Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f win32_30.mak CFG=[Unicode30 | Unicode30Debug] [ALL | CLEAN]
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "Unicode30" (Win32 Release DLL)
+!MESSAGE "Unicode30Debug" (Win32 Debug DLL)
+!MESSAGE 
+!ERROR An invalid configuration was specified.
+!ENDIF 
+
+#
+#
+!IF "$(PG_INC)" == ""
+PG_INC=$(PROGRAMFILES)\PostgreSQL\8.1\include
+!MESSAGE Using default PostgreSQL Include directory: $(PG_INC)
+!ENDIF
+
+!IF "$(PG_LIB)" == ""
+PG_LIB=$(PROGRAMFILES)\PostgreSQL\8.1\lib\ms
+!MESSAGE Using default PostgreSQL Library directory: $(PG_LIB)
+!ENDIF
+
+!IF "$(SSL_INC)" == ""
+SSL_INC=C:\OpenSSL\include
+!MESSAGE Using default OpenSSL Include directory: $(SSL_INC)
+!ENDIF
+
+!IF "$(SSL_LIB)" == ""
+SSL_LIB=C:\OpenSSL\lib\VC
+!MESSAGE Using default OpenSSL Library directory: $(SSL_LIB)
+!ENDIF
+
+SSL_DLL = "SSLEAY32.dll"
+ADD_DEFINES = $(ADD_DEFINES) /D "SSL_DLL=\"$(SSL_DLL)\""
+
+!IF "$(_NMAKE_VER)" == "6.00.9782.0"
+MSVC_VERSION=vc60
+VC07_DELAY_LOAD=
+ADD_DEFINES = $(ADD_DEFINES) /D "DYNAMIC_LOAD"
+!ELSE
+MSVC_VERSION=vc70
+VC07_DELAY_LOAD="/DelayLoad:libpq.dll /DelayLoad:$(SSL_DLL) /DELAY:UNLOAD"
+ADD_DEFINES = $(ADD_DEFINES) /D "DYNAMIC_LOAD"
+!ENDIF
+
+!IF "$(MEMORY_DEBUG)" == "yes"
+ADD_DEFINES = $(ADD_DEFINES) /D "_MEMORY_DEBUG_"
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+!IF  "$(CFG)" == "Unicode30"
+
+OUTDIR=.\Unicode30
+OUTDIRBIN=.\Unicode30
+INTDIR=.\Unicode30
+
+ALL : "$(OUTDIRBIN)\psqlodbc35w.dll"
+
+
+CLEAN :
+   -@erase "$(INTDIR)\bind.obj"
+   -@erase "$(INTDIR)\columninfo.obj"
+   -@erase "$(INTDIR)\connection.obj"
+   -@erase "$(INTDIR)\convert.obj"
+   -@erase "$(INTDIR)\dlg_specific.obj"
+   -@erase "$(INTDIR)\dlg_wingui.obj"
+   -@erase "$(INTDIR)\drvconn.obj"
+   -@erase "$(INTDIR)\environ.obj"
+   -@erase "$(INTDIR)\execute.obj"
+   -@erase "$(INTDIR)\info.obj"
+   -@erase "$(INTDIR)\info30.obj"
+   -@erase "$(INTDIR)\lobj.obj"
+   -@erase "$(INTDIR)\win_md5.obj"
+   -@erase "$(INTDIR)\misc.obj"
+   -@erase "$(INTDIR)\mylog.obj"
+   -@erase "$(INTDIR)\pgapi30.obj"
+   -@erase "$(INTDIR)\multibyte.obj"
+   -@erase "$(INTDIR)\odbcapiw.obj"
+   -@erase "$(INTDIR)\odbcapi30w.obj"
+   -@erase "$(INTDIR)\win_unicode.obj"
+   -@erase "$(INTDIR)\options.obj"
+   -@erase "$(INTDIR)\parse.obj"
+   -@erase "$(INTDIR)\pgtypes.obj"
+   -@erase "$(INTDIR)\psqlodbc.obj"
+   -@erase "$(INTDIR)\psqlodbc.res"
+   -@erase "$(INTDIR)\qresult.obj"
+   -@erase "$(INTDIR)\results.obj"
+   -@erase "$(INTDIR)\setup.obj"
+   -@erase "$(INTDIR)\socket.obj"
+   -@erase "$(INTDIR)\statement.obj"
+   -@erase "$(INTDIR)\tuple.obj"
+   -@erase "$(INTDIR)\odbcapi.obj"
+   -@erase "$(INTDIR)\odbcapi30.obj"
+   -@erase "$(INTDIR)\descriptor.obj"
+   -@erase "$(INTDIR)\loadlib.obj"
+   -@erase "$(INTDIR)\$(MSVC_VERSION).idb"
+   -@erase "$(OUTDIR)\psqlodbc35w.dll"
+   -@erase "$(OUTDIR)\psqlodbc.exp"
+   -@erase "$(OUTDIR)\psqlodbc.lib"
+   -@erase "$(OUTDIR)\psqlodbc.pch"
+!IF "$(MEMORY_DEBUG)" == "yes"
+   -@erase "$(OUTDIR)\inouealc.obj"
+!ENDIF
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /I "$(PG_INC)" /I "$(SSL_INC)" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "ODBCVER=0x0351" /D "UNICODE_SUPPORT" /D "WIN_MULTITHREAD_SUPPORT" $(ADD_DEFINES) /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 
+RSC=rc.exe
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "NDEBUG" 
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc" 
+BSC32_SBRS= \
+   
+LINK32=link.exe
+DEF_FILE= "psqlodbc_api30w.def"
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\psqlodbc.pdb" /machine:I386 /def:"$(DEF_FILE)" /out:"$(OUTDIRBIN)\psqlodbc35w.dll" /implib:"$(OUTDIR)\psqlodbc.lib" "$(VC07_DELAY_LOAD)" /libpath:"$(PG_LIB)" /libpath:"$(SSL_LIB)"
+LINK32_OBJS= \
+   "$(INTDIR)\bind.obj" \
+   "$(INTDIR)\columninfo.obj" \
+   "$(INTDIR)\connection.obj" \
+   "$(INTDIR)\convert.obj" \
+   "$(INTDIR)\dlg_specific.obj" \
+   "$(INTDIR)\dlg_wingui.obj" \
+   "$(INTDIR)\drvconn.obj" \
+   "$(INTDIR)\environ.obj" \
+   "$(INTDIR)\execute.obj" \
+   "$(INTDIR)\info.obj" \
+   "$(INTDIR)\info30.obj" \
+   "$(INTDIR)\lobj.obj" \
+   "$(INTDIR)\win_md5.obj" \
+   "$(INTDIR)\misc.obj" \
+   "$(INTDIR)\mylog.obj" \
+   "$(INTDIR)\pgapi30.obj" \
+   "$(INTDIR)\multibyte.obj" \
+   "$(INTDIR)\odbcapiw.obj" \
+   "$(INTDIR)\odbcapi30w.obj" \
+   "$(INTDIR)\win_unicode.obj" \
+   "$(INTDIR)\options.obj" \
+   "$(INTDIR)\parse.obj" \
+   "$(INTDIR)\pgtypes.obj" \
+   "$(INTDIR)\psqlodbc.obj" \
+   "$(INTDIR)\qresult.obj" \
+   "$(INTDIR)\results.obj" \
+   "$(INTDIR)\setup.obj" \
+   "$(INTDIR)\socket.obj" \
+   "$(INTDIR)\statement.obj" \
+   "$(INTDIR)\tuple.obj" \
+   "$(INTDIR)\odbcapi.obj" \
+   "$(INTDIR)\odbcapi30.obj" \
+   "$(INTDIR)\descriptor.obj" \
+   "$(INTDIR)\loadlib.obj" \
+!IF "$(MEMORY_DEBUG)" == "yes"
+   "$(INTDIR)\inouealc.obj" \
+!ENDIF
+   "$(INTDIR)\psqlodbc.res"
+
+"$(OUTDIRBIN)\psqlodbc35w.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF  "$(CFG)" == "Unicode30Debug"
+
+OUTDIR=.\Unicode30Debug
+OUTDIRBIN=.\Unicode30Debug
+INTDIR=.\Unicode30Debug
+
+ALL : "$(OUTDIR)\psqlodbc35w.dll"
+
+
+CLEAN :
+   -@erase "$(INTDIR)\bind.obj"
+   -@erase "$(INTDIR)\columninfo.obj"
+   -@erase "$(INTDIR)\connection.obj"
+   -@erase "$(INTDIR)\convert.obj"
+   -@erase "$(INTDIR)\dlg_specific.obj"
+   -@erase "$(INTDIR)\dlg_wingui.obj"
+   -@erase "$(INTDIR)\drvconn.obj"
+   -@erase "$(INTDIR)\environ.obj"
+   -@erase "$(INTDIR)\execute.obj"
+   -@erase "$(INTDIR)\info.obj"
+   -@erase "$(INTDIR)\info30.obj"
+   -@erase "$(INTDIR)\lobj.obj"
+   -@erase "$(INTDIR)\win_md5.obj"
+   -@erase "$(INTDIR)\misc.obj"
+   -@erase "$(INTDIR)\mylog.obj"
+   -@erase "$(INTDIR)\pgapi30.obj"
+   -@erase "$(INTDIR)\multibyte.obj"
+   -@erase "$(INTDIR)\odbcapiw.obj"
+   -@erase "$(INTDIR)\odbcapi30w.obj"
+   -@erase "$(INTDIR)\win_unicode.obj"
+   -@erase "$(INTDIR)\options.obj"
+   -@erase "$(INTDIR)\parse.obj"
+   -@erase "$(INTDIR)\pgtypes.obj"
+   -@erase "$(INTDIR)\psqlodbc.obj"
+   -@erase "$(INTDIR)\psqlodbc.res"
+   -@erase "$(INTDIR)\qresult.obj"
+   -@erase "$(INTDIR)\results.obj"
+   -@erase "$(INTDIR)\setup.obj"
+   -@erase "$(INTDIR)\socket.obj"
+   -@erase "$(INTDIR)\statement.obj"
+   -@erase "$(INTDIR)\tuple.obj"
+   -@erase "$(INTDIR)\odbcapi.obj"
+   -@erase "$(INTDIR)\odbcapi30.obj"
+   -@erase "$(INTDIR)\descriptor.obj"
+   -@erase "$(INTDIR)\loadlib.obj"
+   -@erase "$(INTDIR)\$(MSVC_VERSION).idb"
+   -@erase "$(INTDIR)\$(MSVC_VERSION).pdb"
+   -@erase "$(OUTDIR)\psqlodbc35w.dll"
+   -@erase "$(OUTDIR)\psqlodbc35w.ilk"
+   -@erase "$(OUTDIR)\psqlodbc.exp"
+   -@erase "$(OUTDIR)\psqlodbc.lib"
+   -@erase "$(OUTDIR)\psqlodbc.pdb"
+   -@erase "$(OUTDIR)\psqlodbc.pch"
+!IF "$(MEMORY_DEBUG)" == "yes"
+   -@erase "$(OUTDIR)\inouealc.obj"
+!ENDIF
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /I "$(PG_INC)" /I "$(SSL_INC)" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "ODBCVER=0x0351" /D "UNICODE_SUPPORT" /D "WIN_MULTITHREAD_SUPPORT" $(ADD_DEFINES) /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 
+RSC=rc.exe
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "_DEBUG" 
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc" 
+BSC32_SBRS= \
+   
+LINK32=link.exe
+DEF_FILE= "psqlodbc_api30w.def"
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\psqlodbc.pdb" /debug /machine:I386 /def:"$(DEF_FILE)" /out:"$(OUTDIR)\psqlodbc35w.dll" /implib:"$(OUTDIR)\psqlodbc.lib" /pdbtype:sept "$(VC07_DELAY_LOAD)" /libpath:"$(PG_LIB)" /libpath:"$(SSL_LIB)"
+LINK32_OBJS= \
+   "$(INTDIR)\bind.obj" \
+   "$(INTDIR)\columninfo.obj" \
+   "$(INTDIR)\connection.obj" \
+   "$(INTDIR)\convert.obj" \
+   "$(INTDIR)\dlg_specific.obj" \
+   "$(INTDIR)\dlg_wingui.obj" \
+   "$(INTDIR)\drvconn.obj" \
+   "$(INTDIR)\environ.obj" \
+   "$(INTDIR)\execute.obj" \
+   "$(INTDIR)\info.obj" \
+   "$(INTDIR)\info30.obj" \
+   "$(INTDIR)\lobj.obj" \
+   "$(INTDIR)\win_md5.obj" \
+   "$(INTDIR)\misc.obj" \
+   "$(INTDIR)\mylog.obj" \
+   "$(INTDIR)\pgapi30.obj" \
+   "$(INTDIR)\multibyte.obj" \
+   "$(INTDIR)\odbcapiw.obj" \
+   "$(INTDIR)\odbcapi30w.obj" \
+   "$(INTDIR)\win_unicode.obj" \
+   "$(INTDIR)\options.obj" \
+   "$(INTDIR)\parse.obj" \
+   "$(INTDIR)\pgtypes.obj" \
+   "$(INTDIR)\psqlodbc.obj" \
+   "$(INTDIR)\qresult.obj" \
+   "$(INTDIR)\results.obj" \
+   "$(INTDIR)\setup.obj" \
+   "$(INTDIR)\socket.obj" \
+   "$(INTDIR)\statement.obj" \
+   "$(INTDIR)\tuple.obj" \
+   "$(INTDIR)\odbcapi.obj" \
+   "$(INTDIR)\odbcapi30.obj" \
+   "$(INTDIR)\descriptor.obj" \
+   "$(INTDIR)\loadlib.obj" \
+!IF "$(MEMORY_DEBUG)" == "yes"
+   "$(INTDIR)\inouealc.obj" \
+!ENDIF
+   "$(INTDIR)\psqlodbc.res"
+
+"$(OUTDIR)\psqlodbc35w.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF 
+
+!IF "$(CFG)" == "Unicode30" || "$(CFG)" == "Unicode30Debug"
+
+SOURCE=bind.c
+
+"$(INTDIR)\bind.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=columninfo.c
+
+"$(INTDIR)\columninfo.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=connection.c
+
+"$(INTDIR)\connection.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=convert.c
+
+"$(INTDIR)\convert.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=dlg_specific.c
+
+"$(INTDIR)\dlg_specific.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=dlg_wingui.c
+
+"$(INTDIR)\dlg_wingui.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=drvconn.c
+
+"$(INTDIR)\drvconn.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=environ.c
+
+"$(INTDIR)\environ.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=execute.c
+
+"$(INTDIR)\execute.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=info.c
+
+"$(INTDIR)\info.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=info30.c
+
+"$(INTDIR)\info30.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=lobj.c
+
+"$(INTDIR)\lobj.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=misc.c
+
+"$(INTDIR)\misc.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=mylog.c
+
+"$(INTDIR)\mylog.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=multibyte.c
+
+"$(INTDIR)\multibyte.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=odbcapiw.c
+
+"$(INTDIR)\odbcapiw.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=pgapi30.c
+
+"$(INTDIR)\pgapi30.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=odbcapi30w.c
+
+"$(INTDIR)\odbcapi30w.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=win_unicode.c
+
+"$(INTDIR)\win_unicode.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=options.c
+
+"$(INTDIR)\options.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=parse.c
+
+"$(INTDIR)\parse.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=pgtypes.c
+
+"$(INTDIR)\pgtypes.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=psqlodbc.c
+
+"$(INTDIR)\psqlodbc.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=psqlodbc.rc
+
+!IF "$(CFG)" == "Unicode30"
+"$(INTDIR)\psqlodbc.res" : $(SOURCE) "$(INTDIR)"
+   $(RSC) /l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "NDEBUG" /d "MULTIBYTE" $(SOURCE)
+!ENDIF
+
+!IF "$(CFG)" == "Unicode30Debug"
+"$(INTDIR)\psqlodbc.res" : $(SOURCE) "$(INTDIR)"
+   $(RSC) /l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "_DEBUG" $(SOURCE)
+!ENDIF
+
+
+SOURCE=qresult.c
+
+"$(INTDIR)\qresult.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=results.c
+
+"$(INTDIR)\results.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=setup.c
+
+"$(INTDIR)\setup.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=socket.c
+
+"$(INTDIR)\socket.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=statement.c
+
+"$(INTDIR)\statement.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=tuple.c
+
+"$(INTDIR)\tuple.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=win_md5.c
+
+"$(INTDIR)\win_md5.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=odbcapi.c
+
+"$(INTDIR)\odbcapi.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=odbcapi30.c
+
+"$(INTDIR)\odbcapi30.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=descriptor.c
+
+"$(INTDIR)\descriptor.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=loadlib.c
+
+"$(INTDIR)\loadlib.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+!IF "$(MEMORY_DEBUG)" == "yes"
+SOURCE=inouealc.c
+
+"$(INTDIR)\inouealc.obj" : $(SOURCE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+!ENDIF
+
+
+!ENDIF 
index 63f7de5b79a4f082c91b7d40573002abedde38ae..3be80fe36af4d3c8e682f4daa4d7aa07ecbc215d 100644 (file)
@@ -12,7 +12,7 @@ typedef struct tagSETUPDLG
    HWND        hwndParent;     /* Parent window handle */
    LPCSTR      lpszDrvr;       /* Driver description */
    ConnInfo    ci;
-   char        szDSN[MAXDSNAME];   /* Original data source name */
+   char        szDSN[MAXDSNAME];       /* Original data source name */
    BOOL        fNewDSN;        /* New data source flag */
    BOOL        fDefault;       /* Default data source flag */
 
index d9ec33df0a610bb08c5850ca943b3c8a952f6f16..cd510e8fff505ecee8f326ec95fe443160270e9d 100644 (file)
@@ -10,7 +10,6 @@
 #include "psqlodbc.h"
 #include <stdio.h>
 #include <string.h>
-#include <stdlib.h>
 
 #define    byte3check  0xfffff800
 #define    byte2_base  0x80c0
@@ -41,14 +40,17 @@ UInt4   ucs2strlen(const SQLWCHAR *ucs2str)
        ;
    return len;
 }
-char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen, BOOL lower_identifier)
+char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, Int4 *olen, BOOL lower_identifier)
 {
    char *  utf8str;
 /*mylog("ucs2_to_utf8 %x ilen=%d ", ucs2str, ilen);*/
 
    if (!ucs2str)
+   {
+       *olen = SQL_NULL_DATA;
        return NULL;
-   if (ilen < 0)
+   }
+   if (SQL_NTS == ilen)
        ilen = ucs2strlen(ucs2str);
 /*mylog(" newlen=%d", ilen);*/
    utf8str = (char *) malloc(ilen * 3 + 1);
@@ -76,7 +78,7 @@ char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen, BOOL lower_i
                        ((byte2_mask1 & *wstr) >> 6) |
                        ((byte2_mask2 & *wstr) << 8);
                memcpy(utf8str + len, (char *) &byte2code, sizeof(byte2code));
-               len += 2
+               len += sizeof(byte2code)
            }
            else
            {