OSDN Git Service

[2002-03-28]
authorHiroshi Inoue <inoue@tpf.co.jp>
Thu, 28 Mar 2002 08:08:07 +0000 (08:08 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Thu, 28 Mar 2002 08:08:07 +0000 (08:08 +0000)
1) Prepare to separate 4 kinds of Descriptor handles.
2) Detect the transaction status more naturally.
3) Improve Parse Statement functionality for the use
   of updatable cursors.
4) Improve updatable cursors.
5) Implement SQLGetDescField() and improve SQLColAttribute().
6) etc.

40 files changed:
src/interfaces/odbc/bind.c
src/interfaces/odbc/bind.h
src/interfaces/odbc/connection.c
src/interfaces/odbc/connection.h
src/interfaces/odbc/convert.c
src/interfaces/odbc/descriptor.h [new file with mode: 0644]
src/interfaces/odbc/dlg_specific.c
src/interfaces/odbc/dlg_specific.h
src/interfaces/odbc/environ.c
src/interfaces/odbc/execute.c
src/interfaces/odbc/info.c
src/interfaces/odbc/info30.c
src/interfaces/odbc/misc.c
src/interfaces/odbc/misc.h
src/interfaces/odbc/multibyte.c
src/interfaces/odbc/multibyte.h
src/interfaces/odbc/odbcapi.c
src/interfaces/odbc/odbcapi30.c
src/interfaces/odbc/odbcapi30w.c
src/interfaces/odbc/options.c
src/interfaces/odbc/parse.c
src/interfaces/odbc/pgapi30.c
src/interfaces/odbc/pgapifunc.h
src/interfaces/odbc/pgtypes.c
src/interfaces/odbc/pgtypes.h
src/interfaces/odbc/psqlodbc.h
src/interfaces/odbc/psqlodbc.rc
src/interfaces/odbc/psqlodbc30w.reg [new file with mode: 0644]
src/interfaces/odbc/psqlodbc_api30.def
src/interfaces/odbc/psqlodbc_api30w.def
src/interfaces/odbc/qresult.c
src/interfaces/odbc/qresult.h
src/interfaces/odbc/resource.h
src/interfaces/odbc/results.c
src/interfaces/odbc/setup.c
src/interfaces/odbc/statement.c
src/interfaces/odbc/statement.h
src/interfaces/odbc/tuple.h
src/interfaces/odbc/win32.mak
src/interfaces/odbc/win32_30w.mak

index 4635706..397d984 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "environ.h"
 #include "statement.h"
+#include "descriptor.h"
 #include "qresult.h"
 #include "pgtypes.h"
 #include <stdlib.h>
@@ -41,6 +42,7 @@ PGAPI_BindParameter(
 {
        StatementClass *stmt = (StatementClass *) hstmt;
        static char *func = "PGAPI_BindParameter";
+       APDFields       *opts;
 
        mylog("%s: entering...\n", func);
 
@@ -51,103 +53,54 @@ PGAPI_BindParameter(
        }
        SC_clear_error(stmt);
 
-       if (stmt->parameters_allocated < ipar)
-       {
-               ParameterInfoClass *old_parameters;
-               int                     i,
-                                       old_parameters_allocated;
-
-               old_parameters = stmt->parameters;
-               old_parameters_allocated = stmt->parameters_allocated;
-
-               stmt->parameters = (ParameterInfoClass *) malloc(sizeof(ParameterInfoClass) * (ipar));
-               if (!stmt->parameters)
-               {
-                       stmt->errornumber = STMT_NO_MEMORY_ERROR;
-                       stmt->errormsg = "Could not allocate memory for statement parameters";
-                       SC_log_error(func, "", stmt);
-                       return SQL_ERROR;
-               }
-
-               stmt->parameters_allocated = ipar;
-
-               /* copy the old parameters over */
-               for (i = 0; i < old_parameters_allocated; i++)
-               {
-                       /* a structure copy should work */
-                       stmt->parameters[i] = old_parameters[i];
-               }
-
-               /* get rid of the old parameters, if there were any */
-               if (old_parameters)
-                       free(old_parameters);
-
-               /*
-                * zero out the newly allocated parameters (in case they skipped
-                * some,
-                */
-               /* so we don't accidentally try to use them later) */
-               for (; i < stmt->parameters_allocated; i++)
-               {
-                       stmt->parameters[i].buflen = 0;
-                       stmt->parameters[i].buffer = 0;
-                       stmt->parameters[i].used = 0;
-                       stmt->parameters[i].paramType = 0;
-                       stmt->parameters[i].CType = 0;
-                       stmt->parameters[i].SQLType = 0;
-                       stmt->parameters[i].precision = 0;
-                       stmt->parameters[i].scale = 0;
-                       stmt->parameters[i].data_at_exec = FALSE;
-                       stmt->parameters[i].lobj_oid = 0;
-                       stmt->parameters[i].EXEC_used = NULL;
-                       stmt->parameters[i].EXEC_buffer = NULL;
-               }
-       }
+       opts = SC_get_APD(stmt);
+       if (opts->allocated < ipar)
+               extend_parameter_bindings(opts, ipar);
 
        /* use zero based column numbers for the below part */
        ipar--;
 
        /* store the given info */
-       stmt->parameters[ipar].buflen = cbValueMax;
-       stmt->parameters[ipar].buffer = rgbValue;
-       stmt->parameters[ipar].used = pcbValue;
-       stmt->parameters[ipar].paramType = fParamType;
-       stmt->parameters[ipar].CType = fCType;
-       stmt->parameters[ipar].SQLType = fSqlType;
-       stmt->parameters[ipar].precision = cbColDef;
-       stmt->parameters[ipar].scale = ibScale;
+       opts->parameters[ipar].buflen = cbValueMax;
+       opts->parameters[ipar].buffer = rgbValue;
+       opts->parameters[ipar].used = pcbValue;
+       opts->parameters[ipar].paramType = fParamType;
+       opts->parameters[ipar].CType = fCType;
+       opts->parameters[ipar].SQLType = fSqlType;
+       opts->parameters[ipar].precision = cbColDef;
+       opts->parameters[ipar].scale = ibScale;
 
        /*
         * If rebinding a parameter that had data-at-exec stuff in it, then
         * free that stuff
         */
-       if (stmt->parameters[ipar].EXEC_used)
+       if (opts->parameters[ipar].EXEC_used)
        {
-               free(stmt->parameters[ipar].EXEC_used);
-               stmt->parameters[ipar].EXEC_used = NULL;
+               free(opts->parameters[ipar].EXEC_used);
+               opts->parameters[ipar].EXEC_used = NULL;
        }
 
-       if (stmt->parameters[ipar].EXEC_buffer)
+       if (opts->parameters[ipar].EXEC_buffer)
        {
-               if (stmt->parameters[ipar].SQLType != SQL_LONGVARBINARY)
-                       free(stmt->parameters[ipar].EXEC_buffer);
-               stmt->parameters[ipar].EXEC_buffer = NULL;
+               if (opts->parameters[ipar].SQLType != SQL_LONGVARBINARY)
+                       free(opts->parameters[ipar].EXEC_buffer);
+               opts->parameters[ipar].EXEC_buffer = NULL;
        }
 
-       if (pcbValue && stmt->options.param_offset_ptr)
-               pcbValue += (*stmt->options.param_offset_ptr >> 2);
+       if (pcbValue && opts->param_offset_ptr)
+               pcbValue += (*opts->param_offset_ptr >> 2);
        /* 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))
-               stmt->parameters[ipar].data_at_exec = TRUE;
+               opts->parameters[ipar].data_at_exec = TRUE;
        else
-               stmt->parameters[ipar].data_at_exec = FALSE;
+               opts->parameters[ipar].data_at_exec = FALSE;
 
        /* 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, stmt->parameters[ipar].data_at_exec);
+       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, opts->parameters[ipar].data_at_exec);
 
        return SQL_SUCCESS;
 }
@@ -165,6 +118,7 @@ PGAPI_BindCol(
 {
        StatementClass *stmt = (StatementClass *) hstmt;
        static char *func = "PGAPI_BindCol";
+       ARDFields       *opts;
 
        mylog("%s: entering...\n", func);
 
@@ -178,8 +132,8 @@ PGAPI_BindCol(
        }
 
 
-       SC_clear_error(stmt);
 
+       opts = SC_get_ARD(stmt);
        if (stmt->status == STMT_EXECUTING)
        {
                stmt->errormsg = "Can't bind columns while statement is still executing.";
@@ -188,13 +142,14 @@ PGAPI_BindCol(
                return SQL_ERROR;
        }
 
+       SC_clear_error(stmt);
        /* If the bookmark column is being bound, then just save it */
        if (icol == 0)
        {
                if (rgbValue == NULL)
                {
-                       stmt->bookmark.buffer = NULL;
-                       stmt->bookmark.used = NULL;
+                       opts->bookmark->buffer = NULL;
+                       opts->bookmark->used = NULL;
                }
                else
                {
@@ -215,8 +170,8 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
                                        return SQL_ERROR;
                        }
 
-                       stmt->bookmark.buffer = rgbValue;
-                       stmt->bookmark.used = pcbValue;
+                       opts->bookmark->buffer = rgbValue;
+                       opts->bookmark->used = pcbValue;
                }
                return SQL_SUCCESS;
        }
@@ -226,11 +181,11 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
         * execution of a statement would have setup the necessary bindings.
         * But some apps call BindCol before any statement is executed.
         */
-       if (icol > stmt->bindings_allocated)
-               extend_bindings(stmt, icol);
+       if (icol > opts->allocated)
+               extend_column_bindings(opts, icol);
 
        /* check to see if the bindings were allocated */
-       if (!stmt->bindings)
+       if (!opts->bindings)
        {
                stmt->errormsg = "Could not allocate memory for bindings.";
                stmt->errornumber = STMT_NO_MEMORY_ERROR;
@@ -242,25 +197,29 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
        icol--;
 
        /* Reset for SQLGetData */
-       stmt->bindings[icol].data_left = -1;
+       opts->bindings[icol].data_left = -1;
 
        if (rgbValue == NULL)
        {
                /* we have to unbind the column */
-               stmt->bindings[icol].buflen = 0;
-               stmt->bindings[icol].buffer = NULL;
-               stmt->bindings[icol].used = NULL;
-               stmt->bindings[icol].returntype = SQL_C_CHAR;
+               opts->bindings[icol].buflen = 0;
+               opts->bindings[icol].buffer = NULL;
+               opts->bindings[icol].used = NULL;
+               opts->bindings[icol].returntype = SQL_C_CHAR;
+               if (opts->bindings[icol].ttlbuf)
+                       free(opts->bindings[icol].ttlbuf);
+               opts->bindings[icol].ttlbuf = NULL;
+               opts->bindings[icol].ttlbuflen = 0;
        }
        else
        {
                /* ok, bind that column */
-               stmt->bindings[icol].buflen = cbValueMax;
-               stmt->bindings[icol].buffer = rgbValue;
-               stmt->bindings[icol].used = pcbValue;
-               stmt->bindings[icol].returntype = fCType;
+               opts->bindings[icol].buflen = cbValueMax;
+               opts->bindings[icol].buffer = rgbValue;
+               opts->bindings[icol].used = pcbValue;
+               opts->bindings[icol].returntype = fCType;
 
-               mylog("       bound buffer[%d] = %u\n", icol, stmt->bindings[icol].buffer);
+               mylog("       bound buffer[%d] = %u\n", icol, opts->bindings[icol].buffer);
        }
 
        return SQL_SUCCESS;
@@ -286,6 +245,7 @@ PGAPI_DescribeParam(
 {
        StatementClass *stmt = (StatementClass *) hstmt;
        static char *func = "PGAPI_DescribeParam";
+       APDFields       *opts;
 
        mylog("%s: entering...\n", func);
 
@@ -296,7 +256,8 @@ PGAPI_DescribeParam(
        }
        SC_clear_error(stmt);
 
-       if ((ipar < 1) || (ipar > stmt->parameters_allocated))
+       opts = SC_get_APD(stmt);
+       if ((ipar < 1) || (ipar > opts->allocated))
        {
                stmt->errormsg = "Invalid parameter number for PGAPI_DescribeParam.";
                stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR;
@@ -312,16 +273,16 @@ PGAPI_DescribeParam(
         */
        /* parameter markers, not bound parameters.  */
        if (pfSqlType)
-               *pfSqlType = stmt->parameters[ipar].SQLType;
+               *pfSqlType = opts->parameters[ipar].SQLType;
 
        if (pcbColDef)
-               *pcbColDef = stmt->parameters[ipar].precision;
+               *pcbColDef = opts->parameters[ipar].precision;
 
        if (pibScale)
-               *pibScale = stmt->parameters[ipar].scale;
+               *pibScale = opts->parameters[ipar].scale;
 
        if (pfNullable)
-               *pfNullable = pgtype_nullable(stmt, stmt->parameters[ipar].paramType);
+               *pfNullable = pgtype_nullable(stmt, opts->parameters[ipar].paramType);
 
        return SQL_SUCCESS;
 }
@@ -336,11 +297,13 @@ PGAPI_ParamOptions(
 {
        static char *func = "PGAPI_ParamOptions";
        StatementClass *stmt = (StatementClass *) hstmt;
+       APDFields       *opts;
 
        mylog("%s: entering... %d %x\n", func, crow, pirow);
 
-       stmt->options.paramset_size = crow;
-       stmt->options.param_processed_ptr = (SQLUINTEGER *)pirow;
+       opts = SC_get_APD(stmt);
+       opts->paramset_size = crow;
+       SC_get_IPD(stmt)->param_processed_ptr = (UInt4 *) pirow;
        return SQL_SUCCESS;
 }
 
@@ -433,46 +396,156 @@ create_empty_bindings(int num_columns)
        return new_bindings;
 }
 
+void
+extend_parameter_bindings(APDFields *self, int num_params)
+{
+       static char *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);
+
+       /*
+        * if we have too few, allocate room for more, and copy the old
+        * entries into the new structure
+        */
+       if (self->allocated < num_params)
+       {
+               new_bindings = (ParameterInfoClass *) realloc(self->parameters, sizeof(ParameterInfoClass) * num_params);
+               if (!new_bindings)
+               {
+                       mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_params, self->allocated);
+
+                       self->parameters = NULL;
+                       self->allocated = 0;
+                       return;
+               }
+               memset(&new_bindings[self->allocated], 0,
+                       sizeof(ParameterInfoClass) * (num_params - self->allocated));
+
+               self->parameters = new_bindings;
+               self->allocated = num_params;
+       }
+
+       mylog("exit extend_parameter_bindings\n");
+}
+
+void
+reset_a_parameter_binding(APDFields *self, int ipar)
+{
+       static char *func = "reset_a_parameter_binding";
+
+       mylog("%s: entering ... self=%u, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar);
+
+       if (ipar < 1 || ipar > self->allocated)
+               return;
+
+       ipar--;
+       self->parameters[ipar].buflen = 0;
+       self->parameters[ipar].buffer = 0;
+       self->parameters[ipar].used = 0;
+       self->parameters[ipar].paramType = 0;
+       self->parameters[ipar].CType = 0;
+       if (self->parameters[ipar].EXEC_used)
+       {
+               free(self->parameters[ipar].EXEC_used);
+               self->parameters[ipar].EXEC_used = NULL;
+       }
+
+       if (self->parameters[ipar].EXEC_buffer)
+       {
+               if (self->parameters[ipar].SQLType != SQL_LONGVARBINARY)
+                       free(self->parameters[ipar].EXEC_buffer);
+               self->parameters[ipar].EXEC_buffer = NULL;
+       }
+       self->parameters[ipar].SQLType = 0;
+       self->parameters[ipar].precision = 0;
+       self->parameters[ipar].scale = 0;
+       self->parameters[ipar].data_at_exec = FALSE;
+       self->parameters[ipar].lobj_oid = 0;
+}
+
+/*
+ *     Free parameters and free the memory.
+ */
+void
+APD_free_params(APDFields *self, char option)
+{
+       int                     i;
+
+       mylog("APD_free_params:  ENTER, self=%d\n", self);
+
+       if (!self->parameters)
+               return;
+
+       for (i = 0; i < self->allocated; i++)
+       {
+               if (self->parameters[i].data_at_exec)
+               {
+                       if (self->parameters[i].EXEC_used)
+                       {
+                               free(self->parameters[i].EXEC_used);
+                               self->parameters[i].EXEC_used = NULL;
+                       }
+
+                       if (self->parameters[i].EXEC_buffer)
+                       {
+                               if (self->parameters[i].SQLType != SQL_LONGVARBINARY)
+                                       free(self->parameters[i].EXEC_buffer);
+                               self->parameters[i].EXEC_buffer = NULL;
+                       }
+               }
+       }
+
+       if (option == STMT_FREE_PARAMS_ALL)
+       {
+               if (self->parameters);
+                       free(self->parameters);
+               self->parameters = NULL;
+               self->allocated = 0;
+       }
+
+       mylog("APD_free_params:  EXIT\n");
+}
 
 void
-extend_bindings(StatementClass *stmt, int num_columns)
+extend_column_bindings(ARDFields *self, int num_columns)
 {
-       static char *func = "extend_bindings";
+       static char *func = "extend_column_bindings";
        BindInfoClass *new_bindings;
        int                     i;
 
-       mylog("%s: entering ... stmt=%u, bindings_allocated=%d, num_columns=%d\n", func, stmt, stmt->bindings_allocated, num_columns);
+       mylog("%s: entering ... self=%u, 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
         * entries into the new structure
         */
-       if (stmt->bindings_allocated < num_columns)
+       if (self->allocated < num_columns)
        {
                new_bindings = create_empty_bindings(num_columns);
                if (!new_bindings)
                {
-                       mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_columns, stmt->bindings_allocated);
+                       mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_columns, self->allocated);
 
-                       if (stmt->bindings)
+                       if (self->bindings)
                        {
-                               free(stmt->bindings);
-                               stmt->bindings = NULL;
+                               free(self->bindings);
+                               self->bindings = NULL;
                        }
-                       stmt->bindings_allocated = 0;
+                       self->allocated = 0;
                        return;
                }
 
-               if (stmt->bindings)
+               if (self->bindings)
                {
-                       for (i = 0; i < stmt->bindings_allocated; i++)
-                               new_bindings[i] = stmt->bindings[i];
+                       for (i = 0; i < self->allocated; i++)
+                               new_bindings[i] = self->bindings[i];
 
-                       free(stmt->bindings);
+                       free(self->bindings);
                }
 
-               stmt->bindings = new_bindings;
-               stmt->bindings_allocated = num_columns;
+               self->bindings = new_bindings;
+               self->allocated = num_columns;
        }
 
        /*
@@ -485,5 +558,53 @@ extend_bindings(StatementClass *stmt, int num_columns)
        /* SQLExecDirect(...)  # returns 5 cols */
        /* SQLExecDirect(...)  # returns 10 cols  (now OK) */
 
-       mylog("exit extend_bindings\n");
+       mylog("exit extend_column_bindings\n");
+}
+
+void
+reset_a_column_binding(ARDFields *self, int icol)
+{
+       static char *func = "reset_a_column_binding";
+
+       mylog("%s: entering ... self=%u, bindings_allocated=%d, icol=%d\n", func, self, self->allocated, icol);
+
+       if (icol > self->allocated)
+               return;
+
+       /* use zero based col numbers from here out */
+       if (0 == icol)
+       {
+               self->bookmark->buffer = NULL;
+               self->bookmark->used = NULL;
+       }
+       else
+       {
+               icol--;
+
+               /* we have to unbind the column */
+               self->bindings[icol].buflen = 0;
+               self->bindings[icol].buffer = NULL;
+               self->bindings[icol].used = NULL;
+               self->bindings[icol].data_left = -1;
+               self->bindings[icol].returntype = SQL_C_CHAR;
+               if (self->bindings[icol].ttlbuf)
+                       free(self->bindings[icol].ttlbuf);
+               self->bindings[icol].ttlbuf = NULL;
+               self->bindings[icol].ttlbuflen = 0;
+       }
 }
+
+void   ARD_unbind_cols(ARDFields *self, BOOL freeall)
+{
+       Int2    lf;
+
+       for (lf = 1; lf <= self->allocated; lf++)
+               reset_a_column_binding(self, lf);
+       if (freeall)
+       {
+               if (self->bindings)
+                       free(self->bindings);
+               self->bindings = NULL;
+               self->allocated = 0;
+       }
+} 
index 34b9e1d..16d9f84 100644 (file)
@@ -50,6 +50,9 @@ struct ParameterInfoClass_
 };
 
 BindInfoClass *create_empty_bindings(int num_columns);
-void           extend_bindings(StatementClass *stmt, int num_columns);
+void   extend_column_bindings(ARDFields *opts, int num_columns);
+void   reset_a_column_binding(ARDFields *opts, int icol);
+void   extend_parameter_bindings(APDFields *opts, int num_columns);
+void   reset_a_parameter_binding(APDFields *opts, int ipar);
 
 #endif
index a26913d..db237b3 100644 (file)
@@ -298,8 +298,8 @@ CC_Constructor()
                /* Statements under this conn will inherit these options */
 
                InitializeStatementOptions(&rv->stmtOptions);
-
-
+               InitializeARDFields(&rv->ardOptions);
+               InitializeAPDFields(&rv->apdOptions);
        }
        return rv;
 }
@@ -381,8 +381,6 @@ CC_begin(ConnectionClass *self)
                {
                        ret = QR_command_successful(res);
                        QR_Destructor(res);
-                       if (ret)
-                               CC_set_in_trans(self);
                }
                else
                        return FALSE;
@@ -403,9 +401,6 @@ CC_commit(ConnectionClass *self)
        {
                QResultClass *res = CC_send_query(self, "COMMIT", NULL, CLEAR_RESULT_ON_ABORT);
                mylog("CC_commit:  sending COMMIT!\n");
-
-               CC_set_no_trans(self);
-
                if (res != NULL)
                {
                        ret = QR_command_successful(res);
@@ -429,9 +424,6 @@ CC_abort(ConnectionClass *self)
        {
                QResultClass *res = CC_send_query(self, "ROLLBACK", NULL, CLEAR_RESULT_ON_ABORT);
                mylog("CC_abort:  sending ABORT!\n");
-
-               CC_set_no_trans(self);
-
                if (res != NULL)
                        QR_Destructor(res);
                else
@@ -1118,6 +1110,23 @@ CC_get_error(ConnectionClass *self, int *number, char **message)
 }
 
 
+void   CC_on_commit(ConnectionClass *conn, BOOL set_no_trans)
+{
+       if (CC_is_in_trans(conn))
+       {
+               if (set_no_trans)
+                       CC_set_no_trans(conn);
+       }
+}
+void   CC_on_abort(ConnectionClass *conn, BOOL set_no_trans)
+{
+       if (CC_is_in_trans(conn))
+       {
+               if (set_no_trans)
+                       CC_set_no_trans(conn);
+       }
+}
+
 /*
  *     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
@@ -1134,7 +1143,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
                           *retres = NULL,
                           *res = NULL;
        BOOL    clear_result_on_abort = ((flag & CLEAR_RESULT_ON_ABORT) != 0),
-               create_keyset = ((flag & CREATE_KEYSET) != 0);
+               create_keyset = ((flag & CREATE_KEYSET) != 0),
+               issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self));
        char            swallow,
                           *wq;
        int                     id;
@@ -1146,7 +1156,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
                                query_completed = FALSE,
                                before_64 = PG_VERSION_LT(self, 6.4),
                                aborted = FALSE,
-                               used_passed_result_object = FALSE;
+                               used_passed_result_object = FALSE,
+                               set_no_trans;
 
        /* ERROR_MSG_LENGTH is suffcient */
        static char msgbuffer[ERROR_MSG_LENGTH + 1];
@@ -1173,7 +1184,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
        {
                self->errornumber = CONNECTION_COULD_NOT_SEND;
                self->errormsg = "Could not send Query to backend";
-               CC_set_no_trans(self);
+               CC_on_abort(self, TRUE);
                return NULL;
        }
 
@@ -1182,10 +1193,12 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
        {
                self->errornumber = CONNECTION_COULD_NOT_SEND;
                self->errormsg = "Could not send Query to backend";
-               CC_set_no_trans(self);
+               CC_on_abort(self, TRUE);
                return NULL;
        }
 
+       if (issue_begin)
+               SOCK_put_n_char(sock, "begin;", 6);
        SOCK_put_string(sock, query);
        SOCK_flush_output(sock);
 
@@ -1193,7 +1206,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
        {
                self->errornumber = CONNECTION_COULD_NOT_SEND;
                self->errormsg = "Could not send Query to backend";
-               CC_set_no_trans(self);
+               CC_on_abort(self, TRUE);
                return NULL;
        }
 
@@ -1230,7 +1243,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
                        self->errormsg = "No response from the backend";
 
                        mylog("send_query: 'id' - %s\n", self->errormsg);
-                       CC_set_no_trans(self);
+                       CC_on_abort(self, TRUE);
                        ReadyToReturn = TRUE;
                        retres = NULL;
                        break;
@@ -1254,7 +1267,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
                                        self->errornumber = CONNECTION_NO_RESPONSE;
                                        self->errormsg = "No response from backend while receiving a portal query command";
                                        mylog("send_query: 'C' - %s\n", self->errormsg);
-                                       CC_set_no_trans(self);
+                                       CC_on_abort(self, TRUE);
                                        ReadyToReturn = TRUE;
                                        retres = NULL;
                                }
@@ -1270,6 +1283,24 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
 
                                        mylog("send_query: setting cmdbuffer = '%s'\n", cmdbuffer);
 
+                                       if (strnicmp(cmdbuffer, "BEGIN", 5) == 0)
+                                       {
+                                               CC_set_in_trans(self);
+                                               if (issue_begin)
+                                               {
+                                                       issue_begin = FALSE;
+                                                       continue;
+                                               }
+                                       }
+                                       else if (strnicmp(cmdbuffer, "COMMIT", 6) == 0)
+                                               CC_on_commit(self, TRUE);
+                                       else if (strnicmp(cmdbuffer, "ROLLBACK", 8) == 0)
+                                               CC_on_abort(self, TRUE);
+                                       else if (strnicmp(cmdbuffer, "END", 3) == 0)
+                                               CC_on_commit(self, TRUE);
+                                       else if (strnicmp(cmdbuffer, "ABORT", 5) == 0)
+                                               CC_on_abort(self, TRUE);
+
                                        if (QR_command_successful(res))
                                                QR_set_status(res, PGRES_COMMAND_OK);
                                        QR_set_command(res, cmdbuffer);
@@ -1352,14 +1383,15 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
                                qlog("ERROR from backend during send_query: '%s'\n", msgbuffer);
 
                                /* We should report that an error occured. Zoltan */
-
+                               set_no_trans = FALSE;
                                if (!strncmp(msgbuffer, "FATAL", 5))
                                {
                                        self->errornumber = CONNECTION_SERVER_REPORTED_ERROR;
-                                       CC_set_no_trans(self);
+                                       set_no_trans = TRUE;
                                }
                                else
                                        self->errornumber = CONNECTION_SERVER_REPORTED_WARNING;
+                               CC_on_abort(self, set_no_trans);
                                QR_set_status(res, PGRES_FATAL_ERROR);
                                QR_set_message(res, msgbuffer);
                                QR_set_aborted(res, TRUE);
@@ -1377,9 +1409,6 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
                                if (query_completed)
                                {
                                        res->next = QR_Constructor();
-                                       if (create_keyset)
-                                               QR_set_haskeyset(res->next);
-                                       mylog("send_query: 'T' no result_in: res = %u\n", res->next);
                                        if (!res->next)
                                        {
                                                self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
@@ -1388,6 +1417,9 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
                                                retres = NULL;
                                                break;
                                        }
+                                       if (create_keyset)
+                                               QR_set_haskeyset(res->next);
+                                       mylog("send_query: 'T' no result_in: res = %u\n", res->next);
                                        res = res->next;
 
                                        if (qi)
@@ -1448,7 +1480,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
                        default:
                                self->errornumber = CONNECTION_BACKEND_CRAZY;
                                self->errormsg = "Unexpected protocol character from backend (send_query)";
-                               CC_set_no_trans(self);
+                               CC_on_abort(self, TRUE);
 
                                mylog("send_query: error - %s\n", self->errormsg);
                                ReadyToReturn = TRUE;
@@ -1536,7 +1568,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
        {
                self->errornumber = CONNECTION_COULD_NOT_SEND;
                self->errormsg = "Could not send function to backend";
-               CC_set_no_trans(self);
+               CC_on_abort(self, TRUE);
                return FALSE;
        }
 
@@ -1545,7 +1577,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
        {
                self->errornumber = CONNECTION_COULD_NOT_SEND;
                self->errormsg = "Could not send function to backend";
-               CC_set_no_trans(self);
+               CC_on_abort(self, TRUE);
                return FALSE;
        }
 
@@ -1594,6 +1626,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
                        case 'E':
                                SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
                                self->errormsg = msgbuffer;
+                               CC_on_abort(self, FALSE);
 
                                mylog("send_function(V): 'E' - %s\n", self->errormsg);
                                qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
@@ -1606,7 +1639,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
                        default:
                                self->errornumber = CONNECTION_BACKEND_CRAZY;
                                self->errormsg = "Unexpected protocol character from backend (send_function, args)";
-                               CC_set_no_trans(self);
+                               CC_on_abort(self, TRUE);
 
                                mylog("send_function: error - %s\n", self->errormsg);
                                return FALSE;
@@ -1640,7 +1673,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
                        case 'E':
                                SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
                                self->errormsg = msgbuffer;
-
+                               CC_on_abort(self, FALSE);
                                mylog("send_function(G): 'E' - %s\n", self->errormsg);
                                qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
 
@@ -1661,7 +1694,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
                        default:
                                self->errornumber = CONNECTION_BACKEND_CRAZY;
                                self->errormsg = "Unexpected protocol character from backend (send_function, result)";
-                               CC_set_no_trans(self);
+                               CC_on_abort(self, TRUE);
 
                                mylog("send_function: error - %s\n", self->errormsg);
                                return FALSE;
index ee19d27..67411ed 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include "descriptor.h"
 
 
 typedef enum
@@ -242,6 +243,8 @@ struct ConnectionClass_
        HENV            henv;                   /* environment this connection was created
                                                                 * on */
        StatementOptions stmtOptions;
+       ARDFields       ardOptions;
+       APDFields       apdOptions;
        char       *errormsg;
        int                     errornumber;
        CONN_Status status;
@@ -315,8 +318,11 @@ 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);
+void           CC_on_commit(ConnectionClass *conn, BOOL set_no_trans);
+void           CC_on_abort(ConnectionClass *conn, BOOL set_no_trans);
 
 /* 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 */
 #endif
index 94cd26c..c0a2706 100644 (file)
@@ -107,7 +107,7 @@ char           *mapFuncs[][2] = {
        {"DAYNAME",      "to_char($1, 'Day')" },
        {"DAYOFMONTH",  "cast(extract(day from $1) as integer)" },
        {"DAYOFWEEK",    "(cast(extract(dow from $1) as integer) + 1)" },
-       {"DAYOFYEAR",    "cast(extract(doy from $1) as integer)" },
+       {"DAYOFYEAR",    "cast(extract(doy from $1) as integer)" }, 
        {"HOUR",         "cast(extract(hour from $1) as integer)" },
        {"MINUTE",      "cast(extract(minute from $1) as integer)" },
        {"MONTH",       "cast(extract(month from $1) as integer)" },
@@ -311,8 +311,9 @@ stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, BOOL precision)
 int
 copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col)
 {
-       BindInfoClass *bic = &(stmt->bindings[col]);
-       UInt4   offset = stmt->options.row_offset_ptr ? *stmt->options.row_offset_ptr : 0;
+       ARDFields *opts = SC_get_ARD(stmt);
+       BindInfoClass *bic = &(opts->bindings[col]);
+       UInt4   offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
 
        return copy_and_convert_field(stmt, field_type, value, (Int2) bic->returntype, (PTR) (bic->buffer + offset),
                                                         (SDWORD) bic->buflen, (SDWORD *) (bic->used + (offset >> 2)));
@@ -325,6 +326,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                                           PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue)
 {
        static char *func = "copy_and_convert_field";
+       ARDFields       *opts = SC_get_ARD(stmt);
        Int4            len = 0,
                                copy_len = 0;
        SIMPLE_TIME st;
@@ -335,7 +337,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
        char       *rgbValueBindRow;
        const char *ptr;
        int                     bind_row = stmt->bind_row;
-       int                     bind_size = stmt->options.bind_size;
+       int                     bind_size = opts->bind_size;
        int                     result = COPY_OK;
        BOOL            changed, true_is_minus1 = FALSE;
        const char *neut_str = value;
@@ -349,7 +351,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
 
        if (stmt->current_col >= 0)
        {
-               pbic = &stmt->bindings[stmt->current_col];
+               pbic = &opts->bindings[stmt->current_col];
                if (pbic->data_left == -2)
                        pbic->data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be *
                                                 * needed for ADO ? */
@@ -404,7 +406,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                else
                {
                        stmt->errornumber = STMT_RETURN_NULL_WITHOUT_INDICATOR;
-                       stmt->errormsg = "StrLen_or_IndPtr was a null pointer and NULL data was retrieved";
+                       stmt->errormsg = "StrLen_or_IndPtr was a null pointer and NULL data was retrieved";     
                        SC_log_error(func, "", stmt);
                        return  SQL_ERROR;
                }
@@ -651,7 +653,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                                        pbic->data_left = -1;
                                }
                                else
-                                       pbic = &stmt->bindings[stmt->current_col];
+                                       pbic = &opts->bindings[stmt->current_col];
                                if (pbic->data_left < 0)
                                {
                                        BOOL lf_conv = SC_get_conn(stmt)->connInfo.lf_conversion;
@@ -759,7 +761,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                                if (cbValueMax < 2 * (SDWORD) ucount)
                                        result = COPY_RESULT_TRUNCATED;
                                len = ucount * 2;
-                               free(str);
+                               free(str); 
                        }
                        else
                        {
@@ -923,6 +925,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
 
                        case SQL_C_ULONG:
                                len = 4;
+inolog("rgb=%x + %d, pcb=%x, set %s\n", rgbValue, bind_row * bind_size, pcbValue, neut_str);
                                if (bind_size > 0)
                                        *(UDWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atol(neut_str);
                                else
@@ -960,7 +963,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                                        pbic->data_left = -1;
                                }
                                else
-                                       pbic = &stmt->bindings[stmt->current_col];
+                                       pbic = &opts->bindings[stmt->current_col];
                                if (!pbic->ttlbuf)
                                        pbic->ttlbuflen = 0;
                                if (len = strlen(neut_str), len >= (int) pbic->ttlbuflen)
@@ -1026,7 +1029,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                *(SDWORD *) ((char *) pcbValue + pcbValueOffset) = len;
 
        if (result == COPY_OK && stmt->current_col >= 0)
-               stmt->bindings[stmt->current_col].data_left = 0;
+               opts->bindings[stmt->current_col].data_left = 0;
        return result;
 
 }
@@ -1283,16 +1286,14 @@ copy_statement_with_parameters(StatementClass *stmt)
        char            token_save[64];
        int                     token_len;
        BOOL            prev_token_end;
-       UInt4   offset = stmt->options.param_offset_ptr ? *stmt->options.param_offset_ptr : 0;
+       APDFields       *opts = SC_get_APD(stmt);
+       UInt4   offset = opts->param_offset_ptr ? *opts->param_offset_ptr : 0;
        UInt4   current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
        BOOL    lf_conv = ci->lf_conversion;
 #ifdef MULTIBYTE
        encoded_str     encstr;
 #endif   /* MULTIBYTE */
 
-#ifdef DRIVER_CURSOR_IMPLEMENT
-       BOOL            search_from_pos = FALSE;
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
        Int4    from_pos = -1, where_pos = -1;
 
        if (ci->disallow_premature)
@@ -1324,17 +1325,20 @@ copy_statement_with_parameters(StatementClass *stmt)
        {
                if (stmt->parse_status == STMT_PARSE_NONE)
                        parse_statement(stmt);
-               if (stmt->parse_status != STMT_PARSE_COMPLETE)
+               /*if (stmt->parse_status != STMT_PARSE_COMPLETE)
                        stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-               else if (!stmt->ti || stmt->ntab != 1)
+               else*/ if (!stmt->updatable)
                        stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
                else
                {
-                       /** search_from_pos = TRUE; **/
                        from_pos = stmt->from_pos;
                        where_pos = stmt->where_pos;
                }
        }
+#else
+       stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
+       if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
+               stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY;
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
 
        /* If the application hasn't set a cursor name, then generate one */
@@ -1433,8 +1437,7 @@ copy_statement_with_parameters(StatementClass *stmt)
                 */
                else if (oldchar == '{')
                {
-                       char       *begin = &old_statement[opos];
-                       const char *end;
+                       const char      *begin = &old_statement[opos], *end;
 
                        /* procedure calls */
                        if (stmt->statement_type == STMT_TYPE_PROCCALL)
@@ -1466,8 +1469,8 @@ copy_statement_with_parameters(StatementClass *stmt)
                                        proc_no_param = FALSE;
                                continue;
                        }
-                       if (convert_escape(begin, stmt, &npos, &new_stsize, &end) !=
-                               CONVERT_ESCAPE_OK)
+                       if (convert_escape(begin, stmt, &npos, &new_stsize, &end
+) != CONVERT_ESCAPE_OK)
                        {
                                stmt->errormsg = "ODBC escape convert error";
                                stmt->errornumber = STMT_EXEC_ERROR;
@@ -1522,15 +1525,6 @@ copy_statement_with_parameters(StatementClass *stmt)
                                                                memmove(new_statement, new_statement + declare_pos, npos - declare_pos);
                                                                npos -= declare_pos;
                                                        }
-#ifdef DRIVER_CURSOR_IMPLEMENT
-                                                       else if (search_from_pos && /* where's from clause */
-                                                                        strnicmp(token_save, "from", 4) == 0)
-                                                       {
-                                                               search_from_pos = FALSE;
-                                                               npos -= 5;
-                                                               CVT_APPEND_STR(", CTID, OID from");
-                                                       }
-#endif   /* DRIVER_CURSOR_IMPLEMENT */
                                                }
                                                if (token_len == 3)
                                                {
@@ -1574,7 +1568,7 @@ copy_statement_with_parameters(StatementClass *stmt)
                 */
                param_number++;
 
-               if (param_number >= stmt->parameters_allocated)
+               if (param_number >= opts->allocated)
                {
                        if (stmt->pre_executing)
                        {
@@ -1590,34 +1584,34 @@ copy_statement_with_parameters(StatementClass *stmt)
                }
 
                /* Assign correct buffers based on data at exec param or not */
-               if (stmt->parameters[param_number].data_at_exec)
+               if (opts->parameters[param_number].data_at_exec)
                {
-                       used = stmt->parameters[param_number].EXEC_used ? *stmt->parameters[param_number].EXEC_used : SQL_NTS;
-                       buffer = stmt->parameters[param_number].EXEC_buffer;
+                       used = opts->parameters[param_number].EXEC_used ? *opts->parameters[param_number].EXEC_used : SQL_NTS;
+                       buffer = opts->parameters[param_number].EXEC_buffer;
                }
                else
                {
-                       UInt4   bind_size = stmt->options.param_bind_type;
+                       UInt4   bind_size = opts->param_bind_type;
                        UInt4   ctypelen;
 
-                       buffer = stmt->parameters[param_number].buffer + offset;
+                       buffer = opts->parameters[param_number].buffer + offset;
                        if (current_row > 0)
                        {
                                if (bind_size > 0)
                                        buffer += (bind_size * current_row);
-                               else if (ctypelen = ctype_length(stmt->parameters[param_number].CType), ctypelen > 0)
+                               else if (ctypelen = ctype_length(opts->parameters[param_number].CType), ctypelen > 0)
                                        buffer += current_row * ctypelen;
-                               else
-                                       buffer += current_row * stmt->parameters[param_number].buflen;
+                               else 
+                                       buffer += current_row * opts->parameters[param_number].buflen;
                        }
-                       if (stmt->parameters[param_number].used)
+                       if (opts->parameters[param_number].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 *)stmt->parameters[param_number].used + p_offset);
+                               used = *(SDWORD *)((char *)opts->parameters[param_number].used + p_offset);
                        }
                        else
                                used = SQL_NTS;
@@ -1649,8 +1643,8 @@ copy_statement_with_parameters(StatementClass *stmt)
                        }
                }
 
-               param_ctype = stmt->parameters[param_number].CType;
-               param_sqltype = stmt->parameters[param_number].SQLType;
+               param_ctype = opts->parameters[param_number].CType;
+               param_sqltype = opts->parameters[param_number].SQLType;
 
                mylog("copy_statement_with_params: from(fcType)=%d, to(fSqlType)=%d\n", param_ctype, param_sqltype);
 
@@ -1907,8 +1901,8 @@ copy_statement_with_parameters(StatementClass *stmt)
 
                        case SQL_LONGVARBINARY:
 
-                               if (stmt->parameters[param_number].data_at_exec)
-                                       lobj_oid = stmt->parameters[param_number].lobj_oid;
+                               if (opts->parameters[param_number].data_at_exec)
+                                       lobj_oid = opts->parameters[param_number].lobj_oid;
                                else
                                {
                                        /* begin transaction if needed */
@@ -2048,13 +2042,14 @@ copy_statement_with_parameters(StatementClass *stmt)
        }
 
 #ifdef DRIVER_CURSOR_IMPLEMENT
-       if (search_from_pos)
-               stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
        if (!stmt->load_statement && from_pos >=0)
        {
                stmt->load_statement = malloc(npos + 1);
                memcpy(stmt->load_statement, new_statement, npos);
-               stmt->load_statement[npos] = '\0';
+               if (stmt->load_statement[npos - 1] == ';')
+                       stmt->load_statement[npos - 1] = '\0';
+               else
+                       stmt->load_statement[npos] = '\0';
        }
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
        if (prepare_dummy_cursor && SC_is_pre_executable(stmt))
@@ -2083,7 +2078,7 @@ mapFunction(const char *func, int param_count)
                if (mapFuncs[i][0][0] == '%')
                {
                        if (mapFuncs[i][0][1] - '0' == param_count &&
-                               !stricmp(mapFuncs[i][0] + 2, func))
+                           !stricmp(mapFuncs[i][0] + 2, func))
                                return mapFuncs[i][1];
                }
                else if (!stricmp(mapFuncs[i][0], func))
@@ -2101,7 +2096,7 @@ static int processParameters(const ConnectionClass *conn, const char *value, cha
  * inner_convert_escape()
  * work with embedded escapes sequences
  */
-
+     
 static
 int inner_convert_escape(const ConnectionClass *conn, const char *value,
                char *result, UInt4 maxLen, const char **input_resume,
@@ -2114,7 +2109,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
        const char *valptr;
        UInt4   vlen, prtlen, input_consumed, param_consumed, extra_len;
        Int4    param_pos[16][2];
-
        valptr = value;
        if (*valptr == '{') /* skip the first { */
                valptr++;
@@ -2126,7 +2121,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
                valptr++;
        while ((*valptr != '\0') && isspace((unsigned char) *valptr))
                valptr++;
-
+     
        if (end = my_strchr(conn, valptr, '}'), NULL == end)
        {
                mylog("%s couldn't find the ending }\n",func);
@@ -2138,7 +2133,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
        valnts[vlen] = '\0';
        *input_resume = valptr + vlen; /* resume from the last } */
        mylog("%s: key='%s', val='%s'\n", func, key, valnts);
-
+     
        extra_len = 0;
        if (isalnum(result[-1])) /* Avoid the concatenation of the function name with the previous word. Aceto */
        {
@@ -2175,7 +2170,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
        {
                /* Literal; return the escape part as-is */
                strncpy(result, valnts, maxLen);
-               prtlen = vlen;
+               prtlen = vlen; 
        }
        else if (strcmp(key, "fn") == 0)
        {
@@ -2186,7 +2181,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
                char    *funcEnd = valnts;
                char     svchar;
                const char      *mapExpr;
-
+     
                params[sizeof(params)-1] = '\0';
 
                while ((*funcEnd != '\0') && (*funcEnd != '(') &&
@@ -2200,7 +2195,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
                        funcEnd++;
 
                /*
-                * We expect left parenthesis here, else return fn body as-is
+                * We expect left parenthesis here, else return fn body as-is
                 * since it is one of those "function constants".
                 */
                if (*funcEnd != '(')
@@ -2216,7 +2211,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
                 */
 
                valptr += (UInt4)(funcEnd - valnts);
-               if (subret = processParameters(conn, valptr, params, sizeof(params) - 1, &input_consumed, &param_consumed, param_pos), CONVERT_ESCAPE_OK != subret)
+               if (subret = processParameters(conn, valptr, params, sizeof(params) - 1, &input_consumed, &param_consumed, param_pos), CONVERT_ESCAPE_OK != subret) 
                        return CONVERT_ESCAPE_ERROR;
 
                for (param_count = 0;; param_count++)
@@ -2225,9 +2220,9 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
                                break;
                }
                if (param_count == 1 &&
-                       param_pos[0][1] < param_pos[0][0])
+                   param_pos[0][1] < param_pos[0][0])
                        param_count = 0;
-
+               
                mapExpr = mapFunction(key, param_count);
                if (mapExpr == NULL)
                        prtlen = snprintf(result, maxLen, "%s%s", key, params);
@@ -2259,7 +2254,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
                                {
                                        pidx = *mapptr - '0' - 1;
                                        if (pidx < 0 ||
-                                               param_pos[pidx][0] <0)
+                                           param_pos[pidx][0] < 0)
                                        {
                                                qlog("%s %dth param not found for the expression %s\n", pidx + 1, mapExpr);
                                                return CONVERT_ESCAPE_ERROR;
@@ -2294,7 +2289,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
                /* Bogus key, leave untranslated */
                return CONVERT_ESCAPE_ERROR;
        }
-
+     
        if (count)
                *count = prtlen + extra_len;
        if (prtlen < 0 || prtlen >= maxLen) /* buffer overflow */
@@ -2304,12 +2299,12 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
        }
        return CONVERT_ESCAPE_OK;
 }
-
+     
 /*
  * processParameters()
  * Process function parameters and work with embedded escapes sequences.
  */
-
+     
 static
 int processParameters(const ConnectionClass *conn, const char *value,
                char *result, UInt4 maxLen, UInt4 *input_consumed,
@@ -2324,7 +2319,7 @@ int processParameters(const ConnectionClass *conn, const char *value,
 #ifdef MULTIBYTE
        encoded_str     encstr;
 #endif   /* MULTIBYTE */
-
        buf[sizeof(buf)-1] = '\0';
        innerParenthesis = 0;
        in_quote = in_dquote = in_escape = leadingSpace = FALSE;
@@ -2403,7 +2398,7 @@ int processParameters(const ConnectionClass *conn, const char *value,
                                }
                                innerParenthesis++;
                                break;
-
+     
                        case ')':
                                innerParenthesis--;
                                if (0 == innerParenthesis)
@@ -2414,18 +2409,18 @@ int processParameters(const ConnectionClass *conn, const char *value,
                                        param_pos[param_count][1] = -1;
                                }
                                break;
-
+     
                        case '}':
                                stop = TRUE;
                                break;
-
+     
                        case '{':
                                if (subret = inner_convert_escape(conn, valptr, buf, sizeof(buf) - 1, &valptr, &inner_count), CONVERT_ESCAPE_OK != subret)
                                        return CONVERT_ESCAPE_ERROR;
-
+     
                                if (inner_count + count >= maxLen)
                                        return CONVERT_ESCAPE_OVERFLOW;
-                               memcpy(&result[count], buf, inner_count);
+                               memcpy(&result[count], buf, inner_count); 
                                count += inner_count;
                                ipos = (UInt4) (valptr - value);
                                continue;
@@ -2445,15 +2440,14 @@ int processParameters(const ConnectionClass *conn, const char *value,
                *output_count = count;
        return CONVERT_ESCAPE_OK;
 }
-
+     
 /*
  * convert_escape()
  * This function returns a pointer to static memory!
  */
-
+     
 int
-convert_escape(const char *value, StatementClass *stmt, int *npos, int *stsize,
-                          const char **val_resume)
+convert_escape(const char *value, StatementClass *stmt, int *npos, int *stsize, const char **val_resume)
 {
        int     ret, pos = *npos;
        UInt4   count;
@@ -2920,12 +2914,13 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
        BindInfoClass *bindInfo = NULL;
        ConnectionClass *conn = SC_get_conn(stmt);
        ConnInfo   *ci = &(conn->connInfo);
+       ARDFields       *opts = SC_get_ARD(stmt);
        int                     factor = (fCType == SQL_C_CHAR ? 2 : 1);
 
        /* If using SQLGetData, then current_col will be set */
        if (stmt->current_col >= 0)
        {
-               bindInfo = &stmt->bindings[stmt->current_col];
+               bindInfo = &opts->bindings[stmt->current_col];
                left = bindInfo->data_left;
        }
 
diff --git a/src/interfaces/odbc/descriptor.h b/src/interfaces/odbc/descriptor.h
new file mode 100644 (file)
index 0000000..5803691
--- /dev/null
@@ -0,0 +1,96 @@
+/* File:                       descriptor.h
+ *
+ * Description:                This file contains defines and declarations that are related to
+ *                                     the entire driver.
+ *
+ * Comments:           See "notice.txt" for copyright and license information.
+ *
+ * $Id: descriptor.h,v 1.1 2002/03/28 08:08:02 inoue Exp $
+ *
+ */
+
+#ifndef __DESCRIPTOR_H__
+#define __DESCRIPTOR_H__
+
+#include "psqlodbc.h"
+
+typedef struct
+{
+       COL_INFO        *col_info; /* cached SQLColumns info for this table */
+       char            name[MAX_TABLE_LEN + 1];
+       char            alias[MAX_TABLE_LEN + 1];
+} TABLE_INFO;
+
+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            nullable;
+       char            func;
+       char            expr;
+       char            quote;
+       char            dquote;
+       char            numeric;
+       char            updatable;
+       char            dot[MAX_TABLE_LEN + 1];
+       char            name[MAX_COLUMN_LEN + 1];
+       char            alias[MAX_COLUMN_LEN + 1];
+} FIELD_INFO;
+
+struct ARDFields_
+{
+       StatementClass  *stmt;
+       int             rowset_size;
+       int             bind_size;      /* size of each structure if using Row
+                                                       * Binding */
+       UInt2           *row_operation_ptr;
+       UInt4           *row_offset_ptr;
+       BindInfoClass   *bookmark;
+       BindInfoClass   *bindings;
+       int             allocated;
+};
+
+struct APDFields_
+{
+       StatementClass  *stmt;
+       int             paramset_size;
+       int             param_bind_type; /* size of each structure if using Param
+                                               * Binding */
+       UInt2                   *param_operation_ptr;
+       UInt4                   *param_offset_ptr;
+       ParameterInfoClass      *parameters;
+       int                     allocated;
+};
+
+struct IRDFields_
+{
+       StatementClass  *stmt;
+       UInt4           *rowsFetched;
+       UInt2           *rowStatusArray;
+       UInt4           nfields;
+       FIELD_INFO      **fi;
+};
+
+struct IPDFields_
+{
+       StatementClass  *stmt;
+       UInt4           *param_processed_ptr;
+       UInt2           *param_status_ptr;
+};
+
+void   InitializeARDFields(ARDFields *self);
+void   InitializeAPDFields(APDFields *self);
+/* void        InitializeIRDFields(IRDFields *self);
+void   InitializeIPDFiedls(IPDFields *self); */
+void   ARDFields_free(ARDFields *self);
+void   APDFields_free(APDFields *self);
+void   IRDFields_free(IRDFields *self);
+void   IPDFields_free(IPDFields *self);
+void   ARD_unbind_cols(ARDFields *self, BOOL freeall);
+void   APD_free_params(APDFields *self, char option);
+
+#endif
index a95c676..a4423e4 100644 (file)
@@ -120,6 +120,9 @@ driver_optionsDraw(HWND hdlg, const ConnInfo *ci, int src, BOOL enable)
        }
 
        CheckDlgButton(hdlg, DRV_COMMLOG, comval->commlog);
+#ifndef Q_LOG
+       EnableWindow(GetDlgItem(hdlg, DRV_COMMLOG), FALSE);
+#endif /* Q_LOG */
        CheckDlgButton(hdlg, DRV_OPTIMIZER, comval->disable_optimizer);
        CheckDlgButton(hdlg, DRV_KSQO, comval->ksqo);
        CheckDlgButton(hdlg, DRV_UNIQUEINDEX, comval->unique_index);
@@ -153,6 +156,9 @@ driver_optionsDraw(HWND hdlg, const ConnInfo *ci, int src, BOOL enable)
        CheckDlgButton(hdlg, DRV_PARSE, comval->parse);
        CheckDlgButton(hdlg, DRV_CANCELASFREESTMT, comval->cancel_as_freestmt);
        CheckDlgButton(hdlg, DRV_DEBUG, comval->debug);
+#ifndef MY_LOG
+       EnableWindow(GetDlgItem(hdlg, DRV_DEBUG), FALSE);
+#endif /* MY_LOG */
        SetDlgItemInt(hdlg, DRV_CACHE_SIZE, comval->fetch_max, FALSE);
        SetDlgItemInt(hdlg, DRV_VARCHAR_SIZE, comval->max_varchar_size, FALSE);
        SetDlgItemInt(hdlg, DRV_LONGVARCHAR_SIZE, comval->max_longvarchar_size, TRUE);
@@ -221,7 +227,7 @@ driver_options_update(HWND hdlg, ConnInfo *ci, BOOL updateProfile)
 
 int                    CALLBACK
 driver_optionsProc(HWND hdlg,
-                                  WORD wMsg,
+                                  UINT wMsg,
                                   WPARAM wParam,
                                   LPARAM lParam)
 {
@@ -293,7 +299,7 @@ driver_optionsProc(HWND hdlg,
 
 int                    CALLBACK
 ds_optionsProc(HWND hdlg,
-                          WORD wMsg,
+                          UINT wMsg,
                           WPARAM wParam,
                           LPARAM lParam)
 {
@@ -334,6 +340,10 @@ ds_optionsProc(HWND hdlg,
                        CheckDlgButton(hdlg, DS_DISALLOWPREMATURE, ci->disallow_premature);
                        CheckDlgButton(hdlg, DS_LFCONVERSION, ci->lf_conversion);
                        CheckDlgButton(hdlg, DS_TRUEISMINUS1, ci->true_is_minus1);
+                       CheckDlgButton(hdlg, DS_UPDATABLECURSORS, ci->updatable_cursors);
+#ifndef DRIVER_CURSOR_IMPLEMENT
+                       EnableWindow(GetDlgItem(hdlg, DS_UPDATABLECURSORS), FALSE);
+#endif /* DRIVER_CURSOR_IMPLEMENT */
 
                        EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), atoi(ci->show_oid_column));
 
@@ -371,6 +381,9 @@ ds_optionsProc(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->updatable_cursors = IsDlgButtonChecked(hdlg, DS_UPDATABLECURSORS);
+#endif /* DRIVER_CURSOR_IMPLEMENT */
 
                                        /* OID Options */
                                        sprintf(ci->fake_oid_index, "%d", IsDlgButtonChecked(hdlg, DS_FAKEOIDINDEX));
index f293079..98ecac0 100644 (file)
@@ -169,11 +169,11 @@ void              SetDlgStuff(HWND hdlg, const ConnInfo *ci);
 void           GetDlgStuff(HWND hdlg, ConnInfo *ci);
 
 int CALLBACK driver_optionsProc(HWND hdlg,
-                                  WORD wMsg,
+                                  UINT wMsg,
                                   WPARAM wParam,
                                   LPARAM lParam);
 int CALLBACK ds_optionsProc(HWND hdlg,
-                          WORD wMsg,
+                          UINT wMsg,
                           WPARAM wParam,
                           LPARAM lParam);
 #endif   /* WIN32 */
index 618c5ef..4fdfe74 100644 (file)
@@ -94,7 +94,7 @@ PGAPI_StmtError(      HSTMT hstmt,
        StatementClass *stmt = (StatementClass *) hstmt;
        char            *msg;
        int             status;
-       BOOL    partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
+       BOOL            partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
                        clear_str = ((flag & PODBC_ERROR_CLEAR) != 0);
        SWORD           msglen, stapos, wrtlen, pcblen;
 
@@ -275,6 +275,9 @@ PGAPI_StmtError(    HSTMT hstmt,
                        case STMT_OPERATION_INVALID:
                                strcpy(szSqlState, "S1011");
                                break;
+                       case STMT_INVALID_DESCRIPTOR_IDENTIFIER:
+                               strcpy(szSqlState, "HY091");
+                               break;
                        case STMT_INVALID_OPTION_IDENTIFIER:
                                strcpy(szSqlState, "HY092");
                                break;
@@ -313,6 +316,7 @@ PGAPI_ConnectError( HDBC hdbc,
        BOOL    once_again = FALSE;
        SWORD           msglen;
 
+       mylog("**** PGAPI_ConnectError: hdbc=%u <%d>\n", hdbc, cbErrorMsgMax);
        if (RecNumber != 1)
                return SQL_NO_DATA_FOUND;
        if (cbErrorMsgMax < 0)
@@ -361,6 +365,7 @@ PGAPI_ConnectError( HDBC hdbc,
                                strcpy(szSqlState, "IM002");
                                /* data source not found */
                                break;
+                       case CONNECTION_SERVER_NOT_REACHED:
                        case CONN_OPENDB_ERROR:
                                strcpy(szSqlState, "08001");
                                /* unable to connect to data source */
@@ -413,6 +418,7 @@ PGAPI_ConnectError( HDBC hdbc,
                                break;
                }
 
+       mylog("      szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, msglen, szErrorMsg);
        if (once_again)
        {
                conn->errornumber = status;
@@ -436,6 +442,7 @@ PGAPI_EnvError(             HENV henv,
        char            *msg;
        int             status;
 
+       mylog("**** PGAPI_EnvError: henv=%u <%d>\n", henv, cbErrorMsgMax);
        if (RecNumber != 1)
                return SQL_NO_DATA_FOUND;
        if (cbErrorMsgMax < 0)
@@ -567,7 +574,7 @@ EN_Destructor(EnvironmentClass *self)
 
        mylog("exit EN_Destructor: rv = %d\n", rv);
 #ifdef _MEMORY_DEBUG_
-       debug_memory_inouecheck();
+       debug_memory_check();
 #endif   /* _MEMORY_DEBUG_ */
        return rv;
 }
index 8f05024..1189332 100644 (file)
@@ -206,9 +206,12 @@ PGAPI_Execute(
 {
        static char *func = "PGAPI_Execute";
        StatementClass *stmt = (StatementClass *) hstmt;
+       APDFields       *opts;
+       IPDFields       *ipdopts;
        ConnectionClass *conn;
        int                     i,
                                retval, start_row, end_row;
+       int     cursor_type, scroll_concurrency;
 
        mylog("%s: entering...\n", func);
 
@@ -219,6 +222,9 @@ PGAPI_Execute(
                return SQL_INVALID_HANDLE;
        }
 
+       opts = SC_get_APD(stmt);
+       cursor_type = stmt->options.cursor_type;
+       scroll_concurrency = stmt->options.scroll_concurrency;
        /*
         * If the statement is premature, it means we already executed it from
         * an SQLPrepare/SQLDescribeCol type of scenario.  So just return
@@ -297,24 +303,25 @@ PGAPI_Execute(
        if (start_row = stmt->exec_start_row, start_row < 0)
                start_row = 0; 
        if (end_row = stmt->exec_end_row, end_row < 0)
-               end_row = stmt->options.paramset_size - 1; 
+               end_row = opts->paramset_size - 1; 
        if (stmt->exec_current_row < 0)
                stmt->exec_current_row = start_row;
+       ipdopts = SC_get_IPD(stmt);
        if (stmt->exec_current_row == start_row)
        {
-               if (stmt->options.param_processed_ptr)
-                       *stmt->options.param_processed_ptr = 0;
+               if (ipdopts->param_processed_ptr)
+                       *ipdopts->param_processed_ptr = 0;
                SC_recycle_statement(stmt);
        }
 
 next_param_row:
 #if (ODBCVER >= 0x0300)
-       if (stmt->options.param_operation_ptr)
+       if (opts->param_operation_ptr)
        {
-               while (stmt->options.param_operation_ptr[stmt->exec_current_row] == SQL_PARAM_IGNORE)
+               while (opts->param_operation_ptr[stmt->exec_current_row] == SQL_PARAM_IGNORE)
                {
-                       if (stmt->options.param_status_ptr)
-                               stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_UNUSED;
+                       if (ipdopts->param_status_ptr)
+                               ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_UNUSED;
                        if (stmt->exec_current_row >= end_row)
                        {
                                stmt->exec_current_row = -1;
@@ -335,16 +342,16 @@ next_param_row:
                 * execute of this statement?  Therefore check for params and
                 * re-copy.
                 */
-               UInt4   offset = stmt->options.param_offset_ptr ? *stmt->options.param_offset_ptr : 0;
-               Int4    bind_size = stmt->options.param_bind_type;
+               UInt4   offset = opts->param_offset_ptr ? *opts->param_offset_ptr : 0;
+               Int4    bind_size = opts->param_bind_type;
                Int4    current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
 
                stmt->data_at_exec = -1;
-               for (i = 0; i < stmt->parameters_allocated; i++)
+               for (i = 0; i < opts->allocated; i++)
                {
-                       Int4       *pcVal = stmt->parameters[i].used;
+                       Int4       *pcVal = opts->parameters[i].used;
 
-                       stmt->parameters[i].data_at_exec = FALSE;
+                       opts->parameters[i].data_at_exec = FALSE;
                        if (pcVal)
                        {
                                if (bind_size > 0)
@@ -352,10 +359,10 @@ next_param_row:
                                else
                                        pcVal = (Int4 *)((char *)pcVal + offset + sizeof(SDWORD) * current_row);
                                if (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET)
-                                       stmt->parameters[i].data_at_exec = TRUE;
+                                       opts->parameters[i].data_at_exec = TRUE;
                        }
                        /* Check for data at execution parameters */
-                       if (stmt->parameters[i].data_at_exec)
+                       if (opts->parameters[i].data_at_exec)
                        {
                                if (stmt->data_at_exec < 0)
                                        stmt->data_at_exec = 1;
@@ -394,22 +401,22 @@ next_param_row:
                retval = SC_execute(stmt);
                if (retval != SQL_ERROR)
                {
-                       if (stmt->options.param_processed_ptr)
-                               (*stmt->options.param_processed_ptr)++;
+                       if (ipdopts->param_processed_ptr)
+                               (*ipdopts->param_processed_ptr)++;
                }
 #if (ODBCVER >= 0x0300)
-               if (stmt->options.param_status_ptr)
+               if (ipdopts->param_status_ptr)
                {
                        switch (retval)
                        {
                                case SQL_SUCCESS: 
-                                       stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
+                                       ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
                                        break;
                                case SQL_SUCCESS_WITH_INFO: 
-                                       stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
+                                       ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
                                        break;
                                default: 
-                                       stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
+                                       ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
                                        break;
                        }
                }
@@ -447,7 +454,6 @@ next_param_row:
                        }
                }
                /* we are now in a transaction */
-               CC_set_in_trans(conn);
                res = CC_send_query(conn, stmt->stmt_with_params, NULL, CLEAR_RESULT_ON_ABORT);
                if (!res)
                {
@@ -464,13 +470,18 @@ next_param_row:
                {
                        if (issued_begin)
                                CC_commit(conn);
-                       else if (!in_trans && begin_included)
-                               CC_set_no_trans(conn);
                }
                stmt->status = STMT_FINISHED;
                return SQL_SUCCESS;
        }
-       else
+       else if (stmt->options.cursor_type != cursor_type ||
+                stmt->options.scroll_concurrency != scroll_concurrency)
+       {
+               stmt->errornumber = STMT_OPTION_VALUE_CHANGED;
+               stmt->errormsg = "cursor updatability changed";
+               return SQL_SUCCESS_WITH_INFO;
+       }
+       else 
                return SQL_SUCCESS;
 }
 
@@ -534,11 +545,10 @@ 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);
-               CC_set_no_trans(conn);
-
                if (!res)
                {
                        /* error msg will be in the connection */
+                       CC_on_abort(conn, TRUE);
                        CC_log_error(func, "", conn);
                        return SQL_ERROR;
                }
@@ -548,6 +558,7 @@ PGAPI_Transact(
 
                if (!ok)
                {
+                       CC_on_abort(conn, TRUE);
                        CC_log_error(func, "", conn);
                        return SQL_ERROR;
                }
@@ -697,6 +708,8 @@ PGAPI_ParamData(
 {
        static char *func = "PGAPI_ParamData";
        StatementClass *stmt = (StatementClass *) hstmt;
+       APDFields       *opts;
+       IPDFields       *ipdopts;
        int                     i,
                                retval;
        ConnInfo   *ci;
@@ -709,8 +722,9 @@ PGAPI_ParamData(
                return SQL_INVALID_HANDLE;
        }
        ci = &(SC_get_conn(stmt)->connInfo);
+       opts = SC_get_APD(stmt);
 
-       mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, stmt->data_at_exec, stmt->parameters_allocated);
+       mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, stmt->data_at_exec, opts->allocated);
 
        if (stmt->data_at_exec < 0)
        {
@@ -720,7 +734,7 @@ PGAPI_ParamData(
                return SQL_ERROR;
        }
 
-       if (stmt->data_at_exec > stmt->parameters_allocated)
+       if (stmt->data_at_exec > opts->allocated)
        {
                stmt->errornumber = STMT_SEQUENCE_ERROR;
                stmt->errormsg = "Too many execution-time parameters were present";
@@ -748,6 +762,7 @@ PGAPI_ParamData(
        }
 
        /* Done, now copy the params and then execute the statement */
+       ipdopts = SC_get_IPD(stmt);
        if (stmt->data_at_exec == 0)
        {
                int     end_row;
@@ -761,28 +776,29 @@ PGAPI_ParamData(
                retval = SC_execute(stmt);
                if (retval != SQL_ERROR)
                {
-                       if (stmt->options.param_processed_ptr)
-                               (*stmt->options.param_processed_ptr)++;
+                       if (ipdopts->param_processed_ptr)
+                               (*ipdopts->param_processed_ptr)++;
                }
 #if (ODBCVER >= 0x0300)
-               if (stmt->options.param_status_ptr)
+               if (ipdopts->param_status_ptr)
                {
                        switch (retval)
                        {
                                case SQL_SUCCESS: 
-                                       stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
+                                       ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
                                        break;
                                case SQL_SUCCESS_WITH_INFO: 
-                                       stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
+                                       ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
                                        break;
                                default: 
-                                       stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
+                                       ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
                                        break;
                        }
                }
 #endif /* ODBCVER */
-               if (stmt->exec_end_row < 0)
-                       end_row = stmt->options.paramset_size - 1;
+               end_row = stmt->exec_end_row;
+               if (end_row < 0)
+                       end_row = opts->paramset_size - 1;
                if (retval == SQL_ERROR ||
                    stmt->exec_current_row >= end_row)
                {
@@ -800,14 +816,14 @@ PGAPI_ParamData(
        i = stmt->current_exec_param >= 0 ? stmt->current_exec_param + 1 : 0;
 
        /* At least 1 data at execution parameter, so Fill in the token value */
-       for (; i < stmt->parameters_allocated; i++)
+       for (; i < opts->allocated; i++)
        {
-               if (stmt->parameters[i].data_at_exec)
+               if (opts->parameters[i].data_at_exec)
                {
                        stmt->data_at_exec--;
                        stmt->current_exec_param = i;
                        stmt->put_data = FALSE;
-                       *prgbValue = stmt->parameters[i].buffer;        /* token */
+                       *prgbValue = opts->parameters[i].buffer;        /* token */
                        break;
                }
        }
@@ -828,6 +844,7 @@ PGAPI_PutData(
 {
        static char *func = "PGAPI_PutData";
        StatementClass *stmt = (StatementClass *) hstmt;
+       APDFields       *opts;
        int                     old_pos,
                                retval;
        ParameterInfoClass *current_param;
@@ -841,6 +858,7 @@ PGAPI_PutData(
                return SQL_INVALID_HANDLE;
        }
 
+       opts = SC_get_APD(stmt);
        if (stmt->current_exec_param < 0)
        {
                stmt->errornumber = STMT_SEQUENCE_ERROR;
@@ -849,7 +867,7 @@ PGAPI_PutData(
                return SQL_ERROR;
        }
 
-       current_param = &(stmt->parameters[stmt->current_exec_param]);
+       current_param = &(opts->parameters[stmt->current_exec_param]);
 
        if (!stmt->put_data)
        {                                                       /* first call */
index 99b1420..a2aba6c 100644 (file)
@@ -107,7 +107,7 @@ PGAPI_GetInfo(
                case SQL_BOOKMARK_PERSISTENCE:  /* ODBC 2.0 */
                        /* very simple bookmark support */
                        len = 4;
-                       value = ci->drivers.use_declarefetch ? 0 : (SQL_BP_SCROLL);
+                       value = ci->drivers.use_declarefetch ? 0 : (SQL_BP_SCROLL | SQL_BP_DELETE | SQL_BP_UPDATE | SQL_BP_TRANSACTION);
                        break;
 
                case SQL_COLUMN_ALIAS:  /* ODBC 2.0 */
@@ -495,8 +495,10 @@ PGAPI_GetInfo(
                case SQL_POS_OPERATIONS:                /* ODBC 2.0 */
                        len = 4;
                        value = ci->drivers.lie ? (SQL_POS_POSITION | SQL_POS_REFRESH | SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD) : (SQL_POS_POSITION | SQL_POS_REFRESH);
+#ifdef DRIVER_CURSOR_IMPLEMENT
                        if (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 */
@@ -554,8 +556,10 @@ PGAPI_GetInfo(
                                                                           SQL_SCCO_OPT_ROWVER |
                                                                           SQL_SCCO_OPT_VALUES) :
                                (SQL_SCCO_READ_ONLY);
+#ifdef DRIVER_CURSOR_IMPLEMENT
                        if (ci->updatable_cursors)
                                value |= SQL_SCCO_OPT_ROWVER;
+#endif /* DRIVER_CURSOR_IMPLEMENT */
                        break;
 
                case SQL_SCROLL_OPTIONS:                /* ODBC 1.0 */
@@ -588,8 +592,10 @@ PGAPI_GetInfo(
                case SQL_STATIC_SENSITIVITY:    /* ODBC 2.0 */
                        len = 4;
                        value = ci->drivers.lie ? (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES) : 0;
+#ifdef DRIVER_CURSOR_IMPLEMENT
                        if (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 */
@@ -753,7 +759,11 @@ PGAPI_GetTypeInfo(
        }
        SC_set_Result(stmt, res);
 
-       extend_bindings(stmt, 15);
+#if (ODBCVER >= 0x0399)
+       extend_column_bindings(SC_get_ARD(stmt), 19);
+#else
+       extend_column_bindings(SC_get_ARD(stmt), 15);
+#endif /* ODBCVER */
 
        QR_set_num_fields(res, 15);
        QR_set_field_info(res, 0, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
@@ -771,6 +781,12 @@ PGAPI_GetTypeInfo(
        QR_set_field_info(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_TEXT, 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);
+#if (ODBCVER >=0x0399)
+       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);
+#endif /* ODBCVER */
 
        for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i])
        {
@@ -795,7 +811,7 @@ PGAPI_GetTypeInfo(
                        set_tuplefield_null(&row->tuple[12]);
 
                        /* These values can be NULL */
-                       set_nullfield_int4(&row->tuple[2], pgtype_precision(stmt, pgType, PG_STATIC, PG_STATIC));
+                       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));
@@ -803,6 +819,12 @@ PGAPI_GetTypeInfo(
                        set_nullfield_int2(&row->tuple[11], pgtype_auto_increment(stmt, pgType));
                        set_nullfield_int2(&row->tuple[13], pgtype_scale(stmt, pgType, PG_STATIC));
                        set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, pgType, PG_STATIC));
+#if (ODBCVER >=0x0399)
+                       set_nullfield_int2(&row->tuple[15], pgtype_sqldesctype(stmt, pgType));
+                       set_nullfield_int2(&row->tuple[16], pgtype_datetime_sub(stmt, pgType));
+                       set_nullfield_int4(&row->tuple[17], pgtype_radix(stmt, pgType));
+                       set_nullfield_int4(&row->tuple[18], 0);
+#endif /* ODBCVER */
 
                        QR_add_tuple(res, row);
                }
@@ -1317,7 +1339,7 @@ PGAPI_Tables(
         * a statement is actually executed, so we'll have to do this
         * ourselves.
         */
-       extend_bindings(stmt, 5);
+       extend_column_bindings(SC_get_ARD(stmt), 5);
 
        /* set the field names */
        QR_set_num_fields(res, 5);
@@ -1523,13 +1545,15 @@ PGAPI_Columns(
                                field_name[MAX_INFO_STRING],
                                field_type_name[MAX_INFO_STRING];
        Int2            field_number, sqltype,
+                               reserved_cols,
                                result_cols,
-                               scale;
+                               decimal_digits;
        Int4            field_type,
                                the_type,
                                field_length,
                                mod_length,
-                               precision;
+                               column_size,
+                               ordinal;
        char            useStaticPrecision;
        char            not_null[MAX_INFO_STRING],
                                relhasrules[MAX_INFO_STRING];
@@ -1735,11 +1759,12 @@ PGAPI_Columns(
         * ourselves.
         */
 #if (ODBCVER >= 0x0300)
-       result_cols = 18;
+       reserved_cols = 18;
 #else
-       result_cols = 14;
+       reserved_cols = 12;
 #endif /* ODBCVER */
-       extend_bindings(stmt, result_cols);
+       result_cols = reserved_cols + 2;
+       extend_column_bindings(SC_get_ARD(stmt), result_cols);
 
        /* set the field names */
        QR_set_num_fields(res, result_cols);
@@ -1749,9 +1774,9 @@ PGAPI_Columns(
        QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_TEXT, 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_TEXT, MAX_INFO_STRING);
-       QR_set_field_info(res, 6, "PRECISION", PG_TYPE_INT4, 4);
-       QR_set_field_info(res, 7, "LENGTH", PG_TYPE_INT4, 4);
-       QR_set_field_info(res, 8, "SCALE", PG_TYPE_INT2, 2);
+       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_TEXT, 254);
@@ -1764,11 +1789,11 @@ PGAPI_Columns(
        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_TEXT, 254);
-#else
-       QR_set_field_info(res, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
-       QR_set_field_info(res, 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
 #endif /* ODBCVER */
+       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);
 
+       ordinal = 1;
        result = PGAPI_Fetch(hcol_stmt);
 
        /*
@@ -1794,14 +1819,13 @@ PGAPI_Columns(
                        set_tuplefield_string(&row->tuple[1], "");
                        set_tuplefield_string(&row->tuple[2], table_name);
                        set_tuplefield_string(&row->tuple[3], "oid");
-                       sqltype = pgtype_to_sqltype(stmt, the_type);
+                       sqltype = pgtype_to_concise_type(stmt, the_type);
                        set_tuplefield_int2(&row->tuple[4], sqltype);
                        set_tuplefield_string(&row->tuple[5], "OID");
 
-                       set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
-                       set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, the_type, PG_STATIC, PG_STATIC));
-
-                       set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, the_type, PG_STATIC));
+                       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], "");
@@ -1810,15 +1834,15 @@ PGAPI_Columns(
                        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_length(stmt, the_type, PG_STATIC, PG_STATIC));
-                       set_tuplefield_int4(&row->tuple[16], 0);
+                       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");
-#else
-                       set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
-                       set_tuplefield_int4(&row->tuple[13], the_type);
 #endif /* ODBCVER */
+                       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);
+                       ordinal++;
                }
        }
 
@@ -1834,7 +1858,7 @@ PGAPI_Columns(
                set_tuplefield_string(&row->tuple[1], "");
                set_tuplefield_string(&row->tuple[2], table_name);
                set_tuplefield_string(&row->tuple[3], field_name);
-               sqltype = pgtype_to_sqltype(stmt, field_type);
+               sqltype = pgtype_to_concise_type(stmt, field_type);
                set_tuplefield_int2(&row->tuple[4], sqltype);
                set_tuplefield_string(&row->tuple[5], field_type_name);
 
@@ -1845,15 +1869,15 @@ PGAPI_Columns(
                 * VARCHAR - the length is stored in the pg_attribute.atttypmod field
                 * BPCHAR  - the length is also stored as varchar is
                 *
-                * NUMERIC - the scale is stored in atttypmod as follows:
+                * NUMERIC - the decimal_digits is stored in atttypmod as follows:
                 *
-                *      precision =((atttypmod - VARHDRSZ) >> 16) & 0xffff
-                *      scale    = (atttypmod - VARHDRSZ) & 0xffff
+                *      column_size =((atttypmod - VARHDRSZ) >> 16) & 0xffff
+                *      decimal_digits   = (atttypmod - VARHDRSZ) & 0xffff
                 *
                 *----------
                 */
-               qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,sqltype=%d,name='%s'\n",
-                        table_name, field_name, field_type, pgtype_to_sqltype, field_type_name);
+               qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,name='%s'\n",
+                        table_name, field_name, field_type, field_type_name);
 
                useStaticPrecision = TRUE;
 
@@ -1866,15 +1890,18 @@ PGAPI_Columns(
                        {
                                useStaticPrecision = FALSE;
 
-                               precision = (mod_length >> 16) & 0xffff;
-                               scale = mod_length & 0xffff;
+                               column_size = (mod_length >> 16) & 0xffff;
+                               decimal_digits = mod_length & 0xffff;
 
-                               mylog("%s: field type is NUMERIC: field_type = %d, mod_length=%d, precision=%d, scale=%d\n", func, field_type, mod_length, precision, scale);
+                               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[7], precision + 2);             /* sign+dec.point */
-                               set_tuplefield_int4(&row->tuple[6], precision);
-                               set_tuplefield_int4(&row->tuple[12], precision + 2);    /* sign+dec.point */
-                               set_nullfield_int2(&row->tuple[8], scale);
+                               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);
+#if (ODBCVER >= 0x0300)
+                               set_tuplefield_null(&row->tuple[15]);
+#endif /* ODBCVER */
+                               set_tuplefield_int4(&row->tuple[reserved_cols], column_size + 2);       /* sign+dec.point */
                        }
                }
 
@@ -1891,54 +1918,42 @@ PGAPI_Columns(
 
                        mylog("%s: field type is VARCHAR,BPCHAR: field_type = %d, mod_length = %d\n", func, field_type, mod_length);
 
-                       set_tuplefield_int4(&row->tuple[7], mod_length);
                        set_tuplefield_int4(&row->tuple[6], mod_length);
-                       set_tuplefield_int4(&row->tuple[12], mod_length);
-                       set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, field_type, PG_STATIC));
+                       set_tuplefield_int4(&row->tuple[7], mod_length);
+                       set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC));
+#if (ODBCVER >= 0x0300)
+                       set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, field_type, PG_STATIC, PG_STATIC));
+#endif /* ODBCVER */
+                       set_tuplefield_int4(&row->tuple[reserved_cols], mod_length);
                }
 
                if (useStaticPrecision)
                {
-                       mylog("%s: field type is OTHER: field_type = %d, pgtype_length = %d\n", func, field_type, pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
+                       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[7], pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
-                       set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, field_type, PG_STATIC, PG_STATIC));
-                       set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC));
-                       set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, field_type, 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_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC));
+#if (ODBCVER >= 0x0300)
+                       set_tuplefield_null(&row->tuple[15]);
+#endif /* ODBCVER */
+                       set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC));
                }
 
                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], "");
 #if (ODBCVER >= 0x0300)
-               switch (sqltype)
-               {
-                       case SQL_TYPE_DATE:
-                               set_tuplefield_int2(&row->tuple[13], SQL_DATETIME);
-                               set_tuplefield_int2(&row->tuple[14], SQL_CODE_DATE);
-                               break;
-                       case SQL_TYPE_TIME:
-                               set_tuplefield_int2(&row->tuple[13], SQL_DATETIME);
-                               set_tuplefield_int2(&row->tuple[14], SQL_CODE_TIME);
-                               break;
-                       case SQL_TYPE_TIMESTAMP:
-                               set_tuplefield_int2(&row->tuple[13], SQL_DATETIME);
-                               set_tuplefield_int2(&row->tuple[14], SQL_CODE_TIMESTAMP);
-                               break;
-                       default:
-                               set_tuplefield_int2(&row->tuple[13], sqltype);
-                               set_tuplefield_null(&row->tuple[14]);
-                               break;
-               }
-               set_tuplefield_int4(&row->tuple[15], pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
-               set_tuplefield_int4(&row->tuple[16], field_number);
+               set_tuplefield_null(&row->tuple[12]);
+               set_tuplefield_int2(&row->tuple[13], pgtype_to_sqldesctype(stmt, field_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]);
-#else
-               set_tuplefield_int4(&row->tuple[13], field_type);
 #endif /* ODBCVER */
+               set_tuplefield_int4(&row->tuple[reserved_cols + 1], field_type);
 
                QR_add_tuple(res, row);
-
+               ordinal++;
 
                result = PGAPI_Fetch(hcol_stmt);
 
@@ -1968,12 +1983,12 @@ PGAPI_Columns(
                set_tuplefield_string(&row->tuple[1], "");
                set_tuplefield_string(&row->tuple[2], table_name);
                set_tuplefield_string(&row->tuple[3], "xmin");
-               sqltype = pgtype_to_sqltype(stmt, the_type);
+               sqltype = pgtype_to_concise_type(stmt, the_type);
                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_precision(stmt, the_type, PG_STATIC, PG_STATIC));
-               set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
-               set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, the_type, PG_STATIC));
+               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], "");
@@ -1981,15 +1996,15 @@ PGAPI_Columns(
                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_length(stmt, the_type, PG_STATIC, PG_STATIC));
-               set_tuplefield_int4(&row->tuple[16], 0);
+               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");
-#else
-               set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
-               set_tuplefield_int4(&row->tuple[13], the_type);
 #endif /* ODBCVER */
+               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);
+               ordinal++;
        }
 
        /*
@@ -2096,7 +2111,7 @@ PGAPI_SpecialColumns(
 
        res = QR_Constructor();
        SC_set_Result(stmt, res);
-       extend_bindings(stmt, 8);
+       extend_column_bindings(SC_get_ARD(stmt), 8);
 
        QR_set_num_fields(res, 8);
        QR_set_field_info(res, 0, "SCOPE", PG_TYPE_INT2, 2);
@@ -2117,11 +2132,11 @@ PGAPI_SpecialColumns(
 
                        set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION);
                        set_tuplefield_string(&row->tuple[1], "oid");
-                       set_tuplefield_int2(&row->tuple[2], pgtype_to_sqltype(stmt, PG_TYPE_OID));
+                       set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, PG_TYPE_OID));
                        set_tuplefield_string(&row->tuple[3], "OID");
-                       set_tuplefield_int4(&row->tuple[4], pgtype_precision(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
-                       set_tuplefield_int4(&row->tuple[5], pgtype_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
-                       set_tuplefield_int2(&row->tuple[6], pgtype_scale(stmt, PG_TYPE_OID, PG_STATIC));
+                       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);
@@ -2137,11 +2152,11 @@ PGAPI_SpecialColumns(
 
                                set_tuplefield_null(&row->tuple[0]);
                                set_tuplefield_string(&row->tuple[1], "xmin");
-                               set_tuplefield_int2(&row->tuple[2], pgtype_to_sqltype(stmt, the_type));
+                               set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type));
                                set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type));
-                               set_tuplefield_int4(&row->tuple[4], pgtype_precision(stmt, the_type, PG_STATIC, PG_STATIC));
-                               set_tuplefield_int4(&row->tuple[5], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
-                               set_tuplefield_int2(&row->tuple[6], pgtype_scale(stmt, the_type, PG_STATIC));
+                               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);
@@ -2227,7 +2242,7 @@ PGAPI_Statistics(
         * a statement is actually executed, so we'll have to do this
         * ourselves.
         */
-       extend_bindings(stmt, 13);
+       extend_column_bindings(SC_get_ARD(stmt), 13);
 
        /* set the field names */
        QR_set_num_fields(res, 13);
@@ -2671,7 +2686,7 @@ PGAPI_PrimaryKeys(
         * ourselves.
         */
        result_cols = 6;
-       extend_bindings(stmt, result_cols);
+       extend_column_bindings(SC_get_ARD(stmt), result_cols);
 
        /* set the field names */
        QR_set_num_fields(res, result_cols);
@@ -3067,7 +3082,7 @@ PGAPI_ForeignKeys(
         * ourselves.
         */
        result_cols = 14;
-       extend_bindings(stmt, result_cols);
+       extend_column_bindings(SC_get_ARD(stmt), result_cols);
 
        /* set the field names */
        QR_set_num_fields(res, result_cols);
@@ -3803,7 +3818,7 @@ PGAPI_Procedures(
         * results can be retrieved.
         */
        stmt->status = STMT_FINISHED;
-       extend_bindings(stmt, 8);
+       extend_column_bindings(SC_get_ARD(stmt), 8);
        /* set up the current tuple pointer for SQLFetch */
        stmt->currTuple = -1;
        stmt->rowset_start = -1;
@@ -3891,7 +3906,7 @@ PGAPI_TablePrivileges(
         * ourselves.
         */
        result_cols = 7;
-       extend_bindings(stmt, result_cols);
+       extend_column_bindings(SC_get_ARD(stmt), result_cols);
 
        /* set the field names */
        stmt->manual_result = TRUE;
@@ -3983,7 +3998,7 @@ PGAPI_TablePrivileges(
                                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)))
+                               if (gres = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), gres != NULL)
                                {
                                        grolist = QR_get_value_backend_row(gres, 0, 0);
                                        if (grolist && grolist[0] == '{')
index 414110b..c1c2c63 100644 (file)
@@ -53,14 +53,13 @@ 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_UPDATE | SQL_CA1_POS_DELETE
-                               | SQL_CA1_POS_REFRESH);
-                       if (ci->drivers.lie)
-                               value |= (SQL_CA1_BULK_ADD
+                               | SQL_CA1_POS_REFRESH | SQL_CA1_BULK_ADD
                                | SQL_CA1_BULK_UPDATE_BY_BOOKMARK
                                | SQL_CA1_BULK_DELETE_BY_BOOKMARK
                                | SQL_CA1_BULK_FETCH_BY_BOOKMARK
-
-                               | SQL_CA1_LOCK_EXCLUSIVE
+                               );
+                       if (ci->drivers.lie)
+                               value |= (SQL_CA1_LOCK_EXCLUSIVE
                                | SQL_CA1_LOCK_UNLOCK
                                | SQL_CA1_POSITIONED_UPDATE
                                | SQL_CA1_POSITIONED_DELETE
@@ -72,9 +71,10 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
                        value = 0;
                        if (ci->updatable_cursors || ci->drivers.lie)
                                value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
-                               | SQL_CA2_SENSITIVITY_ADDITIONS
                                | SQL_CA2_SENSITIVITY_DELETIONS
-                               | SQL_CA2_SENSITIVITY_UPDATES);
+                               | SQL_CA2_SENSITIVITY_UPDATES
+                               /* | SQL_CA2_SENSITIVITY_ADDITIONS */
+                               );
                        if (ci->drivers.lie)
                                value |= (SQL_CA2_READ_ONLY_CONCURRENCY
                                | SQL_CA2_LOCK_CONCURRENCY
@@ -97,19 +97,21 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
                        len = 4;
                        value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE
                                | SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK
-                               | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION;
+                               | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION
+                               | SQL_CA1_POS_REFRESH;
                        if (ci->updatable_cursors)
                                value |= (SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
-                               | SQL_CA1_POS_REFRESH);
+                               );
                        break;
                case SQL_STATIC_CURSOR_ATTRIBUTES2:
                        len = 4;
-                       value = 0;
+                       value = SQL_CA2_READ_ONLY_CONCURRENCY;
                        if (ci->updatable_cursors)
                                value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
-                               | SQL_CA2_SENSITIVITY_ADDITIONS
+                               /* | SQL_CA2_SENSITIVITY_ADDITIONS
                                | SQL_CA2_SENSITIVITY_DELETIONS
-                               | SQL_CA2_SENSITIVITY_UPDATES);
+                               | SQL_CA2_SENSITIVITY_UPDATES */
+                               );
                        break;
 
                case SQL_ODBC_INTERFACE_CONFORMANCE:
index 443d1f4..a7bcaca 100644 (file)
@@ -115,6 +115,11 @@ mylog(char *fmt,...)
                va_end(args);
        }
 }
+#else
+void
+MyLog(char *fmt,...)
+{
+}
 #endif
 
 
index b658ed7..cba7f2b 100644 (file)
 #define MYLOGDIR                       "/tmp"
 #else
 #define MYLOGDIR                       "c:"
-#endif
+#endif /* WIN32 */
 extern void mylog(char *fmt,...);
-#define        inolog  mylog   /* for really temporary debug */
 
 #else
 #ifndef WIN32
 #define mylog(args...)                 /* GNU convention for variable arguments */
 #else
-#define mylog                                  /* mylog */
-#endif
-#endif
+extern void MyLog(char *fmt,...);
+#define mylog  if (0) MyLog            /* mylog */
+#endif /* WIN32 */
+#endif /* MY_LOG */
+#define        inolog  mylog   /* for really temporary debug */
 
 #ifdef Q_LOG
 #define QLOGFILE                       "psqlodbc_"
@@ -64,6 +65,7 @@ extern void qlog(char *fmt,...);
 #define qlog                                   /* qlog */
 #endif
 #endif
+#define        inoqlog qlog
 
 #ifndef WIN32
 #define DIRSEPARATOR           "/"
index 362916d..9c8c7da 100644 (file)
@@ -59,7 +59,7 @@ pg_CS CS_Table[] =
        { "OTHER", OTHER }
 };
 
-int
+static int
 pg_ismb(int characterset_code)
 {
        int i=0,MB_CHARACTERSET[]={EUC_JP,EUC_CN,EUC_KR,EUC_TW,UTF8,MULE_INTERNAL,SJIS,BIG5,GBK,UHC,JOHAB};
@@ -228,8 +228,8 @@ pg_CS_stat(int stat,unsigned int character,int characterset_code)
                                        character > 0xa0)
                                        stat = 3;
                                else if (stat == 3 ||
-                                       (stat < 2 &&
-                                       character > 0xa0))
+                                       stat < 2 &&
+                                       character > 0xa0)
                                        stat = 2;
                                else if (stat == 2)
                                        stat = 1;
index 8c9b4cc..47a57b0 100644 (file)
@@ -86,7 +86,4 @@ void encoded_str_constr(encoded_str *encstr, int ccsc, const char *str);
 #define make_encoded_str(encstr, conn, str) encoded_str_constr(encstr, conn->ccsc, str)
 extern int encoded_nextchar(encoded_str *encstr);
 extern int encoded_byte_check(encoded_str *encstr, int abspos);
-
-/* This doesn't seem to be called by anyone, bjm 2002-03-24 */
-extern int pg_ismb(int characterset_code);
 #define check_client_encoding(X) pg_CS_name(pg_CS_code(X))
index cbb31da..d116d00 100644 (file)
@@ -204,8 +204,9 @@ SQLFetch(HSTMT StatementHandle)
 
        if (conn->driver_version >= 0x0300)
        {
-               SQLUSMALLINT *rowStatusArray = stmt->options.rowStatusArray;
-               SQLINTEGER *pcRow = stmt->options.rowsFetched;
+               IRDFields       *irdopts = SC_get_IRD(stmt);
+               SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray;
+               SQLINTEGER *pcRow = irdopts->rowsFetched;
 
                mylog("[[%s]]", func);
                return PGAPI_ExtendedFetch(StatementHandle, SQL_FETCH_NEXT, 0,
index c4efdd5..0e9b63a 100644 (file)
@@ -155,8 +155,9 @@ SQLFetchScroll(HSTMT StatementHandle,
        static char *func = "SQLFetchScroll";
        StatementClass *stmt = (StatementClass *) StatementHandle;
        RETCODE         ret;
-       SQLUSMALLINT *rowStatusArray = stmt->options.rowStatusArray;
-       SQLINTEGER *pcRow = stmt->options.rowsFetched;
+       IRDFields       *irdopts = SC_get_IRD(stmt);
+       SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray;
+       SQLINTEGER *pcRow = irdopts->rowsFetched;
 
        mylog("[[%s]] %d,%d\n", func, FetchOrientation, FetchOffset);
        if (FetchOrientation == SQL_FETCH_BOOKMARK)
@@ -208,8 +209,8 @@ SQLGetDescField(SQLHDESC DescriptorHandle,
                                SQLINTEGER *StringLength)
 {
        mylog("[[SQLGetDescField]]\n");
-       mylog("Error not implemented\n");
-       return SQL_ERROR;
+       return PGAPI_GetDescField(DescriptorHandle, RecNumber, FieldIdentifier,
+                       Value, BufferLength, StringLength);
 }
 
 /*     new function */
@@ -233,7 +234,7 @@ SQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
                                PTR DiagInfo, SQLSMALLINT BufferLength,
                                SQLSMALLINT *StringLength)
 {
-       mylog("[[SQLGetDiagField]]\n");
+       mylog("[[SQLGetDiagField]] Handle=(%u,%x) Rec=%d Id=%d\n", HandleType, Handle, RecNumber, DiagIdentifier);
        return SQL_ERROR;
 }
 
@@ -285,21 +286,9 @@ SQLGetConnectAttr(HDBC ConnectionHandle,
                                  SQLINTEGER Attribute, PTR Value,
                                  SQLINTEGER BufferLength, SQLINTEGER *StringLength)
 {
-       ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
-
        mylog("[[SQLGetConnectAttr]] %d\n", Attribute);
-       switch (Attribute)
-       {
-               case SQL_ATTR_ASYNC_ENABLE:
-               case SQL_ATTR_AUTO_IPD:
-               case SQL_ATTR_CONNECTION_DEAD:
-               case SQL_ATTR_CONNECTION_TIMEOUT:
-               case SQL_ATTR_METADATA_ID:
-                       conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
-                       conn->errormsg = "Unsupported connection option (Set)";
-                       return SQL_ERROR;
-       }
-       return PGAPI_GetConnectOption(ConnectionHandle, (UWORD) Attribute, Value);
+       return PGAPI_GetConnectAttr(ConnectionHandle, Attribute,Value,
+                       BufferLength, StringLength);
 }
 
 /*     SQLGetStmtOption -> SQLGetStmtAttr */
@@ -309,91 +298,10 @@ SQLGetStmtAttr(HSTMT StatementHandle,
                           SQLINTEGER BufferLength, SQLINTEGER *StringLength)
 {
        static char *func = "SQLGetStmtAttr";
-       StatementClass *stmt = (StatementClass *) StatementHandle;
-       RETCODE         ret = SQL_SUCCESS;
-       int                     len = 0;
 
        mylog("[[%s]] Handle=%u %d\n", func, StatementHandle, Attribute);
-       switch (Attribute)
-       {
-               case SQL_ATTR_FETCH_BOOKMARK_PTR:               /* 16 */
-                       Value = stmt->options.bookmark_ptr;
-                       len = 4;
-                       break;
-               case SQL_ATTR_PARAM_BIND_OFFSET_PTR:    /* 17 */
-                       Value = stmt->options.param_offset_ptr;
-                       len = 4;
-                       break;
-               case SQL_ATTR_PARAM_BIND_TYPE:  /* 18 */
-                       *((SQLUINTEGER *) Value) = stmt->options.param_bind_type;
-                       len = 4;
-                       break;
-               case SQL_ATTR_PARAM_OPERATION_PTR:              /* 19 */
-                       Value = stmt->options.param_operation_ptr;
-                       len = 4;
-                       break;
-               case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
-                       Value = stmt->options.param_status_ptr;
-                       len = 4;
-                       break;
-               case SQL_ATTR_PARAMS_PROCESSED_PTR:             /* 21 */
-                       Value = stmt->options.param_processed_ptr;
-                       len = 4;
-                       break;
-               case SQL_ATTR_PARAMSET_SIZE:    /* 22 */
-                       *((SQLUINTEGER *) Value) = stmt->options.paramset_size;
-                       len = 4;
-                       break;
-               case SQL_ATTR_ROW_BIND_OFFSET_PTR:              /* 23 */
-                       Value = stmt->options.row_offset_ptr;
-                       len = 4;
-                       break;
-               case SQL_ATTR_ROW_OPERATION_PTR:                /* 24 */
-                       Value = stmt->options.row_operation_ptr;
-                       len = 4;
-                       break;
-               case SQL_ATTR_ROW_STATUS_PTR:   /* 25 */
-                       Value = stmt->options.rowStatusArray;
-                       len = 4;
-                       break;
-               case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
-                       Value = stmt->options.rowsFetched;
-                       len = 4;
-                       break;
-               case SQL_ATTR_ROW_ARRAY_SIZE:   /* 27 */
-                       *((SQLUINTEGER *) Value) = stmt->options.rowset_size;
-                       len = 4;
-                       break;
-               case SQL_ATTR_APP_ROW_DESC:             /* 10010 */
-               case SQL_ATTR_APP_PARAM_DESC:   /* 10011 */
-               case SQL_ATTR_IMP_ROW_DESC:             /* 10012 */
-               case SQL_ATTR_IMP_PARAM_DESC:   /* 10013 */
-                       len = 4;
-                       *((HSTMT *) Value) = descHandleFromStatementHandle(StatementHandle, Attribute); 
-                       break;
-               case SQL_ATTR_AUTO_IPD: /* 10001 */
-                       /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
-
-               case SQL_ATTR_CURSOR_SCROLLABLE:                /* -1 */
-               case SQL_ATTR_CURSOR_SENSITIVITY:               /* -2 */
-               case SQL_ATTR_ENABLE_AUTO_IPD:  /* 15 */
-               case SQL_ATTR_METADATA_ID:              /* 10014 */
-
-                       /*
-                        * case SQL_ATTR_PREDICATE_PTR: case
-                        * SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR:
-                        */
-                       stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
-                       stmt->errormsg = "Unsupported statement option (Get)";
-                       SC_log_error(func, "", stmt);
-                       return SQL_ERROR;
-               default:
-                       len = 4;
-                       ret = PGAPI_GetStmtOption(StatementHandle, (UWORD) Attribute, Value);
-       }
-       if (ret == SQL_SUCCESS && StringLength)
-               *StringLength = len;
-       return ret;
+       return PGAPI_GetStmtAttr(StatementHandle, Attribute, Value,
+                       BufferLength, StringLength);
 }
 
 /*     SQLSetConnectOption -> SQLSetConnectAttr */
@@ -405,18 +313,8 @@ SQLSetConnectAttr(HDBC ConnectionHandle,
        ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
 
        mylog("[[SQLSetConnectAttr]] %d\n", Attribute);
-       switch (Attribute)
-       {
-               case SQL_ATTR_ASYNC_ENABLE:
-               case SQL_ATTR_AUTO_IPD:
-               case SQL_ATTR_CONNECTION_DEAD:
-               case SQL_ATTR_CONNECTION_TIMEOUT:
-               case SQL_ATTR_METADATA_ID:
-                       conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
-                       conn->errormsg = "Unsupported connection option (Set)";
-                       return SQL_ERROR;
-       }
-       return PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value);
+       return PGAPI_SetConnectAttr(ConnectionHandle, Attribute, Value,
+                                 StringLength);
 }
 
 /*     new function */
@@ -497,70 +395,7 @@ SQLSetStmtAttr(HSTMT StatementHandle,
        StatementClass *stmt = (StatementClass *) StatementHandle;
 
        mylog("[[%s]] Handle=%u %d,%u\n", func, StatementHandle, Attribute, Value);
-       switch (Attribute)
-       {
-               case SQL_ATTR_CURSOR_SCROLLABLE:                /* -1 */
-               case SQL_ATTR_CURSOR_SENSITIVITY:               /* -2 */
-
-               case SQL_ATTR_ENABLE_AUTO_IPD:  /* 15 */
-
-               case SQL_ATTR_APP_ROW_DESC:             /* 10010 */
-               case SQL_ATTR_APP_PARAM_DESC:   /* 10011 */
-               case SQL_ATTR_AUTO_IPD: /* 10001 */
-               /* 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) */
-               case SQL_ATTR_METADATA_ID:              /* 10014 */
-
-                       /*
-                        * case SQL_ATTR_PREDICATE_PTR: case
-                        * SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR:
-                        */
-                       stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
-                       stmt->errormsg = "Unsupported statement option (Set)";
-                       SC_log_error(func, "", stmt);
-                       return SQL_ERROR;
-
-               case SQL_ATTR_FETCH_BOOKMARK_PTR:               /* 16 */
-                       stmt->options.bookmark_ptr = Value;
-                       break;
-               case SQL_ATTR_PARAM_BIND_OFFSET_PTR:    /* 17 */
-                       stmt->options.param_offset_ptr = (SQLUINTEGER *) Value;
-                       break;
-               case SQL_ATTR_PARAM_BIND_TYPE:  /* 18 */
-                       stmt->options.param_bind_type = (SQLUINTEGER) Value;
-                       break;
-               case SQL_ATTR_PARAM_OPERATION_PTR:              /* 19 */
-                       stmt->options.param_operation_ptr = Value;
-                       break;
-               case SQL_ATTR_PARAM_STATUS_PTR:                 /* 20 */
-                       stmt->options.param_status_ptr = (SQLUSMALLINT *) Value;
-                       break;
-               case SQL_ATTR_PARAMS_PROCESSED_PTR:             /* 21 */
-                       stmt->options.param_processed_ptr = (SQLUINTEGER *) Value;
-                       break;
-               case SQL_ATTR_PARAMSET_SIZE:    /* 22 */
-                       stmt->options.paramset_size = (SQLUINTEGER) Value;
-                       break;
-               case SQL_ATTR_ROW_BIND_OFFSET_PTR:              /* 23 */
-                       stmt->options.row_offset_ptr = (SQLUINTEGER *) Value;
-                       break;
-               case SQL_ATTR_ROW_OPERATION_PTR:                /* 24 */
-                       stmt->options.row_operation_ptr = Value;
-                       break;
-               case SQL_ATTR_ROW_STATUS_PTR:   /* 25 */
-                       stmt->options.rowStatusArray = (SQLUSMALLINT *) Value;
-                       break;
-               case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
-                       stmt->options.rowsFetched = (SQLUINTEGER *) Value;
-                       break;
-               case SQL_ATTR_ROW_ARRAY_SIZE:   /* 27 */
-                       stmt->options.rowset_size = (SQLUINTEGER) Value;
-                       break;
-               default:
-                       return PGAPI_SetStmtOption(StatementHandle, (UWORD) Attribute, (UDWORD) Value);
-       }
-       return SQL_SUCCESS;
+       return PGAPI_SetStmtAttr(StatementHandle, Attribute, Value, StringLength);
 }
 
 #define SQL_FUNC_ESET(pfExists, uwAPI) \
@@ -630,8 +465,9 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
        if (ci->drivers.lie)
                SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLUMNPRIVILEGES); /* 56 not implemented yet */ 
        SQL_FUNC_ESET(pfExists, SQL_API_SQLDATASOURCES);        /* 57 */
-       SQL_FUNC_ESET(pfExists, SQL_API_SQLDESCRIBEPARAM);      /* 58 */
-       /* SQL_FUNC_ESET(pfExists, SQL_API_SQLEXTENDEDFETCH); 59 deprecated */
+       if (ci->drivers.lie)
+               SQL_FUNC_ESET(pfExists, SQL_API_SQLDESCRIBEPARAM); /* 58 not properly implemented */
+       SQL_FUNC_ESET(pfExists, SQL_API_SQLEXTENDEDFETCH); /* 59 deprecated ? */
 
        /*
         * for (++i; i < SQL_API_SQLBINDPARAMETER; i++)
@@ -678,8 +514,75 @@ 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->drivers.lie)
-               SQL_FUNC_ESET(pfExists, SQL_API_SQLBULKOPERATIONS); /* 24 not implemented yet */
+       if (ci->updatable_cursors)
+               SQL_FUNC_ESET(pfExists, SQL_API_SQLBULKOPERATIONS);     /* 24 */
 
        return SQL_SUCCESS;
 }
+
+RETCODE        SQL_API
+SQLBulkOperations(HSTMT hstmt, SQLSMALLINT operation)
+{
+       static char     *func = "SQLBulkOperations";
+       StatementClass  *stmt = (StatementClass *) hstmt;
+       ARDFields       *opts = SC_get_ARD(stmt);
+       RETCODE         ret;
+       UInt4           offset, bind_size = opts->bind_size, *bmark;
+       int             i, processed;
+       ConnectionClass *conn;
+       BOOL            auto_commit_needed = FALSE;
+
+       mylog("[[%s]] operation = %d\n", func, operation);
+       offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
+       switch (operation)
+       {
+               case SQL_ADD:
+                       ret = PGAPI_SetPos(hstmt, 0, operation, SQL_LOCK_NO_CHANGE);
+                       break;
+               default:
+                       if (SQL_FETCH_BY_BOOKMARK != operation)
+                       {
+                               conn = SC_get_conn(stmt);
+                               if (auto_commit_needed = CC_is_in_autocommit(conn), auto_commit_needed)
+                                       PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT,
+SQL_AUTOCOMMIT_OFF);
+                       }
+                       if (bmark = (UInt4 *) opts->bookmark->buffer, !bmark)
+                       {
+                               stmt->errormsg = "bookmark isn't specified";
+                               return SQL_ERROR;
+                       }
+                       bmark += (offset >> 4);
+                       for (i = 0, processed = 0; i < opts->rowset_size; i++)
+                       {
+                               if (!opts->row_operation_ptr || SQL_ROW_PROCEED == opts->row_operation_ptr[i])
+                               {
+                                       switch (operation)
+                                       {
+                                               case SQL_UPDATE_BY_BOOKMARK:
+                                                       ret = SC_pos_update(stmt, (UWORD) i, *bmark);
+                                                       break;
+                                               case SQL_DELETE_BY_BOOKMARK:
+                                                       ret = SC_pos_delete(stmt, (UWORD) i, *bmark);
+                                                       break;
+                                               case SQL_FETCH_BY_BOOKMARK:
+                                                       ret = SC_pos_refresh(stmt, (UWORD) i, *bmark);
+                                                       break;
+                                       }
+                                       processed++;
+                                       if (SQL_ERROR == ret)
+                                               break;
+                                       if (bind_size > 0)
+                                               bmark += (bind_size >> 2);
+                                       else
+                                               bmark++; 
+                               }
+                       }
+                       if (auto_commit_needed)
+                               PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
+                       if (SC_get_IRD(stmt)->rowsFetched)
+                               *SC_get_IRD(stmt)->rowsFetched = processed;
+                       break;
+       }
+       return ret;
+}      
index 3523720..0273f97 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Classes:                    n/a
  *
- * API functions:      SQLColAttributeW, SQLGetStmtW, SQLSetStmtW,
+ * API functions:      SQLColAttributeW, SQLGetStmtAttrW, SQLSetStmtAttrW,
                        SQLSetConnectAttrW, SQLGetConnectAttrW,
                        SQLGetDescFieldW, SQLGetDescRecW, SQLGetDiagFieldW,
                        SQLGetDiagRecW,
@@ -75,6 +75,48 @@ RETCODE SQL_API      SQLSetConnectAttrW(HDBC hdbc,
        return ret;
 }
 
+/*      new function */
+RETCODE  SQL_API
+SQLSetDescFieldW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber,
+                               SQLSMALLINT FieldIdentifier, PTR Value, 
+                               SQLINTEGER BufferLength)
+{
+       RETCODE ret;
+       UInt4   vallen;
+        char    *uval = NULL;
+       BOOL    val_alloced = FALSE;
+
+       mylog("[SQLSetDescFieldW]");
+       if (BufferLength > 0)
+       {
+               uval = ucs2_to_utf8(Value, BufferLength / 2, &vallen);
+               val_alloced = TRUE;
+       }
+       else
+       {
+               uval = Value;
+               vallen = BufferLength;
+       }
+       ret = PGAPI_SetDescField(DescriptorHandle, RecNumber, FieldIdentifier,
+                               uval, vallen);
+       if (val_alloced)
+               free(uval);
+       return ret;
+}
+RETCODE SQL_API
+SQLGetDescFieldW(SQLHDESC hdesc, SQLSMALLINT iRecord, SQLSMALLINT iField,
+                               PTR rgbValue, SQLINTEGER cbValueMax,
+                               SQLINTEGER *pcbValue)
+{
+       RETCODE ret;
+        char    *qstr = NULL, *mtxt = NULL;
+
+       mylog("[SQLGetDescFieldW]");
+       ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbValue,
+                               cbValueMax, pcbValue);
+       return ret;
+}
+
 RETCODE SQL_API        SQLGetDiagRecW(SWORD fHandleType,
                SQLHANDLE       handle,
                SQLSMALLINT     iRecord,
@@ -131,7 +173,25 @@ RETCODE SQL_API SQLColAttributeW(
        RETCODE ret;
 
        mylog("[SQLColAttributeW]");
+       switch (fDescType)
+       { 
+               case SQL_DESC_BASE_COLUMN_NAME:
+               case SQL_DESC_BASE_TABLE_NAME:
+               case SQL_DESC_CATALOG_NAME:
+               case SQL_DESC_LABEL:
+               case SQL_DESC_LITERAL_PREFIX:
+               case SQL_DESC_LITERAL_SUFFIX:
+               case SQL_DESC_LOCAL_TYPE_NAME:
+               case SQL_DESC_NAME:
+               case SQL_DESC_SCHEMA_NAME:
+               case SQL_DESC_TABLE_NAME:
+               case SQL_DESC_TYPE_NAME:
+               case SQL_COLUMN_NAME:
+                       break;
+       }
+
        ret = PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc,
                cbDescMax, pcbDesc, pfDesc);
+
        return ret;
 }
index ea11fae..d560ff4 100644 (file)
@@ -53,9 +53,9 @@ set_statement_option(ConnectionClass *conn,
                case SQL_BIND_TYPE:
                        /* now support multi-column and multi-row binding */
                        if (conn)
-                               conn->stmtOptions.bind_size = vParam;
+                               conn->ardOptions.bind_size = vParam;
                        if (stmt)
-                               stmt->options.bind_size = vParam;
+                               SC_get_ARD(stmt)->bind_size = vParam;
                        break;
 
                case SQL_CONCURRENCY:
@@ -173,7 +173,7 @@ set_statement_option(ConnectionClass *conn,
                         */
 
                        if (stmt && stmt->save_rowset_size <= 0 && stmt->last_fetch_count > 0)
-                               stmt->save_rowset_size = stmt->options.rowset_size;
+                               stmt->save_rowset_size = SC_get_ARD(stmt)->rowset_size;
 
                        if (vParam < 1)
                        {
@@ -182,9 +182,9 @@ set_statement_option(ConnectionClass *conn,
                        }
 
                        if (conn)
-                               conn->stmtOptions.rowset_size = vParam;
+                               conn->ardOptions.rowset_size = vParam;
                        if (stmt)
-                               stmt->options.rowset_size = vParam;
+                               SC_get_ARD(stmt)->rowset_size = vParam;
                        break;
 
                case SQL_SIMULATE_CURSOR:               /* NOT SUPPORTED */
@@ -590,16 +590,16 @@ PGAPI_GetStmtOption(
                        break;
 
                case SQL_BIND_TYPE:
-                       *((SDWORD *) pvParam) = stmt->options.bind_size;
+                       *((SDWORD *) pvParam) = SC_get_ARD(stmt)->bind_size;
                        break;
 
                case SQL_CONCURRENCY:   /* NOT REALLY SUPPORTED */
-                       mylog("GetStmtOption(): SQL_CONCURRENCY\n");
+                       mylog("GetStmtOption(): SQL_CONCURRENCY %d\n", stmt->options.scroll_concurrency);
                        *((SDWORD *) pvParam) = stmt->options.scroll_concurrency;
                        break;
 
                case SQL_CURSOR_TYPE:   /* PARTIAL SUPPORT */
-                       mylog("GetStmtOption(): SQL_CURSOR_TYPE\n");
+                       mylog("GetStmtOption(): SQL_CURSOR_TYPE %d\n", stmt->options.cursor_type);
                        *((SDWORD *) pvParam) = stmt->options.cursor_type;
                        break;
 
@@ -630,7 +630,7 @@ PGAPI_GetStmtOption(
                        break;
 
                case SQL_ROWSET_SIZE:
-                       *((SDWORD *) pvParam) = stmt->options.rowset_size;
+                       *((SDWORD *) pvParam) = SC_get_ARD(stmt)->rowset_size;
                        break;
 
                case SQL_SIMULATE_CURSOR:               /* NOT SUPPORTED */
index 8a7e6d7..3549ff2 100644 (file)
@@ -236,19 +236,25 @@ void
 getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
 {
        char       *str;
+       Int2    reserved_cols;
 
+#if (ODBCVER >= 0x0300)
+       reserved_cols = 18;
+#else
+       reserved_cols = 12;
+#endif /* ODBCVER */
        if (fi->name[0] == '\0')
                strcpy(fi->name, QR_get_value_manual(col_info->result, k, 3));
 
-       fi->type = atoi(QR_get_value_manual(col_info->result, k, 13));
-       fi->precision = atoi(QR_get_value_manual(col_info->result, k, 6));
+       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->scale = atoi(str);
+               fi->decimal_digits = atoi(str);
        else
-               fi->scale = -1;
+               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, 12));
+       fi->display_size = atoi(QR_get_value_manual(col_info->result, k, reserved_cols));
 }
 
 
@@ -315,16 +321,17 @@ parse_statement(StatementClass *stmt)
        ConnectionClass *conn = stmt->hdbc;
        HSTMT           hcol_stmt;
        StatementClass *col_stmt;
+       IRDFields       *irdflds = SC_get_IRD(stmt);
        RETCODE         result;
        BOOL            updatable = TRUE;
 
        mylog("%s: entering...\n", func);
 
        ptr = stmt->statement;
-       fi = stmt->fi;
+       fi = irdflds->fi;
        ti = stmt->ti;
 
-       stmt->nfld = 0;
+       irdflds->nfields = 0;
        stmt->ntab = 0;
        stmt->from_pos = -1;
        stmt->where_pos = -1;
@@ -371,7 +378,7 @@ parse_statement(StatementClass *stmt)
                                mylog("FROM\n");
                                continue;
                        }
-               }
+               } /* in_select && unquoted && blevel == 0 */
                if (unquoted && blevel == 0)
                {
                        if ((!stricmp(token, "where") ||
@@ -386,18 +393,18 @@ parse_statement(StatementClass *stmt)
                                in_from = FALSE;
                                in_where = TRUE;
 
-                               if (!stricmp(token, "where"))
+                               if (stmt->where_pos < 0)
+                                       stmt->where_pos = pptr - stmt->statement;
+                               mylog("%s...\n", token);
+                               if (stricmp(token, "where") &&
+                                   stricmp(token, "order"))
                                {
-                                       if (stmt->where_pos < 0)
-                                               stmt->where_pos = pptr - stmt->statement;
-                               }
-                               else if (stricmp(token, "order"))
                                        updatable = FALSE;
-
-                               mylog("WHERE...\n");
-                               break;
+                                       break;
+                               }
+                               continue;
                        }
-               }
+               } /* unquoted && blevel == 0 */
                if (in_select && (in_expr || in_func))
                {
                        /* just eat the expression */
@@ -435,7 +442,7 @@ parse_statement(StatementClass *stmt)
                                }
                        }
                        continue;
-               }
+               } /* in_select && (in_expr || in_func) */
 
                if (unquoted && !stricmp(token, "select"))
                {
@@ -464,81 +471,81 @@ parse_statement(StatementClass *stmt)
                                }
                                mylog("done distinct\n");
                                in_distinct = FALSE;
-                       }
+                       } /* in_distinct */
 
                        if (!in_field)
                        {
                                if (!token[0])
                                        continue;
 
-                               if (!(stmt->nfld % FLD_INCR))
+                               if (!(irdflds->nfields % FLD_INCR))
                                {
-                                       mylog("reallocing at nfld=%d\n", stmt->nfld);
-                                       fi = (FIELD_INFO **) realloc(fi, (stmt->nfld + FLD_INCR) * sizeof(FIELD_INFO *));
+                                       mylog("reallocing at nfld=%d\n", irdflds->nfields);
+                                       fi = (FIELD_INFO **) realloc(fi, (irdflds->nfields + FLD_INCR) * sizeof(FIELD_INFO *));
                                        if (!fi)
                                        {
                                                stmt->parse_status = STMT_PARSE_FATAL;
                                                return FALSE;
                                        }
-                                       stmt->fi = fi;
+                                       irdflds->fi = fi;
                                }
 
-                               fi[stmt->nfld] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
-                               if (fi[stmt->nfld] == NULL)
+                               fi[irdflds->nfields] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
+                               if (fi[irdflds->nfields] == NULL)
                                {
                                        stmt->parse_status = STMT_PARSE_FATAL;
                                        return FALSE;
                                }
 
                                /* Initialize the field info */
-                               memset(fi[stmt->nfld], 0, sizeof(FIELD_INFO));
+                               memset(fi[irdflds->nfields], 0, sizeof(FIELD_INFO));
 
                                /* double quotes are for qualifiers */
                                if (dquote)
-                                       fi[stmt->nfld]->dquote = TRUE;
+                                       fi[irdflds->nfields]->dquote = TRUE;
 
                                if (quote)
                                {
-                                       fi[stmt->nfld]->quote = TRUE;
-                                       fi[stmt->nfld]->precision = strlen(token);
+                                       fi[irdflds->nfields]->quote = TRUE;
+                                       fi[irdflds->nfields]->column_size = strlen(token);
                                }
                                else if (numeric)
                                {
-                                       mylog("**** got numeric: nfld = %d\n", stmt->nfld);
-                                       fi[stmt->nfld]->numeric = TRUE;
+                                       mylog("**** got numeric: nfld = %d\n", irdflds->nfields);
+                                       fi[irdflds->nfields]->numeric = TRUE;
                                }
                                else if (token[0] == '(')
                                {                               /* expression */
                                        mylog("got EXPRESSION\n");
-                                       fi[stmt->nfld++]->expr = TRUE;
+                                       fi[irdflds->nfields++]->expr = TRUE;
                                        in_expr = TRUE;
                                        blevel = 1;
                                        continue;
                                }
                                else
                                {
-                                       strcpy(fi[stmt->nfld]->name, token);
-                                       fi[stmt->nfld]->dot[0] = '\0';
+                                       strcpy(fi[irdflds->nfields]->name, token);
+                                       fi[irdflds->nfields]->dot[0] = '\0';
                                }
-                               mylog("got field='%s', dot='%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->dot);
+                               mylog("got field='%s', dot='%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->dot);
 
                                if (delim == ',')
                                        mylog("comma (1)\n");
                                else
                                        in_field = TRUE;
-                               stmt->nfld++;
+                               irdflds->nfields++;
                                continue;
-                       }
+                       } /* !in_field */
 
                        /*
                         * We are in a field now
                         */
                        if (in_dot)
                        {
-                               stmt->nfld--;
-                               strcpy(fi[stmt->nfld]->dot, fi[stmt->nfld]->name);
-                               strcpy(fi[stmt->nfld]->name, token);
-                               stmt->nfld++;
+                               irdflds->nfields--;
+                               strcpy(fi[irdflds->nfields]->dot, fi[irdflds->nfields]->name);
+                               strcpy(fi[irdflds->nfields]->name, token);
+                               irdflds->nfields++;
                                in_dot = FALSE;
 
                                if (delim == ',')
@@ -551,13 +558,13 @@ parse_statement(StatementClass *stmt)
 
                        if (in_as)
                        {
-                               stmt->nfld--;
-                               strcpy(fi[stmt->nfld]->alias, token);
-                               mylog("alias for field '%s' is '%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->alias);
+                               irdflds->nfields--;
+                               strcpy(fi[irdflds->nfields]->alias, token);
+                               mylog("alias for field '%s' is '%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->alias);
                                in_as = FALSE;
                                in_field = FALSE;
 
-                               stmt->nfld++;
+                               irdflds->nfields++;
 
                                if (delim == ',')
                                        mylog("comma(2)\n");
@@ -569,13 +576,13 @@ parse_statement(StatementClass *stmt)
                        {
                                in_func = TRUE;
                                blevel = 1;
-                               fi[stmt->nfld - 1]->func = TRUE;
+                               fi[irdflds->nfields - 1]->func = TRUE;
 
                                /*
                                 * name will have the function name -- maybe useful some
                                 * day
                                 */
-                               mylog("**** got function = '%s'\n", fi[stmt->nfld - 1]->name);
+                               mylog("**** got function = '%s'\n", fi[irdflds->nfields - 1]->name);
                                continue;
                        }
 
@@ -595,11 +602,11 @@ parse_statement(StatementClass *stmt)
 
                        /* otherwise, it's probably an expression */
                        in_expr = TRUE;
-                       fi[stmt->nfld - 1]->expr = TRUE;
-                       fi[stmt->nfld - 1]->name[0] = '\0';
-                       fi[stmt->nfld - 1]->precision = 0;
+                       fi[irdflds->nfields - 1]->expr = TRUE;
+                       fi[irdflds->nfields - 1]->name[0] = '\0';
+                       fi[irdflds->nfields - 1]->column_size = 0;
                        mylog("*** setting expression\n");
-               }
+               } /* in_select end */
 
                if (in_from)
                {
@@ -607,6 +614,8 @@ parse_statement(StatementClass *stmt)
                        {
                                if (!token[0])
                                        continue;
+                               if (token[0] == ';')
+                                       break;
 
                                if (!(stmt->ntab % TAB_INCR))
                                {
@@ -658,12 +667,17 @@ 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);
-                       in_table = FALSE;
-                       if (delim == ',')
-                               mylog("more than 1 tables\n");
-               }
+                       if (token[0] == ';')
+                               break;
+                       if (stricmp(token, "as"))
+                       {
+                               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);
+                               in_table = FALSE;
+                               if (delim == ',')
+                                       mylog("more than 1 tables\n");
+                       }
+               } /* in_from */
        }
 
        /*
@@ -673,7 +687,7 @@ parse_statement(StatementClass *stmt)
        parse = TRUE;
 
        /* Resolve field names with tables */
-       for (i = 0; i < stmt->nfld; i++)
+       for (i = 0; i < (int) irdflds->nfields; i++)
        {
                if (fi[i]->func || fi[i]->expr || fi[i]->numeric)
                {
@@ -687,16 +701,16 @@ parse_statement(StatementClass *stmt)
                        fi[i]->ti = NULL;
 
                        /*
-                        * fi[i]->type = PG_TYPE_TEXT; fi[i]->precision = 0; the
+                        * fi[i]->type = PG_TYPE_TEXT; fi[i]->column_size = 0; the
                         * following may be better
                         */
                        fi[i]->type = PG_TYPE_UNKNOWN;
-                       if (fi[i]->precision == 0)
+                       if (fi[i]->column_size == 0)
                        {
                                fi[i]->type = PG_TYPE_VARCHAR;
-                               fi[i]->precision = 254;
+                               fi[i]->column_size = 254;
                        }
-                       fi[i]->length = fi[i]->precision;
+                       fi[i]->length = fi[i]->column_size;
                        continue;
                }
                /* it's a dot, resolve to table or alias */
@@ -721,9 +735,9 @@ parse_statement(StatementClass *stmt)
        }
 
        mylog("--------------------------------------------\n");
-       mylog("nfld=%d, ntab=%d\n", stmt->nfld, stmt->ntab);
+       mylog("nfld=%d, ntab=%d\n", irdflds->nfields, stmt->ntab);
 
-       for (i = 0; i < stmt->nfld; i++)
+       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)
@@ -836,7 +850,7 @@ parse_statement(StatementClass *stmt)
        /*
         * Now resolve the fields to point to column info
         */
-       for (i = 0; i < stmt->nfld;)
+       for (i = 0; i < (int) irdflds->nfields;)
        {
                fi[i]->updatable = updatable;
                /* Dont worry about functions or quotes */
@@ -875,8 +889,8 @@ parse_statement(StatementClass *stmt)
                        increased_cols = total_cols - 1;
 
                        /* Allocate some more field pointers if necessary */
-                       old_alloc = ((stmt->nfld - 1) / FLD_INCR + 1) * FLD_INCR;
-                       new_size = stmt->nfld + increased_cols;
+                       old_alloc = ((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);
 
@@ -891,14 +905,14 @@ parse_statement(StatementClass *stmt)
                                        stmt->parse_status = STMT_PARSE_FATAL;
                                        return FALSE;
                                }
-                               stmt->fi = fi;
+                               irdflds->fi = fi;
                        }
 
                        /*
                         * copy any other fields (if there are any) up past the
                         * expansion
                         */
-                       for (j = stmt->nfld - 1; j > i; j--)
+                       for (j = irdflds->nfields - 1; j > i; j--)
                        {
                                mylog("copying field %d to %d\n", j, increased_cols + j);
                                fi[increased_cols + j] = fi[j];
@@ -906,8 +920,8 @@ parse_statement(StatementClass *stmt)
                        mylog("done copying fields\n");
 
                        /* Set the new number of fields */
-                       stmt->nfld += increased_cols;
-                       mylog("stmt->nfld now at %d\n", stmt->nfld);
+                       irdflds->nfields += increased_cols;
+                       mylog("irdflds->nfields now at %d\n", irdflds->nfields);
 
 
                        /* copy the new field info */
@@ -990,6 +1004,7 @@ parse_statement(StatementClass *stmt)
        else
                stmt->parse_status = STMT_PARSE_COMPLETE;
 
+       stmt->updatable = updatable;
        mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, stmt->parse_status);
        return parse;
 }
index 6e4c575..a67cc43 100644 (file)
 #include "environ.h"
 #include "connection.h"
 #include "statement.h"
+#include "descriptor.h"
 #include "pgapifunc.h"
 
+static HSTMT statementHandleFromDescHandle(HSTMT, SQLINTEGER *descType); 
 /*     SQLError -> SQLDiagRec */
 RETCODE                SQL_API
 PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
@@ -54,6 +56,12 @@ PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
                                        NativeError, MessageText, BufferLength,
                                        TextLength, 0);
                        break;
+               case SQL_HANDLE_DESC:
+                       ret = PGAPI_StmtError(statementHandleFromDescHandle(Handle, NULL),
+                                       RecNumber, Sqlstate, NativeError,
+                                       MessageText, BufferLength,
+                                       TextLength, 0);
+                       break;
                default:
                        ret = SQL_ERROR;
        }
@@ -131,21 +139,37 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
                        SQLINTEGER Attribute, PTR Value,
                        SQLINTEGER BufferLength, SQLINTEGER *StringLength)
 {
+       static const char *func = "PGAPI_GetConnectAttr";
        ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
+       RETCODE ret = SQL_SUCCESS;
+       SQLINTEGER      len = 4;
 
        mylog("PGAPI_GetConnectAttr %d\n", Attribute);
        switch (Attribute)
        {
                case SQL_ATTR_ASYNC_ENABLE:
+                       *((SQLUINTEGER *) Value) = SQL_ASYNC_ENABLE_OFF;
+                       break;
                case SQL_ATTR_AUTO_IPD:
+                       *((SQLUINTEGER *) Value) = SQL_FALSE;
+                       break;
                case SQL_ATTR_CONNECTION_DEAD:
+                       *((SQLUINTEGER *) Value) = SQL_CD_FALSE;
+                       break;
                case SQL_ATTR_CONNECTION_TIMEOUT:
+                       *((SQLUINTEGER *) Value) = 0;
+                       break;
                case SQL_ATTR_METADATA_ID:
                        conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
                        conn->errormsg = "Unsupported connect attribute (Get)";
+                       CC_log_error(func, "", conn);
                        return SQL_ERROR;
+               default:
+                       ret = PGAPI_GetConnectOption(ConnectionHandle, (UWORD) Attribute, Value);
        }
-       return PGAPI_GetConnectOption(ConnectionHandle, (UWORD) Attribute, Value);
+       if (StringLength)
+               *StringLength = len;
+       return ret;
 }
 
 static HSTMT
@@ -168,113 +192,263 @@ static HSTMT
 statementHandleFromDescHandle(HSTMT DescHandle, SQLINTEGER *descType) 
 {
        SQLUINTEGER res = (SQLUINTEGER) DescHandle % 4;
-       switch (res)
+       if (descType)
        {
-               case 0: *descType = SQL_ATTR_APP_ROW_DESC; /* 10010 */
-                       break;
-               case 1: *descType = SQL_ATTR_APP_PARAM_DESC; /* 10011 */
-                       break;
-               case 2: *descType = SQL_ATTR_IMP_ROW_DESC; /* 10012 */
-                       break;
-               case 3: *descType = SQL_ATTR_IMP_PARAM_DESC; /* 10013 */
-                       break;
+               switch (res)
+               {
+                       case 0: *descType = SQL_ATTR_APP_ROW_DESC; /* 10010 */
+                               break;
+                       case 1: *descType = SQL_ATTR_APP_PARAM_DESC; /* 10011 */
+                               break;
+                       case 2: *descType = SQL_ATTR_IMP_ROW_DESC; /* 10012 */
+                               break;
+                       case 3: *descType = SQL_ATTR_IMP_PARAM_DESC; /* 10013 */
+                               break;
+               }
        }
        return (HSTMT) ((SQLUINTEGER) DescHandle - res);
 }
 
+static  void column_bindings_set(ARDFields *opts, int cols, BOOL maxset)
+{
+       int     i;
+
+       if (cols == opts->allocated)
+               return;
+       if (cols > opts->allocated)
+       {
+               extend_column_bindings(opts, cols);
+               return;
+       }
+       if (maxset)     return;
+
+       for (i = opts->allocated; i > cols; i--)
+               reset_a_column_binding(opts, i);
+       opts->allocated = cols;
+       if (0 == cols)
+       {
+               free(opts->bindings);
+               opts->bindings = NULL;
+       }
+}
+
 static RETCODE SQL_API
 ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
                SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
 {
        RETCODE         ret = SQL_SUCCESS;
        PTR             tptr;
+       ARDFields       *opts = SC_get_ARD(stmt);
        switch (FieldIdentifier)
        {
                case SQL_DESC_ARRAY_SIZE:
-                       stmt->options.rowset_size = (SQLUINTEGER) Value;
+                       opts->rowset_size = (SQLUINTEGER) Value;
                        break; 
                case SQL_DESC_ARRAY_STATUS_PTR:
-                       stmt->options.row_operation_ptr = Value;
+                       opts->row_operation_ptr = Value;
                        break;
                case SQL_DESC_BIND_OFFSET_PTR:
-                       stmt->options.row_offset_ptr = Value;
+                       opts->row_offset_ptr = Value;
                        break;
                case SQL_DESC_BIND_TYPE:
-                       stmt->options.bind_size = (SQLUINTEGER) Value;
+                       opts->bind_size = (SQLUINTEGER) Value;
                        break;
 
+               case SQL_DESC_TYPE:
+                       column_bindings_set(opts, RecNumber, TRUE);
+                       reset_a_column_binding(opts, RecNumber);
+                       opts->bindings[RecNumber - 1].returntype = (Int4) Value;
+                       break;
+               case SQL_DESC_DATETIME_INTERVAL_CODE:
+                       column_bindings_set(opts, RecNumber, TRUE);
+                       switch (opts->bindings[RecNumber - 1].returntype)
+                       {
+                               case SQL_DATETIME:
+                               case SQL_C_TYPE_DATE:
+                               case SQL_C_TYPE_TIME:
+                               case SQL_C_TYPE_TIMESTAMP:
+                               switch ((Int4) Value)
+                               {
+                                       case SQL_CODE_DATE:
+                                               opts->bindings[RecNumber - 1].returntype = SQL_C_TYPE_DATE;
+                                               break;
+                                       case SQL_CODE_TIME:
+                                               opts->bindings[RecNumber - 1].returntype = SQL_C_TYPE_TIME;
+                                               break;
+                                       case SQL_CODE_TIMESTAMP:
+                                               opts->bindings[RecNumber - 1].returntype = SQL_C_TYPE_TIMESTAMP;
+                                               break;
+                               }
+                               break;
+                       }
+                       break;
+               case SQL_DESC_CONCISE_TYPE:
+                       column_bindings_set(opts, RecNumber, TRUE);
+                       opts->bindings[RecNumber - 1].returntype = (Int4) Value;
+                       break;
                case SQL_DESC_DATA_PTR:
                        if (!RecNumber)
-                               stmt->bookmark.buffer = Value;
+                               opts->bookmark->buffer = Value;
                        else
-                               stmt->bindings[RecNumber - 1].buffer = Value;
+                       {
+                               column_bindings_set(opts, RecNumber, TRUE);
+                               opts->bindings[RecNumber - 1].buffer = Value;
+                       }
                        break;
                case SQL_DESC_INDICATOR_PTR:
                        if (!RecNumber)
-                               tptr = stmt->bookmark.used;
+                               tptr = opts->bookmark->used;
                        else
-                               tptr = stmt->bindings[RecNumber - 1].used;
+                       {
+                               column_bindings_set(opts, RecNumber, TRUE);
+                               tptr = opts->bindings[RecNumber - 1].used;
+                       }
                        if (Value != tptr)
                        {
                                ret = SQL_ERROR;
-                               stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+                               stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
                                stmt->errormsg = "INDICATOR != OCTET_LENGTH_PTR"; 
                        }
                        break;
                case SQL_DESC_OCTET_LENGTH_PTR:
                        if (!RecNumber)
-                               stmt->bookmark.used = Value;
+                               opts->bookmark->used = Value;
                        else
-                               stmt->bindings[RecNumber - 1].used = Value;
+                       {
+                               column_bindings_set(opts, RecNumber, TRUE);
+                               opts->bindings[RecNumber - 1].used = Value;
+                       }
+                       break;
+               case SQL_DESC_COUNT:
+                       column_bindings_set(opts, (SQLUINTEGER) Value, FALSE);
+                       break;
+               case SQL_DESC_OCTET_LENGTH:
+                       if (RecNumber)
+                       {
+                               column_bindings_set(opts, RecNumber, TRUE);
+                               opts->bindings[RecNumber - 1].buflen = (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:
+               case SQL_DESC_PRECISION:
+               case SQL_DESC_SCALE:
                default:ret = SQL_ERROR;
-                       stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
-                       stmt->errormsg = "not implemedted yet"; 
+                       stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
        }
        return ret;
 }
 
+static  void parameter_bindings_set(APDFields *opts, int params, BOOL maxset)
+{
+       int     i;
+
+       if (params == opts->allocated)
+               return;
+       if (params > opts->allocated)
+       {
+               extend_parameter_bindings(opts, params);
+               return;
+       }
+       if (maxset)     return;
+
+       for (i = opts->allocated; i > params; i--)
+               reset_a_parameter_binding(opts, i);
+       opts->allocated = params;
+       if (0 == params)
+       {
+               free(opts->parameters);
+               opts->parameters = NULL;
+       }
+}
+
 static RETCODE SQL_API
 APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
                SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
 {
        RETCODE         ret = SQL_SUCCESS;
+       APDFields       *opts = SC_get_APD(stmt);
        switch (FieldIdentifier)
        {
                case SQL_DESC_ARRAY_SIZE:
-                       stmt->options.paramset_size = (SQLUINTEGER) Value;
+                       opts->paramset_size = (SQLUINTEGER) Value;
                        break; 
                case SQL_DESC_ARRAY_STATUS_PTR:
-                       stmt->options.param_operation_ptr = Value;
+                       opts->param_operation_ptr = Value;
                        break;
                case SQL_DESC_BIND_OFFSET_PTR:
-                       stmt->options.param_offset_ptr = Value;
+                       opts->param_offset_ptr = Value;
                        break;
                case SQL_DESC_BIND_TYPE:
-                       stmt->options.param_bind_type = (SQLUINTEGER) Value;
+                       opts->param_bind_type = (SQLUINTEGER) Value;
                        break;
 
+               case SQL_DESC_TYPE:
+                       parameter_bindings_set(opts, RecNumber, TRUE);
+                       reset_a_parameter_binding(opts, RecNumber);
+                       opts->parameters[RecNumber - 1].CType = (Int4) Value;
+                       break;
+               case SQL_DESC_DATETIME_INTERVAL_CODE:
+                       parameter_bindings_set(opts, RecNumber, TRUE);
+                       switch (opts->parameters[RecNumber - 1].CType)
+                       {
+                               case SQL_DATETIME:
+                               case SQL_C_TYPE_DATE:
+                               case SQL_C_TYPE_TIME:
+                               case SQL_C_TYPE_TIMESTAMP:
+                               switch ((Int4) Value)
+                               {
+                                       case SQL_CODE_DATE:
+                                               opts->parameters[RecNumber - 1].CType = SQL_C_TYPE_DATE;
+                                               break;
+                                       case SQL_CODE_TIME:
+                                               opts->parameters[RecNumber - 1].CType = SQL_C_TYPE_TIME;
+                                               break;
+                                       case SQL_CODE_TIMESTAMP:
+                                               opts->parameters[RecNumber - 1].CType = SQL_C_TYPE_TIMESTAMP;
+                                               break;
+                               }
+                               break;
+                       }
+                       break;
+               case SQL_DESC_CONCISE_TYPE:
+                       parameter_bindings_set(opts, RecNumber, TRUE);
+                       opts->parameters[RecNumber - 1].CType = (Int4) Value;
+                       break;
                case SQL_DESC_DATA_PTR:
-                       if (stmt->parameters_allocated < RecNumber)
-                               PGAPI_BindParameter(stmt, RecNumber, 0, 0, 0, 0, 0, 0, 0, 0);
-                       stmt->parameters[RecNumber - 1].buffer = Value;
+                       parameter_bindings_set(opts, RecNumber, TRUE);
+                       opts->parameters[RecNumber - 1].buffer = Value;
                        break;
                case SQL_DESC_INDICATOR_PTR:
-                       if (stmt->parameters_allocated < RecNumber ||
-                           Value != stmt->parameters[RecNumber - 1].used)
+                       if (opts->allocated < RecNumber ||
+                           Value != opts->parameters[RecNumber - 1].used)
                        {
                                ret = SQL_ERROR;
-                               stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+                               stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
                                stmt->errormsg = "INDICATOR != OCTET_LENGTH_PTR"; 
                        }
                        break;
+               case SQL_DESC_OCTET_LENGTH:
+                       parameter_bindings_set(opts, RecNumber, TRUE);
+                       opts->parameters[RecNumber - 1].buflen = (Int4) Value;
+                       break;
                case SQL_DESC_OCTET_LENGTH_PTR:
-                       if (stmt->parameters_allocated < RecNumber)
-                               PGAPI_BindParameter(stmt, RecNumber, 0, 0, 0, 0, 0, 0, 0, 0);
-                       stmt->parameters[RecNumber - 1].used = Value;
+                       parameter_bindings_set(opts, RecNumber, TRUE);
+                       opts->parameters[RecNumber - 1].used = Value;
                        break;
+               case SQL_DESC_COUNT:
+                       parameter_bindings_set(opts, (SQLUINTEGER) Value, FALSE);
+                       break; 
+               case SQL_DESC_ALLOC_TYPE: /* read-only */
+               case SQL_DESC_DATETIME_INTERVAL_PRECISION:
+               case SQL_DESC_LENGTH:
+               case SQL_DESC_NUM_PREC_RADIX:
+               case SQL_DESC_PRECISION:
+               case SQL_DESC_SCALE:
                default:ret = SQL_ERROR;
-                       stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+                       stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
        }
        return ret;
 }
@@ -284,16 +458,51 @@ IRDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
                SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
 {
        RETCODE         ret = SQL_SUCCESS;
+       IRDFields       *opts = SC_get_IRD(stmt);
        switch (FieldIdentifier)
        {
                case SQL_DESC_ARRAY_STATUS_PTR:
-                       stmt->options.rowStatusArray = (SQLUSMALLINT *) Value;
+                       opts->rowStatusArray = (SQLUSMALLINT *) Value;
                        break;
                case SQL_DESC_ROWS_PROCESSED_PTR:
-                       stmt->options.rowsFetched = (SQLUINTEGER *) Value;
+                       opts->rowsFetched = (SQLUINTEGER *) Value;
                        break;
+               case SQL_DESC_ALLOC_TYPE: /* read-only */
+               case SQL_DESC_COUNT: /* read-only */
+               case SQL_DESC_AUTO_UNIQUE_VALUE: /* read-only */
+               case SQL_DESC_BASE_COLUMN_NAME: /* read-only */
+               case SQL_DESC_BASE_TABLE_NAME: /* read-only */
+               case SQL_DESC_CASE_SENSITIVE: /* read-only */
+               case SQL_DESC_CATALOG_NAME: /* read-only */
+               case SQL_DESC_CONCISE_TYPE: /* read-only */
+               case SQL_DESC_DATETIME_INTERVAL_CODE: /* read-only */
+               case SQL_DESC_DATETIME_INTERVAL_PRECISION: /* read-only */
+               case SQL_DESC_DISPLAY_SIZE: /* read-only */
+               case SQL_DESC_FIXED_PREC_SCALE: /* read-only */
+               case SQL_DESC_LABEL: /* read-only */
+               case SQL_DESC_LENGTH: /* read-only */
+               case SQL_DESC_LITERAL_PREFIX: /* read-only */
+               case SQL_DESC_LITERAL_SUFFIX: /* read-only */
+               case SQL_DESC_LOCAL_TYPE_NAME: /* read-only */
+               case SQL_DESC_NAME: /* read-only */
+               case SQL_DESC_NULLABLE: /* read-only */
+               case SQL_DESC_NUM_PREC_RADIX: /* read-only */
+               case SQL_DESC_OCTET_LENGTH: /* read-only */
+               case SQL_DESC_PRECISION: /* read-only */
+#if (ODBCVER >= 0x0350)
+               case SQL_DESC_ROWVER: /* read-only */
+#endif /* ODBCVER */
+               case SQL_DESC_SCALE: /* read-only */
+               case SQL_DESC_SCHEMA_NAME: /* read-only */
+               case SQL_DESC_SEARCHABLE: /* read-only */
+               case SQL_DESC_TABLE_NAME: /* read-only */
+               case SQL_DESC_TYPE: /* read-only */
+               case SQL_DESC_TYPE_NAME: /* read-only */
+               case SQL_DESC_UNNAMED: /* read-only */
+               case SQL_DESC_UNSIGNED: /* read-only */
+               case SQL_DESC_UPDATABLE: /* read-only */
                default:ret = SQL_ERROR;
-                       stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+                       stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
        }
        return ret;
 }
@@ -303,17 +512,526 @@ IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
                SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
 {
        RETCODE         ret = SQL_SUCCESS;
+       IPDFields       *ipdopts = SC_get_IPD(stmt);
+       APDFields       *apdopts = SC_get_APD(stmt);
+
+       switch (FieldIdentifier)
+       {
+               case SQL_DESC_ARRAY_STATUS_PTR:
+                       ipdopts->param_status_ptr = (SQLUSMALLINT *) Value;
+                       break;
+               case SQL_DESC_ROWS_PROCESSED_PTR:
+                       ipdopts->param_processed_ptr = (SQLUINTEGER *) Value;
+                       break;
+               case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */ 
+                       if (SQL_UNNAMED !=  (SQLUINTEGER) Value)
+                       {
+                               ret = SQL_ERROR;
+                               stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
+                       }
+                       break;
+               case SQL_DESC_TYPE:
+                       parameter_bindings_set(apdopts, RecNumber, TRUE);
+                       apdopts->parameters[RecNumber - 1].SQLType = (Int4) Value;
+                       break;
+               case SQL_DESC_DATETIME_INTERVAL_CODE:
+                       parameter_bindings_set(apdopts, RecNumber, TRUE);
+                       switch (apdopts->parameters[RecNumber - 1].SQLType)
+                       {
+                               case SQL_DATETIME:
+                               case SQL_TYPE_DATE:
+                               case SQL_TYPE_TIME:
+                               case SQL_TYPE_TIMESTAMP:
+                               switch ((Int4) Value)
+                               {
+                                       case SQL_CODE_DATE:
+                                               apdopts->parameters[RecNumber - 1].SQLType = SQL_TYPE_DATE;
+                                               break;
+                                       case SQL_CODE_TIME:
+                                               apdopts->parameters[RecNumber - 1].SQLType = SQL_TYPE_TIME;
+                                               break;
+                                       case SQL_CODE_TIMESTAMP:
+                                               apdopts->parameters[RecNumber - 1].SQLType = SQL_TYPE_TIMESTAMP;
+                                               break;
+                               }
+                               break;
+                       }
+                       break;
+               case SQL_DESC_CONCISE_TYPE:
+                       parameter_bindings_set(apdopts, RecNumber, TRUE);
+                       apdopts->parameters[RecNumber - 1].SQLType = (Int4) Value;
+                       break;
+               case SQL_DESC_COUNT:
+                       parameter_bindings_set(apdopts, (SQLUINTEGER) Value, FALSE);
+                       break; 
+               case SQL_DESC_PARAMETER_TYPE:
+                       apdopts->parameters[RecNumber - 1].paramType = (Int2) Value;
+                       break;
+               case SQL_DESC_SCALE:
+                       apdopts->parameters[RecNumber - 1].scale = (Int2) Value;
+                       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:
+               case SQL_DESC_PRECISION:
+#if (ODBCVER >= 0x0350)
+               case SQL_DESC_ROWVER: /* read-only */
+#endif /* ODBCVER */
+               case SQL_DESC_TYPE_NAME: /* read-only */
+               case SQL_DESC_UNSIGNED: /* read-only */
+               default:ret = SQL_ERROR;
+                       stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
+       }
+       return ret;
+}
+
+
+static RETCODE SQL_API
+ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+               SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength,
+               SQLINTEGER *StringLength)
+{
+       RETCODE         ret = SQL_SUCCESS;
+       SQLINTEGER      len, ival;
+       PTR             ptr = NULL;
+       const ARDFields *opts = SC_get_ARD(stmt);
+
+       len = 4;
+       switch (FieldIdentifier)
+       {
+               case SQL_DESC_ARRAY_SIZE:
+                       ival = opts->rowset_size;
+                       break; 
+               case SQL_DESC_ARRAY_STATUS_PTR:
+                       ptr = opts->row_operation_ptr;
+                       break;
+               case SQL_DESC_BIND_OFFSET_PTR:
+                       ptr = opts->row_offset_ptr;
+                       break;
+               case SQL_DESC_BIND_TYPE:
+                       ival = opts->bind_size;
+                       break;
+               case SQL_DESC_TYPE:
+                       switch (opts->bindings[RecNumber - 1].returntype)
+                       {
+                               case SQL_C_TYPE_DATE:
+                               case SQL_C_TYPE_TIME:
+                               case SQL_C_TYPE_TIMESTAMP:
+                                       ival = SQL_DATETIME;
+                                       break;
+                               default:
+                                       ival = opts->bindings[RecNumber - 1].returntype;
+                       }
+                       break;
+               case SQL_DESC_DATETIME_INTERVAL_CODE:
+                       switch (opts->bindings[RecNumber - 1].returntype)
+                       {
+                               case SQL_C_TYPE_DATE:
+                                       ival = SQL_CODE_DATE;
+                                       break;
+                               case SQL_C_TYPE_TIME:
+                                       ival = SQL_CODE_TIME;
+                                       break;
+                               case SQL_C_TYPE_TIMESTAMP:
+                                       ival = SQL_CODE_TIMESTAMP;
+                                       break;
+                               default:
+                                       ival = 0;
+                                       break;
+                       }
+                       break;
+               case SQL_DESC_CONCISE_TYPE:
+                       ival = opts->bindings[RecNumber - 1].returntype;
+                       break;
+               case SQL_DESC_DATA_PTR:
+                       if (!RecNumber)
+                               ptr = opts->bookmark->buffer;
+                       else
+                       {
+                               ptr = opts->bindings[RecNumber - 1].buffer;
+                       }
+                       break;
+               case SQL_DESC_INDICATOR_PTR:
+                       if (!RecNumber)
+                               ptr = opts->bookmark->used;
+                       else
+                       {
+                               ptr = opts->bindings[RecNumber - 1].used;
+                       }
+                       break;
+               case SQL_DESC_OCTET_LENGTH_PTR:
+                       if (!RecNumber)
+                               ptr = opts->bookmark->used;
+                       else
+                       {
+                               ptr = opts->bindings[RecNumber - 1].used;
+                       }
+                       break;
+               case SQL_DESC_COUNT:
+                       ival = opts->allocated;
+                       break;
+               case SQL_DESC_OCTET_LENGTH:
+                       if (RecNumber)
+                       {
+                               ival = opts->bindings[RecNumber - 1].buflen;
+                       }
+                       break;
+               case SQL_DESC_ALLOC_TYPE: /* read-only */
+                       ival = SQL_DESC_ALLOC_AUTO;
+                       break;
+               case SQL_DESC_DATETIME_INTERVAL_PRECISION:
+               case SQL_DESC_LENGTH:
+               case SQL_DESC_NUM_PREC_RADIX:
+               case SQL_DESC_PRECISION:
+               case SQL_DESC_SCALE:
+               default:ret = SQL_ERROR;
+                       stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
+       }
+       switch (BufferLength)
+       {
+               case 0:
+               case SQL_IS_INTEGER:
+                       len = 4;
+                       *((SQLINTEGER *) Value) = ival;
+                       break;
+               case SQL_IS_UINTEGER:
+                       len = 4;
+                       *((UInt4 *) Value) = ival;
+                       break;
+               case SQL_IS_SMALLINT:
+                       len = 2;
+                       *((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
+                       break;
+               case SQL_IS_USMALLINT:
+                       len = 2;
+                       *((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
+                       break;
+               case SQL_IS_POINTER:
+                       len = 4;
+                       *((void **) Value) = ptr;
+                       break;
+       }
+                       
+       if (StringLength)
+               *StringLength = len;
+       return ret;
+}
+
+static RETCODE SQL_API
+APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+               SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength,
+               SQLINTEGER *StringLength)
+{
+       RETCODE         ret = SQL_SUCCESS;
+       SQLINTEGER      ival = 0, len;
+       PTR             ptr = NULL;
+       const APDFields *opts = SC_get_APD(stmt);
+
+       len = 4;
+       switch (FieldIdentifier)
+       {
+               case SQL_DESC_ARRAY_SIZE:
+                       ival = opts->paramset_size;
+                       break; 
+               case SQL_DESC_ARRAY_STATUS_PTR:
+                       ptr = opts->param_operation_ptr;
+                       break;
+               case SQL_DESC_BIND_OFFSET_PTR:
+                       ptr = opts->param_offset_ptr;
+                       break;
+               case SQL_DESC_BIND_TYPE:
+                       ival = opts->param_bind_type;
+                       break;
+
+               case SQL_DESC_TYPE:
+                       switch (opts->parameters[RecNumber - 1].CType)
+                       {
+                               case SQL_C_TYPE_DATE:
+                               case SQL_C_TYPE_TIME:
+                               case SQL_C_TYPE_TIMESTAMP:
+                                       ival = SQL_DATETIME;
+                                       break;
+                               default:
+                                       ival = opts->parameters[RecNumber - 1].CType;
+                       }
+                       break;
+               case SQL_DESC_DATETIME_INTERVAL_CODE:
+                       switch (opts->parameters[RecNumber - 1].CType)
+                       {
+                               case SQL_C_TYPE_DATE:
+                                       ival = SQL_CODE_DATE;
+                                       break;
+                               case SQL_C_TYPE_TIME:
+                                       ival = SQL_CODE_TIME;
+                                       break;
+                               case SQL_C_TYPE_TIMESTAMP:
+                                       ival = SQL_CODE_TIMESTAMP;
+                                       break;
+                               default:
+                                       ival = 0;
+                                       break;
+                       }
+                       break;
+               case SQL_DESC_CONCISE_TYPE:
+                       ival = opts->parameters[RecNumber - 1].CType;
+                       break;
+               case SQL_DESC_DATA_PTR:
+                       ptr = opts->parameters[RecNumber - 1].buffer;
+                       break;
+               case SQL_DESC_INDICATOR_PTR:
+                       ptr = opts->parameters[RecNumber - 1].used;
+                       break;
+               case SQL_DESC_OCTET_LENGTH:
+                       ival = opts->parameters[RecNumber - 1].buflen;
+                       break;
+               case SQL_DESC_OCTET_LENGTH_PTR:
+                       ptr = opts->parameters[RecNumber - 1].used;
+                       break;
+               case SQL_DESC_COUNT:
+                       ival = opts->allocated;
+                       break; 
+               case SQL_DESC_ALLOC_TYPE: /* read-only */
+                       ival = SQL_DESC_ALLOC_AUTO;
+                       break;
+               case SQL_DESC_DATETIME_INTERVAL_PRECISION:
+               case SQL_DESC_LENGTH:
+               case SQL_DESC_NUM_PREC_RADIX:
+               case SQL_DESC_PRECISION:
+               case SQL_DESC_SCALE:
+               default:ret = SQL_ERROR;
+                       stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
+       }
+       switch (BufferLength)
+       {
+               case 0:
+               case SQL_IS_INTEGER:
+                       len = 4;
+                       *((Int4 *) Value) = ival;
+                       break;
+               case SQL_IS_UINTEGER:
+                       len = 4;
+                       *((UInt4 *) Value) = ival;
+                       break;
+               case SQL_IS_SMALLINT:
+                       len = 2;
+                       *((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
+                       break;
+               case SQL_IS_USMALLINT:
+                       len = 2;
+                       *((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
+                       break;
+               case SQL_IS_POINTER:
+                       len = 4;
+                       *((void **) Value) = ptr;
+                       break;
+       }
+                       
+       if (StringLength)
+               *StringLength = len;
+       return ret;
+}
+
+static RETCODE SQL_API
+IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+               SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength,
+               SQLINTEGER *StringLength)
+{
+       RETCODE         ret = SQL_SUCCESS;
+       SQLINTEGER      ival = 0, len;
+       PTR             ptr = NULL;
+       const IRDFields *opts = SC_get_IRD(stmt);
+
+       switch (FieldIdentifier)
+       {
+               case SQL_DESC_ARRAY_STATUS_PTR:
+                       ptr = opts->rowStatusArray;
+                       break;
+               case SQL_DESC_ROWS_PROCESSED_PTR:
+                       ptr = opts->rowsFetched;
+                       break;
+               case SQL_DESC_ALLOC_TYPE: /* read-only */
+               case SQL_DESC_COUNT: /* read-only */
+               case SQL_DESC_AUTO_UNIQUE_VALUE: /* read-only */
+               case SQL_DESC_BASE_COLUMN_NAME: /* read-only */
+               case SQL_DESC_BASE_TABLE_NAME: /* read-only */
+               case SQL_DESC_CASE_SENSITIVE: /* read-only */
+               case SQL_DESC_CATALOG_NAME: /* read-only */
+               case SQL_DESC_CONCISE_TYPE: /* read-only */
+               case SQL_DESC_DATETIME_INTERVAL_CODE: /* read-only */
+               case SQL_DESC_DATETIME_INTERVAL_PRECISION: /* read-only */
+               case SQL_DESC_DISPLAY_SIZE: /* read-only */
+               case SQL_DESC_FIXED_PREC_SCALE: /* read-only */
+               case SQL_DESC_LABEL: /* read-only */
+               case SQL_DESC_LENGTH: /* read-only */
+               case SQL_DESC_LITERAL_PREFIX: /* read-only */
+               case SQL_DESC_LITERAL_SUFFIX: /* read-only */
+               case SQL_DESC_LOCAL_TYPE_NAME: /* read-only */
+               case SQL_DESC_NAME: /* read-only */
+               case SQL_DESC_NULLABLE: /* read-only */
+               case SQL_DESC_NUM_PREC_RADIX: /* read-only */
+               case SQL_DESC_OCTET_LENGTH: /* read-only */
+               case SQL_DESC_PRECISION: /* read-only */
+#if (ODBCVER >= 0x0350)
+               case SQL_DESC_ROWVER: /* read-only */
+#endif /* ODBCVER */
+               case SQL_DESC_SCALE: /* read-only */
+               case SQL_DESC_SCHEMA_NAME: /* read-only */
+               case SQL_DESC_SEARCHABLE: /* read-only */
+               case SQL_DESC_TABLE_NAME: /* read-only */
+               case SQL_DESC_TYPE: /* read-only */
+               case SQL_DESC_TYPE_NAME: /* read-only */
+               case SQL_DESC_UNNAMED: /* read-only */
+               case SQL_DESC_UNSIGNED: /* read-only */
+               case SQL_DESC_UPDATABLE: /* read-only */
+               default:ret = SQL_ERROR;
+                       stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
+       }
+       switch (BufferLength)
+       {
+               case 0:
+               case SQL_IS_INTEGER:
+                       len = 4;
+                       *((Int4 *) Value) = ival;
+                       break;
+               case SQL_IS_UINTEGER:
+                       len = 4;
+                       *((UInt4 *) Value) = ival;
+                       break;
+               case SQL_IS_SMALLINT:
+                       len = 2;
+                       *((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
+                       break;
+               case SQL_IS_USMALLINT:
+                       len = 2;
+                       *((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
+                       break;
+               case SQL_IS_POINTER:
+                       len = 4;
+                       *((void **) Value) = ptr;
+                       break;
+       }
+                       
+       if (StringLength)
+               *StringLength = len;
+       return ret;
+}
+
+static RETCODE SQL_API
+IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+               SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength,
+               SQLINTEGER *StringLength)
+{
+       RETCODE         ret = SQL_SUCCESS;
+       SQLINTEGER      ival = 0, len;
+       PTR             ptr = NULL;
+       const IPDFields *ipdopts = SC_get_IPD(stmt);
+       const APDFields *apdopts = SC_get_APD(stmt);
+
        switch (FieldIdentifier)
        {
                case SQL_DESC_ARRAY_STATUS_PTR:
-                       stmt->options.param_status_ptr = (SQLUSMALLINT *) Value;
+                       ptr = ipdopts->param_status_ptr;
                        break;
                case SQL_DESC_ROWS_PROCESSED_PTR:
-                       stmt->options.param_processed_ptr = (SQLUINTEGER *) Value;
+                       ptr = ipdopts->param_processed_ptr;
+                       break;
+               case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */
+                       ival = SQL_UNNAMED;
+                       break;
+               case SQL_DESC_TYPE:
+                       switch (apdopts->parameters[RecNumber - 1].SQLType)
+                       {
+                               case SQL_TYPE_DATE:
+                               case SQL_TYPE_TIME:
+                               case SQL_TYPE_TIMESTAMP:
+                                       ival = SQL_DATETIME;
+                                       break;
+                               default:
+                                       ival = apdopts->parameters[RecNumber - 1].SQLType;
+                       }
+                       break;
+               case SQL_DESC_DATETIME_INTERVAL_CODE:
+                       switch (apdopts->parameters[RecNumber - 1].SQLType)
+                       {
+                               case SQL_TYPE_DATE:
+                                       ival = SQL_CODE_DATE;
+                               case SQL_TYPE_TIME:
+                                       ival = SQL_CODE_TIME;
+                                       break;
+                               case SQL_TYPE_TIMESTAMP:
+                                       ival = SQL_CODE_TIMESTAMP;
+                                       break;
+                               default:
+                                       ival = 0;
+                       }
+                       break;
+               case SQL_DESC_CONCISE_TYPE:
+                       ival = apdopts->parameters[RecNumber - 1].SQLType;
+                       break;
+               case SQL_DESC_COUNT:
+                       ival = apdopts->allocated;
+                       break; 
+               case SQL_DESC_PARAMETER_TYPE:
+                       ival = apdopts->parameters[RecNumber - 1].paramType;
+                       break;
+               case SQL_DESC_SCALE:
+                       ival = apdopts->parameters[RecNumber - 1].scale ;
                        break;
+               case SQL_DESC_ALLOC_TYPE: /* read-only */
+                       ival = SQL_DESC_ALLOC_AUTO;
+                       break; 
+               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:
+               case SQL_DESC_PRECISION:
+#if (ODBCVER >= 0x0350)
+               case SQL_DESC_ROWVER: /* read-only */
+#endif /* ODBCVER */
+               case SQL_DESC_TYPE_NAME: /* read-only */
+               case SQL_DESC_UNSIGNED: /* read-only */
                default:ret = SQL_ERROR;
-                       stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+                       stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
+       }
+       switch (BufferLength)
+       {
+               case 0:
+               case SQL_IS_INTEGER:
+                       len = 4;
+                       *((Int4 *) Value) = ival;
+                       break;
+               case SQL_IS_UINTEGER:
+                       len = 4;
+                       *((UInt4 *) Value) = ival;
+                       break;
+               case SQL_IS_SMALLINT:
+                       len = 2;
+                       *((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
+                       break;
+               case SQL_IS_USMALLINT:
+                       len = 2;
+                       *((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
+                       break;
+               case SQL_IS_POINTER:
+                       len = 4;
+                       *((void **)Value) = ptr;
+                       break;
        }
+                       
+       if (StringLength)
+               *StringLength = len;
        return ret;
 }
 
@@ -332,51 +1050,51 @@ PGAPI_GetStmtAttr(HSTMT StatementHandle,
        switch (Attribute)
        {
                case SQL_ATTR_FETCH_BOOKMARK_PTR:               /* 16 */
-                       Value = stmt->options.bookmark_ptr;
+                       *((void **) Value) = stmt->options.bookmark_ptr;
                        len = 4;
                        break;
                case SQL_ATTR_PARAM_BIND_OFFSET_PTR:    /* 17 */
-                       Value = stmt->options.param_offset_ptr;
+                       *((SQLUINTEGER **) Value) = SC_get_APD(stmt)->param_offset_ptr;
                        len = 4;
                        break;
                case SQL_ATTR_PARAM_BIND_TYPE:  /* 18 */
-                       *((SQLUINTEGER *) Value) = stmt->options.param_bind_type;
+                       *((SQLUINTEGER *) Value) = SC_get_APD(stmt)->param_bind_type;
                        len = 4;
                        break;
                case SQL_ATTR_PARAM_OPERATION_PTR:              /* 19 */
-                       Value = stmt->options.param_operation_ptr;
+                       *((SQLUSMALLINT **) Value) = SC_get_APD(stmt)->param_operation_ptr;
                        len = 4;
                        break;
                case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
-                       Value = stmt->options.param_status_ptr;
+                       *((SQLUSMALLINT **) Value) = SC_get_IPD(stmt)->param_status_ptr;
                        len = 4;
                        break;
                case SQL_ATTR_PARAMS_PROCESSED_PTR:             /* 21 */
-                       Value = stmt->options.param_processed_ptr;
+                       *((SQLUINTEGER **) Value) = SC_get_IPD(stmt)->param_processed_ptr;
                        len = 4;
                        break;
                case SQL_ATTR_PARAMSET_SIZE:    /* 22 */
-                       *((SQLUINTEGER *) Value) = stmt->options.paramset_size;
+                       *((SQLUINTEGER *) Value) = SC_get_APD(stmt)->paramset_size;
                        len = 4;
                        break;
                case SQL_ATTR_ROW_BIND_OFFSET_PTR:              /* 23 */
-                       Value = stmt->options.row_offset_ptr;
+                       *((SQLUINTEGER **) Value) = SC_get_ARD(stmt)->row_offset_ptr;
                        len = 4;
                        break;
                case SQL_ATTR_ROW_OPERATION_PTR:                /* 24 */
-                       Value = stmt->options.row_operation_ptr;
+                       *((SQLUSMALLINT **) Value) = SC_get_ARD(stmt)->row_operation_ptr;
                        len = 4;
                        break;
                case SQL_ATTR_ROW_STATUS_PTR:   /* 25 */
-                       Value = stmt->options.rowStatusArray;
+                       *((SQLUSMALLINT **) Value) = SC_get_IRD(stmt)->rowStatusArray;
                        len = 4;
                        break;
                case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
-                       Value = stmt->options.rowsFetched;
+                       *((SQLUINTEGER **) Value) = SC_get_IRD(stmt)->rowsFetched;
                        len = 4;
                        break;
                case SQL_ATTR_ROW_ARRAY_SIZE:   /* 27 */
-                       *((SQLUINTEGER *) Value) = stmt->options.rowset_size;
+                       *((SQLUINTEGER *) Value) = SC_get_ARD(stmt)->rowset_size;
                        len = 4;
                        break;
                case SQL_ATTR_APP_ROW_DESC:             /* 10010 */
@@ -418,6 +1136,7 @@ PGAPI_SetConnectAttr(HDBC ConnectionHandle,
                        SQLINTEGER StringLength)
 {
        ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
+       RETCODE ret = SQL_SUCCESS;
 
        mylog("PGAPI_SetConnectAttr %d\n", Attribute);
        switch (Attribute)
@@ -430,8 +1149,54 @@ PGAPI_SetConnectAttr(HDBC ConnectionHandle,
                        conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
                        conn->errormsg = "Unsupported connect attribute (Set)";
                        return SQL_ERROR;
+               default:
+                       ret = PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value);
        }
-       return PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value);
+       return ret;
+}
+
+/*     new function */
+RETCODE                SQL_API
+PGAPI_GetDescField(SQLHDESC DescriptorHandle,
+                       SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
+                       PTR Value, SQLINTEGER BufferLength,
+                       SQLINTEGER *StringLength)
+{
+       RETCODE         ret = SQL_SUCCESS;
+       HSTMT           hstmt;
+       SQLUINTEGER     descType;
+       StatementClass *stmt;
+       static const char *func = "PGAPI_GetDescField";
+
+       mylog("%s h=%u rec=%d field=%d blen=%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, BufferLength);
+       hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType);
+       mylog("stmt=%x type=%d\n", hstmt, descType);
+       stmt = (StatementClass *) hstmt;
+       switch (descType)
+       {
+               case SQL_ATTR_APP_ROW_DESC:
+                       ret = ARDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
+                       break;
+               case SQL_ATTR_APP_PARAM_DESC:
+                       ret = APDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
+                       break;
+               case SQL_ATTR_IMP_ROW_DESC:
+                       ret = IRDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
+                       break;
+               case SQL_ATTR_IMP_PARAM_DESC:
+                       ret = IPDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
+                       break;
+               default:ret = SQL_ERROR;
+                       stmt->errornumber = STMT_INTERNAL_ERROR; 
+                       stmt->errormsg = "Error not implemented";
+       }
+       if (ret == SQL_ERROR)
+       {
+               if (!stmt->errormsg && stmt->errornumber == STMT_INVALID_DESCRIPTOR_IDENTIFIER) 
+                       stmt->errormsg = "can't SQLGetDescField for this descriptor identifier"; 
+               SC_log_error(func, "", stmt);
+       }
+       return ret;
 }
 
 /*     new function */
@@ -446,7 +1211,7 @@ PGAPI_SetDescField(SQLHDESC DescriptorHandle,
        StatementClass *stmt;
        static const char *func = "PGAPI_SetDescField";
 
-       mylog("%s h=%u rec=%d field=%d val=%x\n", func, DescriptorHandle, RecNumber, FieldIdentifier, Value);
+       mylog("%s h=%u rec=%d field=%d val=%x,%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, Value, BufferLength);
        hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType);
        mylog("stmt=%x type=%d\n", hstmt, descType);
        stmt = (StatementClass *) hstmt;
@@ -469,7 +1234,11 @@ PGAPI_SetDescField(SQLHDESC DescriptorHandle,
                        stmt->errormsg = "Error not implemented";
        }
        if (ret == SQL_ERROR)
+       {
+               if (!stmt->errormsg && stmt->errornumber == STMT_INVALID_DESCRIPTOR_IDENTIFIER) 
+                       stmt->errormsg = "can't SQLSetDescField for this descriptor identifier"; 
                SC_log_error(func, "", stmt);
+       }
        return ret;
 }
 
@@ -511,37 +1280,37 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle,
                        stmt->options.bookmark_ptr = Value;
                        break;
                case SQL_ATTR_PARAM_BIND_OFFSET_PTR:    /* 17 */
-                       stmt->options.param_offset_ptr = (SQLUINTEGER *) Value;
+                       SC_get_APD(stmt)->param_offset_ptr = (SQLUINTEGER *) Value;
                        break;
                case SQL_ATTR_PARAM_BIND_TYPE:  /* 18 */
-                       stmt->options.param_bind_type = (SQLUINTEGER) Value;
+                       SC_get_APD(stmt)->param_bind_type = (SQLUINTEGER) Value;
                        break;
                case SQL_ATTR_PARAM_OPERATION_PTR:              /* 19 */
-                       stmt->options.param_operation_ptr = Value;
+                       SC_get_APD(stmt)->param_operation_ptr = Value;
                        break;
                case SQL_ATTR_PARAM_STATUS_PTR:                 /* 20 */
-                       stmt->options.param_status_ptr = (SQLUSMALLINT *) Value;
+                       SC_get_IPD(stmt)->param_status_ptr = (SQLUSMALLINT *) Value;
                        break;
                case SQL_ATTR_PARAMS_PROCESSED_PTR:             /* 21 */
-                       stmt->options.param_processed_ptr = (SQLUINTEGER *) Value;
+                       SC_get_IPD(stmt)->param_processed_ptr = (SQLUINTEGER *) Value;
                        break;
                case SQL_ATTR_PARAMSET_SIZE:    /* 22 */
-                       stmt->options.paramset_size = (SQLUINTEGER) Value;
+                       SC_get_APD(stmt)->paramset_size = (SQLUINTEGER) Value;
                        break;
                case SQL_ATTR_ROW_BIND_OFFSET_PTR:              /* 23 */
-                       stmt->options.row_offset_ptr = (SQLUINTEGER *) Value;
+                       SC_get_ARD(stmt)->row_offset_ptr = (SQLUINTEGER *) Value;
                        break;
                case SQL_ATTR_ROW_OPERATION_PTR:                /* 24 */
-                       stmt->options.row_operation_ptr = Value;
+                       SC_get_ARD(stmt)->row_operation_ptr = Value;
                        break;
                case SQL_ATTR_ROW_STATUS_PTR:   /* 25 */
-                       stmt->options.rowStatusArray = (SQLUSMALLINT *) Value;
+                       SC_get_IRD(stmt)->rowStatusArray = (SQLUSMALLINT *) Value;
                        break;
                case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
-                       stmt->options.rowsFetched = (SQLUINTEGER *) Value;
+                       SC_get_IRD(stmt)->rowsFetched = (SQLUINTEGER *) Value;
                        break;
                case SQL_ATTR_ROW_ARRAY_SIZE:   /* 27 */
-                       stmt->options.rowset_size = (SQLUINTEGER) Value;
+                       SC_get_ARD(stmt)->rowset_size = (SQLUINTEGER) Value;
                        break;
                default:
                        return PGAPI_SetStmtOption(StatementHandle, (UWORD) Attribute, (UDWORD) Value);
index f7a72a2..a906a31 100644 (file)
@@ -280,5 +280,8 @@ RETCODE SQL_API PGAPI_SetStmtAttr(HSTMT StatementHandle,
 RETCODE SQL_API PGAPI_SetDescField(SQLHDESC DescriptorHandle,
                        SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
                        PTR Value, SQLINTEGER BufferLength);
+RETCODE SQL_API PGAPI_GetDescField(SQLHDESC DescriptorHandle,
+                       SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
+                       PTR Value, SQLINTEGER BufferLength, SQLINTEGER *StringLength);
 #endif /* ODBCVER */
 #endif   /* define_PG_API_FUNC_H__ */
index b409858..691fd92 100644 (file)
@@ -26,7 +26,7 @@
 
 
 
-Int4           getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
+Int4           getCharColumnSize(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
 
 /*
  * these are the types we support.     all of the pgtype_ functions should
@@ -230,13 +230,13 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
  *     types that are unknown.  All other pg routines in here return a suitable default.
  */
 Int2
-pgtype_to_sqltype(StatementClass *stmt, Int4 type)
+pgtype_to_concise_type(StatementClass *stmt, Int4 type)
 {
        ConnectionClass *conn = SC_get_conn(stmt);
        ConnInfo        *ci = &(conn->connInfo);
 #if (ODBCVER >= 0x0300)
        EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
-#endif
+#endif /* ODBCVER */
 
        switch (type)
        {
@@ -289,7 +289,7 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type)
                        if (!conn->ms_jet)
                                return SQL_BIGINT;
 #endif /* ODBCVER */
-                       return SQL_CHAR;
+                       return SQL_VARCHAR;
 
                case PG_TYPE_NUMERIC:
                        return SQL_NUMERIC;
@@ -338,6 +338,40 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type)
        }
 }
 
+Int2
+pgtype_to_sqldesctype(StatementClass *stmt, Int4 type)
+{
+       Int2    rettype;
+
+       switch (rettype = pgtype_to_concise_type(stmt, type))
+       {
+#if (ODBCVER >= 0x0300)
+               case SQL_TYPE_DATE:
+               case SQL_TYPE_TIME:
+               case SQL_TYPE_TIMESTAMP:
+                       return SQL_DATETIME;
+#endif /* ODBCVER */
+       }
+       return rettype;
+}
+
+Int2
+pgtype_to_datetime_sub(StatementClass *stmt, Int4 type)
+{
+       switch (pgtype_to_concise_type(stmt, type))
+       {
+#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;
+}
+
 
 Int2
 pgtype_to_ctype(StatementClass *stmt, Int4 type)
@@ -346,7 +380,7 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
        ConnInfo        *ci = &(conn->connInfo);
 #if (ODBCVER >= 0x0300)
        EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
-#endif
+#endif /* ODBCVER */
 
        switch (type)
        {
@@ -484,13 +518,13 @@ pgtype_to_name(StatementClass *stmt, Int4 type)
 
 
 static Int2
-getNumericScale(StatementClass *stmt, Int4 type, int col)
+getNumericDecimalDigits(StatementClass *stmt, Int4 type, int col)
 {
        Int4            atttypmod = -1;
        QResultClass *result;
        ColumnInfoClass *flds;
 
-       mylog("getNumericScale: type=%d, col=%d\n", type, col);
+       mylog("getNumericDecimalDigits: type=%d, col=%d\n", type, col);
 
        if (col < 0)
                return PG_NUMERIC_MAX_SCALE;
@@ -525,13 +559,13 @@ getNumericScale(StatementClass *stmt, Int4 type, int col)
 
 
 static Int4
-getNumericPrecision(StatementClass *stmt, Int4 type, int col)
+getNumericColumnSize(StatementClass *stmt, Int4 type, int col)
 {
        Int4            atttypmod = -1;
        QResultClass *result;
        ColumnInfoClass *flds;
 
-       mylog("getNumericPrecision: type=%d, col=%d\n", type, col);
+       mylog("getNumericColumnSize: type=%d, col=%d\n", type, col);
 
        if (col < 0)
                return PG_NUMERIC_MAX_PRECISION;
@@ -566,15 +600,15 @@ getNumericPrecision(StatementClass *stmt, Int4 type, int col)
 
 
 Int4
-getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
+getCharColumnSize(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
 {
-       int                     p = -1,
+       int                     p = -1, attlen = -1,
                                maxsize;
        QResultClass *result;
        ColumnInfoClass *flds;
        ConnInfo   *ci = &(SC_get_conn(stmt)->connInfo);
 
-       mylog("getCharPrecision: type=%d, col=%d, unknown = %d\n", type, col, handle_unknown_size_as);
+       mylog("getCharColumnSize: type=%d, col=%d, unknown = %d\n", type, col, handle_unknown_size_as);
 
        /* Assign Maximum size based on parameters */
        switch (type)
@@ -607,7 +641,7 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
                        maxsize = TEXT_FIELD_SIZE;
        }
        /*
-        * Static Precision (i.e., the Maximum Precision of the datatype) This
+        * Static ColumnSize (i.e., the Maximum ColumnSize of the datatype) This
         * has nothing to do with a result set.
         */
        if (col < 0)
@@ -628,35 +662,37 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
                        return maxsize;
        }
 
+       p = QR_get_display_size(result, col); /* longest */
+       attlen = QR_get_atttypmod(result, col);
        /* Size is unknown -- handle according to parameter */
-       if (QR_get_atttypmod(result, col) > -1)
-               return QR_get_atttypmod(result, col);
+       if (attlen > p)         /* maybe the length is known */
+               return attlen;
 
        /* The type is really unknown */
        if (type == PG_TYPE_BPCHAR || handle_unknown_size_as == UNKNOWNS_AS_LONGEST)
        {
-               p = QR_get_display_size(result, col);
-               mylog("getCharPrecision: LONGEST: p = %d\n", p);
+               mylog("getCharColumnSize: LONGEST: p = %d\n", p);
                if (p >= 0)
                        return p;
        }
 
+       if (p > maxsize)
+               maxsize = p;
        if (handle_unknown_size_as == UNKNOWNS_AS_MAX)
                return maxsize;
        else /* handle_unknown_size_as == DONT_KNOW */
                return -1;
-       
 }
 
 static Int2
-getTimestampScale(StatementClass *stmt, Int4 type, int col)
+getTimestampDecimalDigits(StatementClass *stmt, Int4 type, int col)
 {
        ConnectionClass *conn = SC_get_conn(stmt);
        Int4            atttypmod;
        QResultClass *result;
        ColumnInfoClass *flds;
 
-       mylog("getTimestampScale: type=%d, col=%d\n", type, col);
+       mylog("getTimestampDecimalDigits: type=%d, col=%d\n", type, col);
 
        if (col < 0)
                return 0;
@@ -685,12 +721,12 @@ getTimestampScale(StatementClass *stmt, Int4 type, int col)
 
 
 static Int4
-getTimestampPrecision(StatementClass *stmt, Int4 type, int col)
+getTimestampColumnSize(StatementClass *stmt, Int4 type, int col)
 {
        Int4            fixed,
                                scale;
 
-       mylog("getTimestampPrecision: type=%d, col=%d\n", type, col);
+       mylog("getTimestampColumnSize: type=%d, col=%d\n", type, col);
 
        switch (type)
        {
@@ -710,11 +746,13 @@ getTimestampPrecision(StatementClass *stmt, Int4 type, int col)
                                fixed = 19;
                        break;
        }
-       scale = getTimestampScale(stmt, type, col);
+       scale = getTimestampDecimalDigits(stmt, type, col);
        return (scale > 0) ? fixed + 1 + scale : fixed;
 }
 
 /*
+ *     This corresponds to "precision" in ODBC 2.x.
+ *
  *     For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, PG_TYPE_NUMERIC, SQLColumns will
  *     override this length with the atttypmod length from pg_attribute .
  *
@@ -722,7 +760,7 @@ getTimestampPrecision(StatementClass *stmt, Int4 type, int col)
  *     This is used for functions SQLDescribeCol and SQLColAttributes.
  */
 Int4
-pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
+pgtype_column_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
 {
        switch (type)
        {
@@ -750,7 +788,7 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
                        return 19;                      /* signed */
 
                case PG_TYPE_NUMERIC:
-                       return getNumericPrecision(stmt, type, col);
+                       return getNumericColumnSize(stmt, type, col);
 
                case PG_TYPE_FLOAT4:
                case PG_TYPE_MONEY:
@@ -769,7 +807,7 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
                        return 22;
                case PG_TYPE_DATETIME:
                        /* return 22; */
-                       return getTimestampPrecision(stmt, type, col);
+                       return getTimestampColumnSize(stmt, type, col);
 
                case PG_TYPE_BOOL:
                {
@@ -787,8 +825,24 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
                                return SQL_NO_TOTAL;
 
                        /* Handle Character types and unknown types */
-                       return getCharPrecision(stmt, type, col, handle_unknown_size_as);
+                       return getCharColumnSize(stmt, type, col, handle_unknown_size_as);
+       }
+}
+
+/*
+ *     "precision in ODBC 3.x.
+ */
+Int4
+pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
+{
+       switch (type)
+       {
+               case PG_TYPE_NUMERIC:
+                       return getNumericColumnSize(stmt, type, col);
+               case PG_TYPE_DATETIME:
+                       return getTimestampDecimalDigits(stmt, type, col);
        }
+       return -1;
 }
 
 
@@ -813,7 +867,7 @@ pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown
                        return 20;                      /* signed: 19 digits + sign */
 
                case PG_TYPE_NUMERIC:
-                       dsize = getNumericPrecision(stmt, type, col);
+                       dsize = getNumericColumnSize(stmt, type, col);
                        return dsize < 0 ? dsize : dsize + 2;
 
                case PG_TYPE_MONEY:
@@ -827,60 +881,62 @@ pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown
 
                        /* Character types use regular precision */
                default:
-                       return pgtype_precision(stmt, type, col, handle_unknown_size_as);
+                       return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
        }
 }
 
 
 /*
- *     For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, SQLColumns will
- *     override this length with the atttypmod length from pg_attribute
+ *     The length in bytes of data transferred on an SQLGetData, SQLFetch,
+ *     or SQLFetchScroll operation if SQL_C_DEFAULT is specified.
  */
 Int4
-pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
+pgtype_buffer_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
 {
        ConnectionClass *conn = SC_get_conn(stmt);
 
        switch (type)
        {
                case PG_TYPE_INT2:
-                       return 2;
+                       return 2; /* sizeof(SQLSMALLINT) */
 
                case PG_TYPE_OID:
                case PG_TYPE_XID:
                case PG_TYPE_INT4:
-                       return 4;
+                       return 4; /* sizeof(SQLINTEGER) */
 
                case PG_TYPE_INT8:
-                       return 20;                      /* signed: 19 digits + sign */
+                       if (SQL_C_CHAR == pgtype_to_ctype(stmt, type))
+                               return 20;                      /* signed: 19 digits + sign */
+                       return 8; /* sizeof(SQLSBININT) */
 
                case PG_TYPE_NUMERIC:
-                       return getNumericPrecision(stmt, type, col) + 2;
+                       return getNumericColumnSize(stmt, type, col) + 2;
 
                case PG_TYPE_FLOAT4:
                case PG_TYPE_MONEY:
-                       return 4;
+                       return 4; /* sizeof(SQLREAL) */
 
                case PG_TYPE_FLOAT8:
-                       return 8;
+                       return 8; /* sizeof(SQLFLOAT) */
 
                case PG_TYPE_DATE:
                case PG_TYPE_TIME:
-                       return 6;                       /* sizeof(DATE(TIME)_STRUCT) */
+                       return 6;               /* sizeof(DATE(TIME)_STRUCT) */
 
                case PG_TYPE_ABSTIME:
                case PG_TYPE_DATETIME:
                case PG_TYPE_TIMESTAMP:
-                       return 16;                      /* sizeof(TIMESTAMP_STRUCT) */
+                       return 16;              /* sizeof(TIMESTAMP_STRUCT) */
 
-                       /* Character types (and NUMERIC) use the default precision */
+                       /* Character types use the default precision */
                case PG_TYPE_VARCHAR:
                case PG_TYPE_BPCHAR:
                        {
                        int     coef = 1;
-                       Int4    prec = pgtype_precision(stmt, type, col, handle_unknown_size_as), maxvarc;
+                       Int4    prec = pgtype_column_size(stmt, type, col, handle_unknown_size_as), maxvarc;
                        if (conn->unicode)
-                               return (prec + 1) * 2;
+                               return prec * 2;
 #ifdef MULTIBYTE
                        /* after 7.2 */
                        if (PG_VERSION_GE(conn, 7.2))
@@ -891,20 +947,100 @@ pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_
                                /* CR -> CR/LF */
                                coef = 2;
                        if (coef == 1)
-                               return prec + 1;
+                               return prec;
                        maxvarc = conn->connInfo.drivers.max_varchar_size;
                        if (prec <= maxvarc && prec * coef > maxvarc)
                                return maxvarc;
                        return coef * prec;
                        }
                default:
-                       return pgtype_precision(stmt, type, col, handle_unknown_size_as);
+                       return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
        }
 }
 
+/*
+ */
+Int4
+pgtype_desclength(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
+{
+       switch (type)
+       {
+               case PG_TYPE_INT2:
+                       return 2;
+
+               case PG_TYPE_OID:
+               case PG_TYPE_XID:
+               case PG_TYPE_INT4:
+                       return 4;
+
+               case PG_TYPE_INT8:
+                       return 20;                      /* signed: 19 digits + sign */
 
+               case PG_TYPE_NUMERIC:
+                       return getNumericColumnSize(stmt, type, col) + 2;
+
+               case PG_TYPE_FLOAT4:
+               case PG_TYPE_MONEY:
+                       return 4;
+
+               case PG_TYPE_FLOAT8:
+                       return 8;
+
+               case PG_TYPE_DATE:
+               case PG_TYPE_TIME:
+               case PG_TYPE_ABSTIME:
+               case PG_TYPE_DATETIME:
+               case PG_TYPE_TIMESTAMP:
+               case PG_TYPE_VARCHAR:
+               case PG_TYPE_BPCHAR:
+                       return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
+               default:
+                       return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
+       }
+}
+
+/*
+ *     Transfer octet length.
+ */
+Int4
+pgtype_transfer_octet_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
+{
+       ConnectionClass *conn = SC_get_conn(stmt);
+
+       int     coef = 1;
+       Int4    prec = pgtype_column_size(stmt, type, col, handle_unknown_size_as), maxvarc;
+       switch (type)
+       {
+               case PG_TYPE_VARCHAR:
+               case PG_TYPE_BPCHAR:
+                       if (conn->unicode)
+                               return prec * 2;
+#ifdef MULTIBYTE
+                       /* after 7.2 */
+                       if (PG_VERSION_GE(conn, 7.2))
+                               coef = 3;
+                       else
+#endif   /* MULTIBYTE */
+                       if ((conn->connInfo).lf_conversion)
+                               /* CR -> CR/LF */
+                               coef = 2;
+                       if (coef == 1)
+                               return prec;
+                       maxvarc = conn->connInfo.drivers.max_varchar_size;
+                       if (prec <= maxvarc && prec * coef > maxvarc)
+                               return maxvarc;
+                       return coef * prec;
+               case PG_TYPE_BYTEA:
+                       return prec;
+       }
+       return -1;
+}
+
+/*
+ *     corrsponds to "scale" in ODBC 2.x.
+ */
 Int2
-pgtype_scale(StatementClass *stmt, Int4 type, int col)
+pgtype_decimal_digits(StatementClass *stmt, Int4 type, int col)
 {
        switch (type)
        {
@@ -927,16 +1063,30 @@ pgtype_scale(StatementClass *stmt, Int4 type, int col)
                        return 0;
                case PG_TYPE_DATETIME:
                        /* return 0; */
-                       return getTimestampScale(stmt, type, col);
+                       return getTimestampDecimalDigits(stmt, type, col);
 
                case PG_TYPE_NUMERIC:
-                       return getNumericScale(stmt, type, col);
+                       return getNumericDecimalDigits(stmt, type, col);
 
                default:
                        return -1;
        }
 }
 
+/*
+ *     "scale" in ODBC 3.x.
+ */
+Int2
+pgtype_scale(StatementClass *stmt, Int4 type, int col)
+{
+       switch (type)
+       {
+               case PG_TYPE_NUMERIC:
+                       return getNumericDecimalDigits(stmt, type, col);
+       }
+       return -1;
+}
+
 
 Int2
 pgtype_radix(StatementClass *stmt, Int4 type)
index 6518179..cef2362 100644 (file)
@@ -72,16 +72,22 @@ extern Int2 sqlTypes[];
 
 Int4           sqltype_to_pgtype(StatementClass *stmt, Int2 fSqlType);
 
-Int2           pgtype_to_sqltype(StatementClass *stmt, Int4 type);
+Int2           pgtype_to_concise_type(StatementClass *stmt, Int4 type);
+Int2           pgtype_to_sqldesctype(StatementClass *stmt, Int4 type);
+Int2           pgtype_to_datetime_sub(StatementClass *stmt, Int4 type);
 Int2           pgtype_to_ctype(StatementClass *stmt, Int4 type);
 char      *pgtype_to_name(StatementClass *stmt, Int4 type);
 
 /*     These functions can use static numbers or result sets(col parameter) */
-Int4           pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
+Int4           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_length(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);
+Int4           pgtype_desclength(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
+Int4           pgtype_transfer_octet_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
 
-Int2           pgtype_scale(StatementClass *stmt, Int4 type, int col);
+Int2           pgtype_decimal_digits(StatementClass *stmt, Int4 type, int col); /* corresponds to "scale" in ODBC 2.x */
+Int2           pgtype_scale(StatementClass *stmt, Int4 type, int col); /* ODBC 3.x " */
 Int2           pgtype_radix(StatementClass *stmt, Int4 type);
 Int2           pgtype_nullable(StatementClass *stmt, Int4 type);
 Int2           pgtype_auto_increment(StatementClass *stmt, Int4 type);
index 958a3b6..a0d4be1 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:           See "notice.txt" for copyright and license information.
  *
- * $Id: psqlodbc.h,v 1.60 2002/03/14 05:42:03 inoue Exp $
+ * $Id: psqlodbc.h,v 1.61 2002/03/28 08:08:06 inoue Exp $
  *
  */
 
@@ -91,7 +91,11 @@ typedef UInt4 Oid;
 
 #ifdef WIN32
 #if (ODBCVER >= 0x0300)
+#ifdef UNICODE_SUPPORT
+#define DRIVER_FILE_NAME                       "PSQLODBC30W.DLL"
+#else
 #define DRIVER_FILE_NAME                       "PSQLODBC30.DLL"
+#endif   /* UNICODE_SUPPORT */
 #else
 #define DRIVER_FILE_NAME                       "PSQLODBC.DLL"
 #endif   /* ODBCVER */
@@ -167,6 +171,11 @@ typedef struct EnvironmentClass_ EnvironmentClass;
 typedef struct TupleNode_ TupleNode;
 typedef struct TupleField_ TupleField;
 typedef struct KeySet_ KeySet;
+typedef struct Rollback_ Rollback;
+typedef struct ARDFields_ ARDFields;
+typedef struct APDFields_ APDFields;
+typedef struct IRDFields_ IRDFields;
+typedef struct IPDFields_ IPDFields;
 
 typedef struct col_info COL_INFO;
 typedef struct lo_arg LO_ARG;
@@ -201,25 +210,12 @@ typedef struct StatementOptions_
 {
        int                     maxRows;
        int                     maxLength;
-       int                     rowset_size;
        int                     keyset_size;
        int                     cursor_type;
        int                     scroll_concurrency;
        int                     retrieve_data;
-       int                     bind_size;              /* size of each structure if using Row
-                                                                * Binding */
        int                     use_bookmarks;
-       UInt4      *rowsFetched;
-       UInt2      *rowStatusArray;
-       void       *bookmark_ptr;
-       UInt2      *row_operation_ptr;
-       UInt4      *row_offset_ptr;
-       UInt4           paramset_size;
-       UInt4           param_bind_type;
-       UInt4      *param_processed_ptr;
-       UInt2      *param_status_ptr;
-       UInt2      *param_operation_ptr;
-       UInt4      *param_offset_ptr;
+       void                    *bookmark_ptr;
 } StatementOptions;
 
 /*     Used to pass extra query info to send_query */
@@ -260,6 +256,7 @@ UInt4       ucs2strlen(const SQLWCHAR *ucs2str);
 char   *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen);
 UInt4  utf8_to_ucs2(const char * utf8str, Int4 ilen, SQLWCHAR *ucs2str, UInt4 buflen);
 #endif /* UNICODE_SUPPORT */
+/*#define      _MEMORY_DEBUG_ */
 #ifdef _MEMORY_DEBUG_
 void      *debug_alloc(size_t);
 void      *debug_realloc(void *, size_t);
index 698bd6c..7c99c03 100644 (file)
@@ -138,7 +138,7 @@ BEGIN
                     BS_NOTIFY | WS_TABSTOP,247,205,40,10
 END
 
-DLG_OPTIONS_DS DIALOG DISCARDABLE  0, 0, 267, 176
+DLG_OPTIONS_DS DIALOG DISCARDABLE  0, 0, 267, 196
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "Advanced Options (DataSource)"
 FONT 10, "Terminal"
@@ -155,23 +155,25 @@ BEGIN
                     BS_AUTOCHECKBOX | WS_TABSTOP,45,43,92,10
     CONTROL         "True is -1",DS_TRUEISMINUS1,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,149,43,86,10
-    GROUPBOX        "Protocol",IDC_STATIC,43,59,180,25
+    CONTROL         "(Trial) Updatable cursors",DS_UPDATABLECURSORS,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,45,58,112,10
+    GROUPBOX        "Protocol",IDC_STATIC,43,74,180,25
     CONTROL         "7.X,6.4+",DS_PG64,"Button",BS_AUTORADIOBUTTON | 
-                    WS_GROUP,53,69,47,10
+                    WS_GROUP,53,84,47,10
     CONTROL         "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
-                    131,69,26,10
+                    131,84,26,10
     CONTROL         "6.2",DS_PG62,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
-                    187,69,26,10
-    GROUPBOX        "OID Options",IDC_STATIC,43,89,180,25
+                    187,84,26,10
+    GROUPBOX        "OID Options",IDC_STATIC,43,104,180,25
     CONTROL         "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX | 
-                    WS_GROUP | WS_TABSTOP,53,100,59,10
+                    WS_GROUP | WS_TABSTOP,53,115,59,10
     CONTROL         "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX | 
-                    WS_GROUP | WS_TABSTOP,161,100,55,10
-    LTEXT           "Connect &Settings:",IDC_STATIC,10,120,35,25
-    EDITTEXT        DS_CONNSETTINGS,50,120,200,20,ES_MULTILINE | 
+                    WS_GROUP | WS_TABSTOP,161,115,55,10
+    LTEXT           "Connect &Settings:",IDC_STATIC,10,135,35,25
+    EDITTEXT        DS_CONNSETTINGS,50,135,200,20,ES_MULTILINE | 
                     ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
-    DEFPUSHBUTTON   "OK",IDOK,71,150,50,14,WS_GROUP
-    PUSHBUTTON      "Cancel",IDCANCEL,146,150,50,14
+    DEFPUSHBUTTON   "OK",IDOK,71,165,50,14,WS_GROUP
+    PUSHBUTTON      "Cancel",IDCANCEL,146,165,50,14
 END
 #else
 DLG_CONFIG DIALOG DISCARDABLE  65, 43, 292, 116
@@ -259,7 +261,7 @@ BEGIN
                     BS_NOTIFY | WS_TABSTOP,233,224,40,10
 END
 
-DLG_OPTIONS_DS DIALOG DISCARDABLE  0, 0, 267, 176
+DLG_OPTIONS_DS DIALOG DISCARDABLE  0, 0, 267, 186
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "Advanced Options (DataSource)"
 FONT 8, "MS Sans Serif"
@@ -273,26 +275,28 @@ BEGIN
     CONTROL         "Disallow &Premature",DS_DISALLOWPREMATURE,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,130,25,85,10
     CONTROL         "LF <-> CR/LF convert",DS_LFCONVERSION,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,45,40,92,10
+                    BS_AUTOCHECKBOX | WS_TABSTOP,25,40,92,10
     CONTROL         "True is -1",DS_TRUEISMINUS1,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,149,40,86,10
-    GROUPBOX        "Protocol",IDC_STATIC,15,55,180,25
+                    BS_AUTOCHECKBOX | WS_TABSTOP,130,40,86,10
+    CONTROL         "(Trial) Updatable Cursors",DS_UPDATABLECURSORS,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,25,55,102,10
+    GROUPBOX        "Protocol",IDC_STATIC,15,70,180,25
     CONTROL         "7.X,6.4+",DS_PG64,"Button",BS_AUTORADIOBUTTON | WS_GROUP,25,
-                    65,35,10
+                    80,35,10
     CONTROL         "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
-                    75,65,26,10
+                    75,80,26,10
     CONTROL         "6.2",DS_PG62,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
-                    130,65,26,10
-    GROUPBOX        "OID Options",IDC_STATIC,15,86,180,25
+                    130,80,26,10
+    GROUPBOX        "OID Options",IDC_STATIC,15,101,180,25
     CONTROL         "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX | 
-                    WS_GROUP | WS_TABSTOP,25,96,59,10
+                    WS_GROUP | WS_TABSTOP,25,111,59,10
     CONTROL         "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX | 
-                    WS_GROUP | WS_TABSTOP,115,96,51,10
-    RTEXT           "Connect &Settings:",IDC_STATIC,10,120,35,25
-    EDITTEXT        DS_CONNSETTINGS,50,120,200,20,ES_MULTILINE | 
+                    WS_GROUP | WS_TABSTOP,115,111,51,10
+    RTEXT           "Connect &Settings:",IDC_STATIC,10,135,35,25
+    EDITTEXT        DS_CONNSETTINGS,50,135,200,20,ES_MULTILINE | 
                     ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
-    DEFPUSHBUTTON   "OK",IDOK,71,150,50,14,WS_GROUP
-    PUSHBUTTON      "Cancel",IDCANCEL,146,150,50,14
+    DEFPUSHBUTTON   "OK",IDOK,71,165,50,14,WS_GROUP
+    PUSHBUTTON      "Cancel",IDCANCEL,146,165,50,14
 END
 #endif
 
diff --git a/src/interfaces/odbc/psqlodbc30w.reg b/src/interfaces/odbc/psqlodbc30w.reg
new file mode 100644 (file)
index 0000000..81fd93e
--- /dev/null
@@ -0,0 +1,16 @@
+REGEDIT4\r
+\r
+[HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI]\r
+\r
+[HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\ODBC Drivers]\r
+"PostgreSQL30W"="Installed"\r
+\r
+[HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\PostgreSQL30W]\r
+"APILevel"="1"\r
+"ConnectFunctions"="YYN"\r
+"Driver"="PSQLODBC30W.DLL"\r
+"DriverODBCVer"="03.00"\r
+"FileUsage"="0"\r
+"Setup"="PSQLODBC30W.DLL"\r
+"SQLLevel"="1"\r
+"UsageCount"=dword:00000001\r
index a2031c7..ddc7806 100755 (executable)
@@ -74,9 +74,9 @@ SQLSetDescField @96
 SQLSetDescRec @97
 SQLSetEnvAttr @98
 SQLSetStmtAttr @99
+SQLBulkOperations @100
 
 SQLDummyOrdinal @199
 dconn_FDriverConnectProc @200
 DllMain @201
 ConfigDSN @202
-
index ef7cdfd..86dedae 100644 (file)
@@ -1,4 +1,4 @@
-LIBRARY psqlodbc30
+LIBRARY psqlodbc30w
 EXPORTS
 SQLAllocConnect @1
 SQLAllocEnv @2
@@ -71,6 +71,7 @@ SQLSetDescField @96
 SQLSetDescRec @97
 SQLSetEnvAttr @98
 SQLSetStmtAttr @99
+SQLBulkOperations @100
 
 SQLDummyOrdinal @199
 dconn_FDriverConnectProc @200
index 89ce039..923448a 100644 (file)
@@ -123,6 +123,8 @@ QR_Constructor()
                rv->rowset_size = 1;
                rv->haskeyset = 0;
                rv->keyset = NULL;
+               rv->rb_count = 0;
+               rv->rollback = NULL;
        }
 
        mylog("exit QR_Constructor\n");
@@ -228,6 +230,12 @@ QR_free_memory(QResultClass *self)
                free(self->keyset);
                self->keyset = NULL;
        }
+       if (self->rollback)
+       {
+               free(self->rollback);
+               self->rb_count = 0;
+               self->rollback = NULL;
+       }
 
        self->fcount = 0;
 
@@ -280,6 +288,8 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
                {
                        self->status = PGRES_FIELDS_OK;
                        self->num_fields = CI_get_num_fields(self->fields);
+                       if (self->haskeyset)
+                               self->num_fields -= 2;
                }
                else
                {
@@ -302,15 +312,18 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
                /* allocate memory for the tuple cache */
                mylog("MALLOC: tuple_size = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
                self->count_allocated = 0;
-               self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size);
-               if (self->haskeyset)
-                       self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size);
-               if (!self->backend_tuples)
+               if (self->num_fields > 0)
                {
-                       self->status = PGRES_FATAL_ERROR;
-                       QR_set_message(self, "Could not get memory for tuple cache.");
-                       return FALSE;
+                       self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size);
+                       if (!self->backend_tuples)
+                       {
+                               self->status = PGRES_FATAL_ERROR;
+                               QR_set_message(self, "Could not get memory for tuple cache.");
+                               return FALSE;
+                       }
                }
+               if (self->haskeyset)
+                       self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size);
                self->count_allocated = tuple_size;
 
                self->inTuples = TRUE;
@@ -415,6 +428,7 @@ QR_next_tuple(QResultClass *self)
        char            fetch[128];
        QueryInfo       qi;
        ConnInfo   *ci = NULL;
+       BOOL            set_no_trans;
 
        if (fetch_count < fcount)
        {
@@ -484,12 +498,16 @@ QR_next_tuple(QResultClass *self)
                        if (!self->backend_tuples || self->cache_size > self->count_allocated)
                        {
                                self->count_allocated = 0;
-                               self->backend_tuples = (TupleField *) realloc(self->backend_tuples, self->num_fields * sizeof(TupleField) * self->cache_size);
-                               if (!self->backend_tuples)
+                               if (self->num_fields > 0)
                                {
-                                       self->status = PGRES_FATAL_ERROR;
-                                       QR_set_message(self, "Out of memory while reading tuples.");
-                                       return FALSE;
+                                       self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
+                                               self->num_fields * sizeof(TupleField) * self->cache_size);
+                                       if (!self->backend_tuples)
+                                       {
+                                               self->status = PGRES_FATAL_ERROR;
+                                               QR_set_message(self, "Out of memory while reading tuples.");
+                                               return FALSE;
+                                       }
                                }
                                if (self->haskeyset)
                                        self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * self->cache_size); 
@@ -555,13 +573,16 @@ QR_next_tuple(QResultClass *self)
 
                                        mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
                                        tuple_size *= 2;
-                                       self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
-                                        tuple_size * self->num_fields * sizeof(TupleField));
-                                       if (!self->backend_tuples)
+                                       if (self->num_fields > 0)
                                        {
-                                               self->status = PGRES_FATAL_ERROR;
-                                               QR_set_message(self, "Out of memory while reading tuples.");
-                                               return FALSE;
+                                               self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
+                                                       tuple_size * self->num_fields * sizeof(TupleField));
+                                               if (!self->backend_tuples)
+                                               {
+                                                       self->status = PGRES_FATAL_ERROR;
+                                                       QR_set_message(self, "Out of memory while reading tuples.");
+                                                       return FALSE;
+                                               }
                                        }
                                        if (self->haskeyset)
                                                self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * tuple_size);
@@ -606,8 +627,10 @@ QR_next_tuple(QResultClass *self)
                                QR_set_message(self, msgbuffer);
                                self->status = PGRES_FATAL_ERROR;
 
+                               set_no_trans = FALSE;
                                if (!strncmp(msgbuffer, "FATAL", 5))
-                                       CC_set_no_trans(self->conn);
+                                       set_no_trans = TRUE;
+                               CC_on_abort(self->conn, set_no_trans);
 
                                qlog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
 
@@ -626,7 +649,7 @@ QR_next_tuple(QResultClass *self)
                                qlog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id);
                                QR_set_message(self, "Unexpected result from backend. It probably crashed");
                                self->status = PGRES_FATAL_ERROR;
-                               CC_set_no_trans(self->conn);
+                               CC_on_abort(self->conn, TRUE);
                                return FALSE;
                }
        }
@@ -647,16 +670,21 @@ QR_read_tuple(QResultClass *self, char binary)
        Int2            bitcnt;
        Int4            len;
        char       *buffer;
-       int                     num_fields = self->num_fields;  /* speed up access */
+       int             ci_num_fields = QR_NumResultCols(self); /* speed up access */
+       int             num_fields = self->num_fields;  /* speed up access */
        SocketClass *sock = CC_get_socket(self->conn);
        ColumnInfoClass *flds;
+       int             effective_cols;
+       char            tidoidbuf[32];
 
        /* set the current row to read the fields into */
+       effective_cols = ci_num_fields;
        this_tuplefield = self->backend_tuples + (self->fcount * num_fields);
        if (self->haskeyset)
        {
                this_keyset = self->keyset + self->fcount;
                this_keyset->status = 0;
+               effective_cols -= 2;
        }
 
        bitmaplen = (Int2) num_fields / BYTELEN;
@@ -672,8 +700,9 @@ QR_read_tuple(QResultClass *self, char binary)
        bitmap_pos = 0;
        bitcnt = 0;
        bmp = bitmap[bitmap_pos];
+       flds = self->fields;
 
-       for (field_lf = 0; field_lf < num_fields; field_lf++)
+       for (field_lf = 0; field_lf < ci_num_fields; field_lf++)
        {
                /* Check if the current field is NULL */
                if (!(bmp & 0200))
@@ -692,14 +721,27 @@ QR_read_tuple(QResultClass *self, char binary)
                        if (!binary)
                                len -= VARHDRSZ;
 
-                       buffer = (char *) malloc(len + 1);
+                       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);
 
-                       this_tuplefield[field_lf].len = len;
-                       this_tuplefield[field_lf].value = 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
@@ -710,9 +752,9 @@ QR_read_tuple(QResultClass *self, char binary)
                         * row!
                         */
 
-                       flds = self->fields;
-                       if (flds && flds->display_size && flds->display_size[field_lf] < len)
-                               flds->display_size[field_lf] = len;
+                               if (flds && flds->display_size && flds->display_size[field_lf] < len)
+                                       flds->display_size[field_lf] = len;
+                       }
                }
 
                /*
@@ -728,15 +770,6 @@ QR_read_tuple(QResultClass *self, char binary)
                else
                        bmp <<= 1;
        }
-       if (this_keyset)
-       {
-               if (this_tuplefield[num_fields - 2].value)
-                       sscanf(this_tuplefield[num_fields - 2].value, "(%lu,%hu)",
-                               &this_keyset->blocknum, &this_keyset->offset);
-               if (this_tuplefield[num_fields - 1].value)
-                       sscanf(this_tuplefield[num_fields - 1].value, "%lu",
-                               &this_keyset->oid);
-       }
        self->currTuple++;
        return TRUE;
 }
index dbb6f46..a7291c4 100644 (file)
@@ -73,8 +73,9 @@ struct QResultClass_
                                                                 * progress? */
        char            aborted;                /* was aborted? */
        char            haskeyset;              /* this result contains keyset ? */
-       KeySet          *keyset;        
-       
+       KeySet          *keyset;
+       UInt4           rb_count;       /* count of rollback info */    
+       Rollback        *rollback;      
 };
 
 #define QR_get_fields(self)                                    (self->fields)
index 4cd1639..ac67ad5 100644 (file)
@@ -54,6 +54,7 @@
 #define DS_DISALLOWPREMATURE           1061\r
 #define DS_LFCONVERSION                        1062\r
 #define DS_TRUEISMINUS1                        1063\r
+#define DS_UPDATABLECURSORS            1064\r
 \r
 /*     Next default values for new objects\r */
 /*\r */
@@ -61,7 +62,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS\r
 #define _APS_NEXT_RESOURCE_VALUE               105\r
 #define _APS_NEXT_COMMAND_VALUE                        40001\r
-#define _APS_NEXT_CONTROL_VALUE                        1062\r
+#define _APS_NEXT_CONTROL_VALUE                        1065\r
 #define _APS_NEXT_SYMED_VALUE                  101\r
 #endif   /*\r */
 
index af7c8b3..6d20bba 100644 (file)
@@ -138,7 +138,7 @@ PGAPI_NumResultCols(
                if (stmt->parse_status != STMT_PARSE_FATAL)
                {
                        parse_ok = TRUE;
-                       *pccol = stmt->nfld;
+                       *pccol = SC_get_IRD(stmt)->nfields;
                        mylog("PARSE: PGAPI_NumResultCols: *pccol = %d\n", *pccol);
                }
        }
@@ -189,11 +189,12 @@ PGAPI_DescribeCol(
        /* gets all the information about a specific column */
        StatementClass *stmt = (StatementClass *) hstmt;
        ConnectionClass *conn;
+       IRDFields       *irdflds;
        QResultClass *res;
        char       *col_name = NULL;
        Int4            fieldtype = 0;
-       int                     precision = 0,
-                               scale = 0;
+       int                     column_size = 0,
+                               decimal_digits = 0;
        ConnInfo   *ci;
        char            parse_ok;
        char            buf[255];
@@ -213,6 +214,7 @@ PGAPI_DescribeCol(
 
        SC_clear_error(stmt);
 
+       irdflds = SC_get_IRD(stmt);
 #if (ODBCVER >= 0x0300)
        if (0 == icol) /* bookmark column */
        {
@@ -249,11 +251,11 @@ PGAPI_DescribeCol(
                        parse_statement(stmt);
                }
 
-               mylog("PARSE: DescribeCol: icol=%d, stmt=%u, stmt->nfld=%d, stmt->fi=%u\n", icol, stmt, stmt->nfld, stmt->fi);
+               mylog("PARSE: DescribeCol: icol=%d, stmt=%u, stmt->nfld=%d, stmt->fi=%u\n", icol, stmt, irdflds->nfields, irdflds->fi);
 
-               if (stmt->parse_status != STMT_PARSE_FATAL && stmt->fi && stmt->fi[icol])
+               if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[icol])
                {
-                       if (icol >= stmt->nfld)
+                       if (icol >= irdflds->nfields)
                        {
                                stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
                                stmt->errormsg = "Invalid column number in DescribeCol.";
@@ -262,15 +264,15 @@ PGAPI_DescribeCol(
                        }
                        mylog("DescribeCol: getting info for icol=%d\n", icol);
 
-                       fieldtype = stmt->fi[icol]->type;
-                       if (stmt->fi[icol]->alias[0])
-                               col_name = stmt->fi[icol]->alias;
+                       fieldtype = irdflds->fi[icol]->type;
+                       if (irdflds->fi[icol]->alias[0])
+                               col_name = irdflds->fi[icol]->alias;
                        else
-                               col_name = stmt->fi[icol]->name;
-                       precision = stmt->fi[icol]->precision;
-                       scale = stmt->fi[icol]->scale;
+                               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', precision=%d\n", fieldtype, col_name, precision);
+                       mylog("PARSE: fieldtype=%d, col_name='%s', column_size=%d\n", fieldtype, col_name, column_size);
                        if (fieldtype > 0)
                                parse_ok = TRUE;
                }
@@ -310,13 +312,13 @@ PGAPI_DescribeCol(
                fieldtype = QR_get_field_type(res, icol);
 
                /* atoi(ci->unknown_sizes) */
-               precision = pgtype_precision(stmt, fieldtype, icol, ci->drivers.unknown_sizes);
-               scale = pgtype_scale(stmt, fieldtype, icol);
+               column_size = pgtype_column_size(stmt, fieldtype, icol, ci->drivers.unknown_sizes);
+               decimal_digits = pgtype_decimal_digits(stmt, fieldtype, icol);
        }
 
        mylog("describeCol: col %d fieldname = '%s'\n", icol, col_name);
        mylog("describeCol: col %d fieldtype = %d\n", icol, fieldtype);
-       mylog("describeCol: col %d precision = %d\n", icol, precision);
+       mylog("describeCol: col %d column_size = %d\n", icol, column_size);
 
        result = SQL_SUCCESS;
 
@@ -341,37 +343,37 @@ PGAPI_DescribeCol(
        }
 
        /*
-        * SQL TYPE
+        * CONCISE(SQL) TYPE
         */
        if (pfSqlType)
        {
-               *pfSqlType = pgtype_to_sqltype(stmt, fieldtype);
+               *pfSqlType = pgtype_to_concise_type(stmt, fieldtype);
 
                mylog("describeCol: col %d *pfSqlType = %d\n", icol, *pfSqlType);
        }
 
        /*
-        * PRECISION
+        * COLUMN SIZE(PRECISION in 2.x)
         */
        if (pcbColDef)
        {
-               if (precision < 0)
-                       precision = 0;          /* "I dont know" */
+               if (column_size < 0)
+                       column_size = 0;                /* "I dont know" */
 
-               *pcbColDef = precision;
+               *pcbColDef = column_size;
 
                mylog("describeCol: col %d  *pcbColDef = %d\n", icol, *pcbColDef);
        }
 
        /*
-        * SCALE
+        * DECIMAL DIGITS(SCALE in 2.x)
         */
        if (pibScale)
        {
-               if (scale < 0)
-                       scale = 0;
+               if (decimal_digits < 0)
+                       decimal_digits = 0;
 
-               *pibScale = scale;
+               *pibScale = decimal_digits;
                mylog("describeCol: col %d  *pibScale = %d\n", icol, *pibScale);
        }
 
@@ -380,7 +382,7 @@ PGAPI_DescribeCol(
         */
        if (pfNullable)
        {
-               *pfNullable = (parse_ok) ? stmt->fi[icol]->nullable : pgtype_nullable(stmt, fieldtype);
+               *pfNullable = (parse_ok) ? irdflds->fi[icol]->nullable : pgtype_nullable(stmt, fieldtype);
 
                mylog("describeCol: col %d  *pfNullable = %d\n", icol, *pfNullable);
        }
@@ -402,6 +404,7 @@ PGAPI_ColAttributes(
 {
        static char *func = "PGAPI_ColAttributes";
        StatementClass *stmt = (StatementClass *) hstmt;
+       IRDFields       *irdflds;
        Int4            col_idx, field_type = 0;
        ConnectionClass *conn;
        ConnInfo        *ci;
@@ -414,7 +417,8 @@ PGAPI_ColAttributes(
                                value = 0;
        const   FIELD_INFO      *fi = NULL;
 
-       mylog("%s: entering..col=%d %d.\n", func, icol, fDescType);
+       mylog("%s: entering..col=%d %d len=%d.\n", func, icol, fDescType,
+                               cbDescMax);
 
        if (!stmt)
        {
@@ -422,6 +426,9 @@ PGAPI_ColAttributes(
                return SQL_INVALID_HANDLE;
        }
 
+       if (pcbDesc)
+               *pcbDesc = 0;
+       irdflds = SC_get_IRD(stmt);
        conn = SC_get_conn(stmt);
        ci = &(conn->connInfo);
 
@@ -466,7 +473,7 @@ PGAPI_ColAttributes(
                        parse_statement(stmt);
                }
 
-               cols = stmt->nfld;
+               cols = irdflds->nfields;
 
                /*
                 * Column Count is a special case.      The Column number is ignored
@@ -484,7 +491,7 @@ PGAPI_ColAttributes(
                        return SQL_SUCCESS;
                }
 
-               if (stmt->parse_status != STMT_PARSE_FATAL && stmt->fi && stmt->fi[col_idx])
+               if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[col_idx])
                {
                        if (col_idx >= cols)
                        {
@@ -493,14 +500,14 @@ PGAPI_ColAttributes(
                                SC_log_error(func, "", stmt);
                                return SQL_ERROR;
                        }
-                       field_type = stmt->fi[col_idx]->type;
+                       field_type = irdflds->fi[col_idx]->type;
                        if (field_type > 0)
                                parse_ok = TRUE;
                }
        }
 
        if (parse_ok)
-               fi = stmt->fi[col_idx];
+               fi = irdflds->fi[col_idx];
        else
        {
                SC_pre_execute(stmt);
@@ -542,8 +549,8 @@ PGAPI_ColAttributes(
                }
 
                field_type = QR_get_field_type(SC_get_Curres(stmt), col_idx);
-               if (stmt->parse_status != STMT_PARSE_FATAL && stmt->fi && stmt->fi[col_idx])
-                       fi = stmt->fi[col_idx];
+               if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[col_idx])
+                       fi = irdflds->fi[col_idx];
        }
 
        mylog("colAttr: col %d field_type = %d\n", col_idx, field_type);
@@ -587,15 +594,18 @@ inolog("AUTO_INCREMENT=%d\n", value);
 
 #if (ODBCVER >= 0x0300)
                case SQL_DESC_NAME:
-#endif /* ODBCVER */
+#else
                case SQL_COLUMN_NAME:
+#endif /* ODBCVER */
                        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);
                        break;
 
                case SQL_COLUMN_LENGTH:
-                       value = fi ? fi->length : pgtype_length(stmt, field_type, col_idx, unknown_sizes);
+                       value = (fi && fi->length > 0) ? fi->length : pgtype_buffer_length(stmt, field_type, col_idx, unknown_sizes);
+                       if (value < 0)
+                               value = 0;
 
                        mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value);
                        break;
@@ -607,8 +617,9 @@ inolog("COLUMN_MONEY=%d\n", value);
 
 #if (ODBCVER >= 0x0300)
                case SQL_DESC_NULLABLE:
-#endif /* ODBCVER */
+#else
                case SQL_COLUMN_NULLABLE:
+#endif /* ODBCVER */
                        value = fi ? fi->nullable : pgtype_nullable(stmt, field_type);
 inolog("COLUMN_NULLABLE=%d\n", value);
                        break;
@@ -617,19 +628,23 @@ inolog("COLUMN_NULLABLE=%d\n", value);
                        p = "";
                        break;
 
-               case SQL_COLUMN_PRECISION:
-                       value = fi ? fi->precision : pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
+               case SQL_COLUMN_PRECISION: /* in 2.x */
+                       value = (fi && fi->column_size > 0) ? fi->column_size : pgtype_column_size(stmt, field_type, col_idx, unknown_sizes);
+                       if (value < 0)
+                               value = 0;
 
-                       mylog("PGAPI_ColAttributes: col %d, precision = %d\n", col_idx, value);
+                       mylog("PGAPI_ColAttributes: col %d, column_size = %d\n", col_idx, value);
                        break;
 
                case SQL_COLUMN_QUALIFIER_NAME: /* == SQL_DESC_CATALOG_NAME */
                        p = "";
                        break;
 
-               case SQL_COLUMN_SCALE:
-                       value = pgtype_scale(stmt, field_type, col_idx);
+               case SQL_COLUMN_SCALE: /* in 2.x */
+                       value = pgtype_decimal_digits(stmt, field_type, col_idx);
 inolog("COLUMN_SCALE=%d\n", value);
+                       if (value < 0)
+                               value = 0;
                        break;
 
                case SQL_COLUMN_SEARCHABLE: /* SQL_DESC_SEARCHABLE */
@@ -643,7 +658,7 @@ inolog("COLUMN_SCALE=%d\n", value);
                        break;
 
                case SQL_COLUMN_TYPE: /* == SQL_DESC_CONCISE_TYPE */
-                       value = pgtype_to_sqltype(stmt, field_type);
+                       value = pgtype_to_concise_type(stmt, field_type);
 inolog("COLUMN_TYPE=%d\n", value);
                        break;
 
@@ -678,46 +693,53 @@ inolog("COLUMN_TYPE=%d\n", value);
                        mylog("PGAPI_ColAttr: BASE_COLUMN_NAME = '%s'\n", p);
                        break;
                case SQL_DESC_BASE_TABLE_NAME: /* the same as TABLE_NAME ok ? */
-                       p = fi && (fi->ti) ? fi->ti->name : "";
+                       p = (fi && (fi->ti)) ? fi->ti->name : "";
 
                        mylog("PGAPI_ColAttr: BASE_TABLE_NAME = '%s'\n", p);
                        break;
                case SQL_DESC_LENGTH: /* different from SQL_COLUMN_LENGTH */
-                       value = fi ? fi->length : pgtype_length(stmt, field_type, col_idx, unknown_sizes);
+                       value = (fi && fi->length > 0) ? fi->length : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
+                       if (value < 0)
+                               value = 0;
 
                        mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value);
                        break;
                case SQL_DESC_OCTET_LENGTH:
-                       value = fi ? fi->length : pgtype_length(stmt, field_type, col_idx, unknown_sizes);
-
+                       value = (fi && fi->length > 0) ? fi->length : pgtype_transfer_octet_length(stmt, field_type, col_idx, unknown_sizes);
+                       if (value < 0)
+                               value = 0;
                        mylog("PGAPI_ColAttributes: col %d, octet_length = %d\n", col_idx, value);
                        break;
                case SQL_DESC_PRECISION: /* different from SQL_COLUMN_PRECISION */
-                       value = fi ? fi->precision : pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
+                       value = (fi && fi->column_size > 0) ? fi->column_size : pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
+                       if (value < 0)
+                               value = 0;
 
                        mylog("PGAPI_ColAttributes: col %d, desc_precision = %d\n", col_idx, value);
                        break;
                case SQL_DESC_SCALE: /* different from SQL_COLUMN_SCALE */
                        value = pgtype_scale(stmt, field_type, col_idx);
+                       if (value < 0)
+                               value = 0;
                        break;
                case SQL_DESC_LOCAL_TYPE_NAME:
                        p = pgtype_to_name(stmt, field_type);
                        break;
                case SQL_DESC_TYPE:
-                       value = pgtype_to_sqltype(stmt, field_type);
-                       switch (value)
-                       {
-                               case SQL_TYPE_DATE:
-                               case SQL_TYPE_TIME:
-                               case SQL_TYPE_TIMESTAMP:
-                                       value = SQL_DATETIME;
-                                       break;
-                       }
+                       value = pgtype_to_sqldesctype(stmt, field_type);
+                       break;
+               case SQL_DESC_NUM_PREC_RADIX:
+                       value = pgtype_radix(stmt, field_type);
                        break;
                case SQL_DESC_LITERAL_PREFIX:
+                       p = pgtype_literal_prefix(stmt, field_type);
+                       break;
                case SQL_DESC_LITERAL_SUFFIX:
-               case SQL_DESC_NUM_PREC_RADIX:
+                       p = pgtype_literal_suffix(stmt, field_type);
+                       break;
                case SQL_DESC_UNNAMED:
+                       value = (fi && !fi->name[0] && !fi->alias[0]) ? SQL_UNNAMED : SQL_NAMED;
+                       break;
 #endif /* ODBCVER */
                default:
                        stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
@@ -967,6 +989,7 @@ PGAPI_Fetch(
 {
        static char *func = "PGAPI_Fetch";
        StatementClass *stmt = (StatementClass *) hstmt;
+       ARDFields       *opts;
        QResultClass *res;
 
        mylog("PGAPI_Fetch: stmt = %u, stmt->result= %u\n", stmt, SC_get_Curres(stmt));
@@ -988,7 +1011,8 @@ PGAPI_Fetch(
        }
 
        /* Not allowed to bind a bookmark column when using SQLFetch. */
-       if (stmt->bookmark.buffer)
+       opts = SC_get_ARD(stmt);
+       if (opts->bookmark->buffer)
        {
                stmt->errornumber = STMT_COLNUM_ERROR;
                stmt->errormsg = "Not allowed to bind a bookmark column when using PGAPI_Fetch";
@@ -1012,7 +1036,7 @@ PGAPI_Fetch(
                return SQL_ERROR;
        }
 
-       if (stmt->bindings == NULL)
+       if (opts->bindings == NULL)
        {
                /* just to avoid a crash if the user insists on calling this */
                /* function even if SQL_ExecDirect has reported an Error */
@@ -1040,6 +1064,7 @@ PGAPI_ExtendedFetch(
 {
        static char *func = "PGAPI_ExtendedFetch";
        StatementClass *stmt = (StatementClass *) hstmt;
+       ARDFields       *opts;
        QResultClass *res;
        int                     num_tuples,
                                i,
@@ -1078,11 +1103,12 @@ PGAPI_ExtendedFetch(
                return SQL_ERROR;
        }
 
+       opts = SC_get_ARD(stmt);
        /*
         * If a bookmark colunmn is bound but bookmark usage is off, then
         * error
         */
-       if (stmt->bookmark.buffer && stmt->options.use_bookmarks == SQL_UB_OFF)
+       if (opts->bookmark->buffer && stmt->options.use_bookmarks == SQL_UB_OFF)
        {
                stmt->errornumber = STMT_COLNUM_ERROR;
                stmt->errormsg = "Attempt to retrieve bookmark with bookmark usage disabled";
@@ -1106,7 +1132,7 @@ PGAPI_ExtendedFetch(
                return SQL_ERROR;
        }
 
-       if (stmt->bindings == NULL)
+       if (opts->bindings == NULL)
        {
                /* just to avoid a crash if the user insists on calling this */
                /* function even if SQL_ExecDirect has reported an Error */
@@ -1118,7 +1144,7 @@ PGAPI_ExtendedFetch(
 
        /* Initialize to no rows fetched */
        if (rgfRowStatus)
-               for (i = 0; i < stmt->options.rowset_size; i++)
+               for (i = 0; i < opts->rowset_size; i++)
                        *(rgfRowStatus + i) = SQL_ROW_NOROW;
 
        if (pcrow)
@@ -1144,7 +1170,7 @@ PGAPI_ExtendedFetch(
                                stmt->rowset_start = 0;
 
                        else
-                               stmt->rowset_start += (save_rowset_size > 0 ? save_rowset_size : stmt->options.rowset_size);
+                               stmt->rowset_start += (save_rowset_size > 0 ? save_rowset_size : opts->rowset_size);
 
                        mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
                        break;
@@ -1159,22 +1185,22 @@ PGAPI_ExtendedFetch(
                         */
                        if (stmt->rowset_start >= num_tuples)
                        {
-                               if (stmt->options.rowset_size > num_tuples)
+                               if (opts->rowset_size > num_tuples)
                                {
                                        stmt->errornumber = STMT_POS_BEFORE_RECORDSET;
                                        stmt->errormsg = "fetch prior from eof and before the beggining";
                                }
-                               stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - stmt->options.rowset_size);
+                               stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - opts->rowset_size);
 
                        }
                        else
                        {
-                               if (stmt->rowset_start < stmt->options.rowset_size)
+                               if (stmt->rowset_start < opts->rowset_size)
                                {
                                        stmt->errormsg = "fetch prior and before the beggining";
                                        stmt->errornumber = STMT_POS_BEFORE_RECORDSET;
                                }
-                               stmt->rowset_start -= stmt->options.rowset_size;
+                               stmt->rowset_start -= opts->rowset_size;
                        }
                        break;
 
@@ -1187,7 +1213,7 @@ PGAPI_ExtendedFetch(
                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 - stmt->options.rowset_size);
+                       stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - opts->rowset_size);
                        break;
 
                case SQL_FETCH_ABSOLUTE:
@@ -1255,7 +1281,7 @@ PGAPI_ExtendedFetch(
        /* If *new* rowset is prior to result_set, return no data found */
        if (stmt->rowset_start < 0)
        {
-               if (stmt->rowset_start + stmt->options.rowset_size <= 0)
+               if (stmt->rowset_start + opts->rowset_size <= 0)
                {
                        stmt->rowset_start = -1;
                        return SQL_NO_DATA_FOUND;
@@ -1271,7 +1297,7 @@ PGAPI_ExtendedFetch(
        stmt->currTuple = stmt->rowset_start - 1;
 
        /* increment the base row in the tuple cache */
-       QR_set_rowset_size(res, stmt->options.rowset_size);
+       QR_set_rowset_size(res, opts->rowset_size);
        /* QR_inc_base(res, stmt->last_fetch_count); */
        /* Is inc_base right ? */
        res->base = stmt->rowset_start;
@@ -1281,7 +1307,7 @@ PGAPI_ExtendedFetch(
        mylog("PGAPI_ExtendedFetch: new currTuple = %d\n", stmt->currTuple);
 
        truncated = error = FALSE;
-       for (i = 0; i < stmt->options.rowset_size; i++)
+       for (i = 0; i < opts->rowset_size; i++)
        {
                stmt->bind_row = i;             /* set the binding location */
                result = SC_fetch(stmt);
@@ -1302,11 +1328,14 @@ PGAPI_ExtendedFetch(
 #ifdef DRIVER_CURSOR_IMPLEMENT
                        else if (res->keyset)
                        {
-                               UWORD   pstatus = res->keyset[stmt->currTuple].status & KEYSET_INFO_PUBLIC;
+                               DWORD   currp = stmt->rowset_start + i;
+                               UWORD   pstatus = res->keyset[currp].status & KEYSET_INFO_PUBLIC;
                                if (pstatus != 0)
                                {
                                        rgfRowStatus[i] = pstatus;
-                                       res->keyset[stmt->currTuple].status &= (~KEYSET_INFO_PUBLIC);
+                                       /* refresh the status */
+                                       if (SQL_ROW_DELETED != pstatus)
+                                               res->keyset[currp].status &= (~KEYSET_INFO_PUBLIC);
                                }
                                else
                                        rgfRowStatus[i] = SQL_ROW_SUCCESS;
@@ -1314,6 +1343,8 @@ PGAPI_ExtendedFetch(
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
                        else
                                *(rgfRowStatus + i) = SQL_ROW_SUCCESS;
+if (rgfRowStatus[i] != SQL_ROW_SUCCESS)
+inolog("rgfRowStatus[%d]=%d\n", i, rgfRowStatus[i]);
                }
        }
 
@@ -1374,39 +1405,35 @@ PGAPI_MoreResults(
 /*
  *     Stuff for updatable cursors.
  */
-static const char *getOidValue(const QResultClass *res, int index)
+static Int2    getNumResultCols(const QResultClass *res)
 {
-       return QR_get_value_backend_row(res, index, QR_NumResultCols(res) - 1);
+       Int2    res_cols = QR_NumResultCols(res);
+       return res->keyset ? res_cols - 2 : res_cols;
 }
 static UInt4   getOid(const QResultClass *res, int index)
 {
        return res->keyset[index].oid;
 }
-static const char *getTidValue(const QResultClass *res, int index)
-{
-       return QR_get_value_backend_row(res, index, QR_NumResultCols(res) - 2);
-}
 static void getTid(const QResultClass *res, int index, UInt4 *blocknum, UInt2 *offset)
 {
        *blocknum = res->keyset[index].blocknum;
        *offset = res->keyset[index].offset;
 }
-static void KeySetSet(const QResultClass *res, int index)
+static void KeySetSet(const TupleField *tuple, int num_fields, KeySet *keyset)
 {
-       int             num_fields = res->num_fields;
-       TupleField      *tuple = res->backend_tuples + num_fields * index;
-       KeySet          *keyset = res->keyset + index;
-
        sscanf(tuple[num_fields - 2].value, "(%u,%hu)",
                        &keyset->blocknum, &keyset->offset);
        sscanf(tuple[num_fields - 1].value, "%u", &keyset->oid);
 }
 
+#define        LATEST_TUPLE_LOAD       1L
+#define        USE_INSERTED_TID        (1L << 1)
 static QResultClass *
-positioned_load(StatementClass *stmt, BOOL latest, int res_cols, UInt4 oid, const char *tidval)
+positioned_load(StatementClass *stmt, UInt4 flag, UInt4 oid, const char *tidval)
 {
        QResultClass *qres;
        char    *selstr;
+       BOOL    latest = ((flag & LATEST_TUPLE_LOAD) != 0);
        UInt4   len;
 
        len = strlen(stmt->load_statement);
@@ -1419,6 +1446,12 @@ positioned_load(StatementClass *stmt, BOOL latest, int res_cols, UInt4 oid, cons
                else 
                        sprintf(selstr, "%s where ctid = '%s' and oid = %u", stmt->load_statement, tidval, oid); 
        }
+       else if ((flag & USE_INSERTED_TID) != 0)
+       {
+               len += 50;
+               selstr = malloc(len);
+               sprintf(selstr, "%s where ctid = currtid(0, '(,)') and oid = %u", stmt->load_statement, oid);
+       } 
        else
        {
                len += 20;
@@ -1428,23 +1461,24 @@ positioned_load(StatementClass *stmt, BOOL latest, int res_cols, UInt4 oid, cons
 
        mylog("selstr=%s\n", selstr);
        qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, CLEAR_RESULT_ON_ABORT);
-free(selstr);
+       free(selstr);
        return qres;
 }
 
 RETCODE                SQL_API
-SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
+SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count)
 {
        int                     i,
                                res_cols;
-       UWORD           rcnt, global_ridx, offset;
+       UWORD           rcnt, offset;
        UInt4           oid, blocknum;
        QResultClass *res,
                           *qres;
+       IRDFields       *irdflds = SC_get_IRD(stmt);
        RETCODE         ret = SQL_ERROR;
        char            tidval[32];
 
-       mylog("positioned load fi=%x ti=%x\n", stmt->fi, stmt->ti);
+       mylog("positioned load fi=%x ti=%x\n", irdflds->fi, stmt->ti);
        rcnt = 0;
        if (count)
                *count = 0;
@@ -1452,23 +1486,18 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
                return SQL_ERROR;
        if (!stmt->ti)
                parse_statement(stmt);  /* not preferable */
-       if (!stmt->ti || stmt->ntab != 1)
+       if (!stmt->updatable)
        {
                stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
                return SQL_ERROR;
        }
        global_ridx = irow + stmt->rowset_start;
-       res_cols = QR_NumResultCols(res);
        if (!(oid = getOid(res, global_ridx)))
                return SQL_SUCCESS_WITH_INFO;
        getTid(res, global_ridx, &blocknum, &offset);
        sprintf(tidval, "(%u, %u)", blocknum, offset);
-       /*if (!(oidval = getOidValue(res, global_ridx)))
-               return SQL_SUCCESS_WITH_INFO;
-       sscanf(oidval, "%u", &oid);
-       tidval = getTidValue(res, global_ridx);*/
-       res_cols -= 2;
-       if (qres = positioned_load(stmt, TRUE, res_cols, oid, tidval), qres)
+       res_cols = getNumResultCols(res);
+       if (qres = positioned_load(stmt, LATEST_TUPLE_LOAD, oid, tidval), qres)
        {
                TupleField *tupleo, *tuplen;
 
@@ -1476,9 +1505,18 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
                tupleo = res->backend_tuples + res->num_fields * global_ridx;
                if (rcnt == 1)
                {
+                       int     effective_fields = res_cols;
+
                        QR_set_position(qres, 0);
                        tuplen = qres->tupleField;
-                       for (i = 0; i < res->num_fields; i++)
+                       if (res->keyset)
+                       {
+                               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);
@@ -1487,13 +1525,6 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
                                tupleo[i].value = tuplen[i].value;
                                tuplen[i].value = NULL;
                        }
-                       if (res->keyset)
-                       {
-                               if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
-                                       strcmp(tupleo[res->num_fields - 2].value, tidval))
-                                       res->keyset[global_ridx].status |= SQL_ROW_UPDATED;
-                               KeySetSet(res, global_ridx);
-                       }
                        ret = SQL_SUCCESS;
                }
                else
@@ -1503,10 +1534,7 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
                        ret = SQL_SUCCESS_WITH_INFO;
                        if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
                        {
-                               if (tupleo[res_cols + 1].value)
-                                       free(tupleo[res_cols + 1].value);
-                               tupleo[res_cols + 1].value = NULL;
-                               tupleo[res_cols + 1].len = 0;
+                               res->keyset[global_ridx].oid = 0;
                                res->keyset[global_ridx].status |= SQL_ROW_DELETED;
                        }
                }
@@ -1520,24 +1548,23 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
 }
 
 RETCODE                SQL_API
-SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
+SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
 {
        int                     i;
-       QResultClass *res,
-                          *qres;
+       QResultClass *res, *qres;
        RETCODE         ret = SQL_ERROR;
 
-       mylog("positioned new fi=%x ti=%x\n", stmt->fi, stmt->ti);
+       mylog("positioned new ti=%x\n", stmt->ti);
        if (!(res = SC_get_Curres(stmt)))
                return SQL_ERROR;
        if (!stmt->ti)
                parse_statement(stmt);  /* not preferable */
-       if (!stmt->ti || stmt->ntab != 1)
+       if (!stmt->updatable)
        {
                stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
                return SQL_ERROR;
        }
-       if (qres = positioned_load(stmt, TRUE, QR_NumResultCols(res) - 2, oid, tidval), qres)
+       if (qres = positioned_load(stmt, tidRef ? USE_INSERTED_TID : 0, oid, NULL), qres)
        {
                TupleField *tupleo, *tuplen;
                int                     count = QR_get_num_tuples(qres);
@@ -1545,6 +1572,8 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
                QR_set_position(qres, 0);
                if (count == 1)
                {
+                       int     effective_fields = res->num_fields;
+
                        tuplen = qres->tupleField;
                        if (res->fcount >= res->count_allocated)
                        {
@@ -1569,22 +1598,29 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
                                res->count_allocated = tuple_size;
                        }
                        tupleo = res->backend_tuples + res->num_fields * res->fcount;
-                       for (i = 0; i < res->num_fields; i++)
+                       KeySetSet(tuplen, qres->num_fields, res->keyset + res->fcount);
+                       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;
                        }
-                       KeySetSet(res, res->fcount);
+                       for (; i < res->num_fields; i++)
+                       {
+                               tupleo[i].len = 0;
+                               tupleo[i].value = NULL;
+                       }
                        res->fcount++;
                        ret = SQL_SUCCESS;
                }
+               else if (0 == count)
+                       ret = SQL_NO_DATA_FOUND;
                else
                {
                        stmt->errornumber = STMT_ROW_VERSION_CHANGED;
-                       stmt->errormsg = "the content was changed before updation";
-                       ret = SQL_SUCCESS_WITH_INFO;
+                       stmt->errormsg = "the driver cound't identify inserted rows";
+                       ret = SQL_ERROR;
                }
                QR_Destructor(qres);
                /* stmt->currTuple = stmt->rowset_start + irow; */
@@ -1593,7 +1629,7 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval)
 }
 
 static RETCODE SQL_API
-irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow)
+irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow, UDWORD global_ridx)
 {
        if (ret != SQL_ERROR)
        {
@@ -1604,18 +1640,17 @@ irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow
                        sscanf(cmdstr, "UPDATE %d", &updcnt) == 1)
                {
                        if (updcnt == 1)
-                               SC_pos_reload(stmt, irow, (UWORD *) 0);
+                               SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0);
                        else if (updcnt == 0)
                        {
                                stmt->errornumber = STMT_ROW_VERSION_CHANGED;
                                stmt->errormsg = "the content was changed before updation";
                                ret = SQL_ERROR;
                                if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
-                                       SC_pos_reload(stmt, irow, (UWORD *) 0);
+                                       SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0);
                        }
                        else
                                ret = SQL_ERROR;
-                       stmt->currTuple = stmt->rowset_start + irow;
                }
                else
                        ret = SQL_ERROR;
@@ -1627,62 +1662,60 @@ irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow
        }
        return ret;
 }
-RETCODE                SQL_API
+RETCODE
 SC_pos_update(StatementClass *stmt,
-                         UWORD irow)
+                         UWORD irow, UDWORD global_ridx)
 {
        int                     i,
-                               res_cols,
                                num_cols,
                                upd_cols;
-       UWORD           global_ridx;
        QResultClass *res;
-       BindInfoClass *bindings = stmt->bindings;
+       ARDFields       *opts = SC_get_ARD(stmt);
+       IRDFields       *irdflds = SC_get_IRD(stmt);
+       BindInfoClass *bindings = opts->bindings;
+       FIELD_INFO      **fi = SC_get_IRD(stmt)->fi;
        char            updstr[4096];
        RETCODE         ret;
        UInt4   oid, offset, blocknum;
        UInt2   pgoffset;
-       Int4    *used;
+       Int4    *used, bind_size = opts->bind_size;
 
-       mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, SC_get_Curres(stmt)->base, stmt->fi, stmt->ti);
+       mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, SC_get_Curres(stmt)->base,fi, stmt->ti);
        if (!(res = SC_get_Curres(stmt)))
                return SQL_ERROR;
        if (!stmt->ti)
                parse_statement(stmt);  /* not preferable */
-       if (!stmt->ti || stmt->ntab != 1)
+       if (!stmt->updatable)
        {
                stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
                return SQL_ERROR;
        }
-       global_ridx = irow + stmt->rowset_start;
-       res_cols = QR_NumResultCols(res);
-       /*if (!(oidval = getOidValue(res, global_ridx)))*/
        if (!(oid = getOid(res, global_ridx)))
        {
                stmt->errormsg = "The row is already deleted";
                return SQL_ERROR;
        }
-       /*tidval = getTidValue(res, global_ridx);*/
        getTid(res, global_ridx, &blocknum, &pgoffset);
 
        sprintf(updstr, "update \"%s\" set", stmt->ti[0]->name);
-       num_cols = stmt->nfld;
-       if (stmt->options.row_offset_ptr)
-               offset = *stmt->options.row_offset_ptr;
-       else
-               offset = 0;
+       num_cols = irdflds->nfields;
+       offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
        for (i = upd_cols = 0; i < num_cols; i++)
        {
                if (used = bindings[i].used, used != NULL)
                {
                        used += (offset >> 2);
-                       mylog("%d used=%d\n", i, *used);
-                       if (*used != SQL_IGNORE)
+                       if (bind_size > 0)
+                               used += (bind_size * irow / 4);
+                       else    
+                               used += irow; 
+                       mylog("%d used=%d,%x\n", i, *used, used);
+                       if (*used != SQL_IGNORE && fi[i]->updatable)
                        {
                                if (upd_cols)
-                                       sprintf(updstr, "%s, \"%s\" = ?", updstr, stmt->fi[i]->name);
+                                       sprintf(updstr, "%s, \"%s\" = ?", updstr, fi[i]->name);
                                else
-                                       sprintf(updstr, "%s \"%s\" = ?", updstr, stmt->fi[i]->name);
+                                       sprintf(updstr, "%s \"%s\" = ?", updstr, fi[i]->name);
                                upd_cols++;
                        }
                }
@@ -1695,6 +1728,7 @@ SC_pos_update(StatementClass *stmt,
                int                     j;
                int                     res_cols = QR_NumResultCols(res);
                StatementClass *qstmt;
+               APDFields       *apdopts;
 
                /*sprintf(updstr, "%s where ctid = '%s' and oid = %s", updstr,
                                tidval, oidval);*/
@@ -1704,21 +1738,26 @@ SC_pos_update(StatementClass *stmt,
                if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS)
                        return SQL_ERROR;
                qstmt = (StatementClass *) hstmt;
-               qstmt->options.param_bind_type = stmt->options.bind_size;
-               qstmt->options.param_offset_ptr = stmt->options.row_offset_ptr;
+               apdopts = SC_get_APD(qstmt);
+               apdopts->param_bind_type = opts->bind_size;
+               apdopts->param_offset_ptr = opts->row_offset_ptr;
                for (i = j = 0; i < num_cols; i++)
                {
                        if (used = bindings[i].used, used != NULL)
                        {
                                used += (offset >> 2);
+                               if (bind_size > 0)
+                                       used += (bind_size * irow / 4);
+                               else
+                                       used += irow;
                                mylog("%d used=%d\n", i, *used);
-                               if (*used != SQL_IGNORE)
+                               if (*used != SQL_IGNORE && fi[i]->updatable)
                                {
                                        PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++j,
                                                                 SQL_PARAM_INPUT, bindings[i].returntype,
-                                         pgtype_to_sqltype(stmt, QR_get_field_type(res, i)),
+                                         pgtype_to_concise_type(stmt, QR_get_field_type(res, i)),
                                                                                QR_get_fieldsize(res, i),
-                                                                       (SQLSMALLINT) stmt->fi[i]->precision,
+                                                                       (SQLSMALLINT) fi[i]->decimal_digits,
                                                                                bindings[i].buffer,
                                                                                bindings[i].buflen,
                                                                                bindings[i].used);
@@ -1739,55 +1778,61 @@ SC_pos_update(StatementClass *stmt,
                        stmt->errormsg = "SetPos with data_at_exec not yet supported";
                        ret = SQL_ERROR;
                }
-               ret = irow_update(ret, stmt, qstmt, irow);
+               ret = irow_update(ret, stmt, qstmt, irow, global_ridx);
                PGAPI_FreeStmt(hstmt, SQL_DROP);
        }
        else
+       {
                ret = SQL_SUCCESS_WITH_INFO;
+               stmt->errormsg = "update list null";
+       }
        if (SQL_SUCCESS == ret && res->keyset)
-               res->keyset[global_ridx].status |= (SQL_ROW_UPDATED | DRV_SELF_UPDATED);
+       {
+               if (CC_is_in_trans(SC_get_conn(stmt)))
+                       res->keyset[global_ridx].status |= (SQL_ROW_UPDATED  | CURS_SELF_UPDATING);
+               else
+                       res->keyset[global_ridx].status |= (SQL_ROW_UPDATED  | CURS_SELF_UPDATED);
+       }
 #if (ODBCVER >= 0x0300)
-       if (stmt->options.rowStatusArray)
+       if (irdflds->rowStatusArray)
        {
                switch (ret)
                {
                        case SQL_SUCCESS:
-                               stmt->options.rowStatusArray[irow] = SQL_ROW_UPDATED;
+                               irdflds->rowStatusArray[irow] = SQL_ROW_UPDATED;
                                break;
                        default:
-                               stmt->options.rowStatusArray[irow] = ret;
+                               irdflds->rowStatusArray[irow] = ret;
                }
        }
 #endif /* ODBCVER */
 
        return ret;
 }
-RETCODE                SQL_API
+RETCODE
 SC_pos_delete(StatementClass *stmt,
-                         UWORD irow)
+                         UWORD irow, UDWORD global_ridx)
 {
-       int                     res_cols;
-       UWORD           global_ridx, offset;
+       UWORD           offset;
        QResultClass *res, *qres;
-       BindInfoClass *bindings = stmt->bindings;
+       ARDFields       *opts = SC_get_ARD(stmt);
+       IRDFields       *irdflds = SC_get_IRD(stmt);
+       BindInfoClass *bindings = opts->bindings;
        char            dltstr[4096];
        RETCODE         ret;
        /*const char       *oidval;*/
        UInt4           oid, blocknum;
 
-       mylog("POS DELETE fi=%x ti=%x\n", stmt->fi, stmt->ti);
+       mylog("POS DELETE ti=%x\n", stmt->ti);
        if (!(res = SC_get_Curres(stmt)))
                return SQL_ERROR;
        if (!stmt->ti)
                parse_statement(stmt);  /* not preferable */
-       if (!stmt->ti || stmt->ntab != 1)
+       if (!stmt->updatable)
        {
                stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
                return SQL_ERROR;
        }
-       res_cols = QR_NumResultCols(res);
-       global_ridx = irow + stmt->rowset_start;
-       /* if (!(oidval = getOidValue(res, global_ridx)))*/
        if (!(oid = getOid(res, global_ridx)))
        {
                stmt->errormsg = "The row is already deleted";
@@ -1810,18 +1855,17 @@ SC_pos_delete(StatementClass *stmt,
                        sscanf(cmdstr, "DELETE %d", &dltcnt) == 1)
                {
                        if (dltcnt == 1)
-                               SC_pos_reload(stmt, irow, (UWORD *) 0);
+                               SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0);
                        else if (dltcnt == 0)
                        {
                                stmt->errornumber = STMT_ROW_VERSION_CHANGED;
                                stmt->errormsg = "the content was changed before deletion";
                                ret = SQL_ERROR;
                                if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
-                                       SC_pos_reload(stmt, irow, (UWORD *) 0);
+                                       SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0);
                        }
                        else
                                ret = SQL_ERROR;
-                       stmt->currTuple = stmt->rowset_start + irow;
                }
                else
                        ret = SQL_ERROR;
@@ -1836,17 +1880,22 @@ SC_pos_delete(StatementClass *stmt,
        if (qres)
                QR_Destructor(qres);
        if (SQL_SUCCESS == ret && res->keyset)
-               res->keyset[global_ridx].status |= (SQL_ROW_DELETED | DRV_SELF_DELETED);
+       {
+               if (CC_is_in_trans(SC_get_conn(stmt)))
+                       res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETING);
+               else
+                       res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED);
+       }
 #if (ODBCVER >= 0x0300)
-       if (stmt->options.rowStatusArray)
+       if (irdflds->rowStatusArray)
        {
                switch (ret)
                {
                        case SQL_SUCCESS:
-                               stmt->options.rowStatusArray[irow] = SQL_ROW_DELETED;
+                               irdflds->rowStatusArray[irow] = SQL_ROW_DELETED;
                                break;
                        default:
-                               stmt->options.rowStatusArray[irow] = ret;
+                               irdflds->rowStatusArray[irow] = ret;
                }
        }
 #endif /* ODBCVER */
@@ -1858,24 +1907,42 @@ irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, int addpos
 {
        if (ret != SQL_ERROR)
        {
-               int                     addcnt;
+               int             addcnt;
                UInt4           oid;
-               const char *cmdstr = QR_get_command(SC_get_Curres(istmt));
+               ARDFields       *opts = SC_get_ARD(stmt);
+               QResultClass    *ires = SC_get_Curres(istmt);
+               const char *cmdstr;
 
+               cmdstr = QR_get_command((ires->next ? ires->next : ires));
                if (cmdstr &&
                        sscanf(cmdstr, "INSERT %u %d", &oid, &addcnt) == 2 &&
                        addcnt == 1)
                {
-                       SC_pos_newload(stmt, oid, NULL);
-                       if (stmt->bookmark.buffer)
+                       ConnectionClass *conn = SC_get_conn(stmt);
+                       RETCODE qret;
+
+                       qret = SQL_NO_DATA_FOUND;
+                       if (PG_VERSION_GE(conn, 7.2))
+                       {
+                               qret = SC_pos_newload(stmt, oid, TRUE);
+                               if (SQL_ERROR == qret)
+                                       return qret;
+                       }
+                       if (SQL_NO_DATA_FOUND == qret)
+                       {
+                               qret = SC_pos_newload(stmt, oid, FALSE);
+                               if (SQL_ERROR == qret)
+                                       return qret;
+                       }
+                       if (opts->bookmark->buffer)
                        {
                                char    buf[32];
-                               UInt4   offset = stmt->options.row_offset_ptr ? *stmt->options.row_offset_ptr : 0;
+                               UInt4   offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
 
                                sprintf(buf, "%ld", addpos + 1);
                                copy_and_convert_field(stmt, 0, buf,
-                                       SQL_C_ULONG, stmt->bookmark.buffer + offset,
-                                       0, stmt->bookmark.used ? stmt->bookmark.used
+                                       SQL_C_ULONG, opts->bookmark->buffer + offset,
+                                       0, opts->bookmark->used ? opts->bookmark->used
                                        + (offset >> 2) : NULL);
                        }
                }
@@ -1887,7 +1954,7 @@ irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, int addpos
        }
        return ret;
 }
-RETCODE                SQL_API
+RETCODE
 SC_pos_add(StatementClass *stmt,
                   UWORD irow)
 {
@@ -1896,51 +1963,62 @@ SC_pos_add(StatementClass *stmt,
                                i;
        HSTMT           hstmt;
        StatementClass *qstmt;
+       ConnectionClass *conn;
        QResultClass *res;
-       BindInfoClass *bindings = stmt->bindings;
+       ARDFields       *opts = SC_get_ARD(stmt);
+       IRDFields       *irdflds = SC_get_IRD(stmt);
+       APDFields       *apdopts;
+       BindInfoClass *bindings = opts->bindings;
+       FIELD_INFO      **fi = SC_get_IRD(stmt)->fi;
        char            addstr[4096];
        RETCODE         ret;
        UInt4           offset;
-       Int4            *used;
+       Int4            *used, bind_size = opts->bind_size;
 
-       mylog("POS ADD fi=%x ti=%x\n", stmt->fi, stmt->ti);
+       mylog("POS ADD fi=%x ti=%x\n", fi, stmt->ti);
        if (!(res = SC_get_Curres(stmt)))
                return SQL_ERROR;
        if (!stmt->ti)
                parse_statement(stmt);  /* not preferable */
-       if (!stmt->ti || stmt->ntab != 1)
+       if (!stmt->updatable)
        {
                stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
                return SQL_ERROR;
        }
-       num_cols = stmt->nfld;
+       num_cols = irdflds->nfields;
+       conn = SC_get_conn(stmt);
        sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name);
        if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS)
                return SQL_ERROR;
-       if (stmt->options.row_offset_ptr)
-               offset = *stmt->options.row_offset_ptr;
+       if (opts->row_offset_ptr)
+               offset = *opts->row_offset_ptr;
        else
                offset = 0;
        qstmt = (StatementClass *) hstmt;
-       qstmt->options.param_bind_type = stmt->options.bind_size;
-       qstmt->options.param_offset_ptr = stmt->options.row_offset_ptr;
+       apdopts = SC_get_APD(qstmt);
+       apdopts->param_bind_type = opts->bind_size;
+       apdopts->param_offset_ptr = opts->row_offset_ptr;
        for (i = add_cols = 0; i < num_cols; i++)
        {
                if (used = bindings[i].used, used != NULL)
                {
                        used += (offset >> 2);
+                       if (bind_size > 0)
+                               used += (bind_size * irow / 4);
+                       else
+                               used += irow;
                        mylog("%d used=%d\n", i, *used);
-                       if (*used != SQL_IGNORE)
+                       if (*used != SQL_IGNORE && fi[i]->updatable)
                        {
                                if (add_cols)
-                                       sprintf(addstr, "%s, \"%s\"", addstr, stmt->fi[i]->name);
+                                       sprintf(addstr, "%s, \"%s\"", addstr, fi[i]->name);
                                else
-                                       sprintf(addstr, "%s\"%s\"", addstr, stmt->fi[i]->name);
+                                       sprintf(addstr, "%s\"%s\"", addstr, fi[i]->name);
                                PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++add_cols,
                                                                 SQL_PARAM_INPUT, bindings[i].returntype,
-                                         pgtype_to_sqltype(stmt, QR_get_field_type(res, i)),
+                                         pgtype_to_concise_type(stmt, QR_get_field_type(res, i)),
                                                                        QR_get_fieldsize(res, i),
-                                                                       (SQLSMALLINT) stmt->fi[i]->precision,
+                                                                       (SQLSMALLINT) fi[i]->decimal_digits,
                                                                        bindings[i].buffer,
                                                                        bindings[i].buflen,
                                                                        bindings[i].used);
@@ -1983,20 +2061,28 @@ SC_pos_add(StatementClass *stmt,
                stmt->bind_row = brow_save; 
        }
        else
+       {
                ret = SQL_SUCCESS_WITH_INFO;
+               stmt->errormsg = "insert list null";
+       }
        PGAPI_FreeStmt(hstmt, SQL_DROP);
        if (SQL_SUCCESS == ret && res->keyset)
-               res->keyset[res->fcount - 1].status |= DRV_SELF_ADDED;
+       {
+               if (CC_is_in_trans(conn))
+                       res->keyset[res->fcount - 1].status |= (SQL_ROW_ADDED | CURS_SELF_ADDING);
+               else
+                       res->keyset[res->fcount - 1].status |= (SQL_ROW_ADDED | CURS_SELF_ADDED);
+       }
 #if (ODBCVER >= 0x0300)
-       if (stmt->options.rowStatusArray)
+       if (irdflds->rowStatusArray)
        {
                switch (ret)
                {
                        case SQL_SUCCESS:
-                               stmt->options.rowStatusArray[irow] = SQL_ROW_ADDED;
+                               irdflds->rowStatusArray[irow] = SQL_ROW_ADDED;
                                break;
                        default:
-                               stmt->options.rowStatusArray[irow] = ret;
+                               irdflds->rowStatusArray[irow] = ret;
                }
        }
 #endif /* ODBCVER */
@@ -2009,6 +2095,47 @@ SC_pos_add(StatementClass *stmt,
  */
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
 
+RETCODE
+SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx)
+{
+       RETCODE ret;
+#if (ODBCVER >= 0x0300)
+       IRDFields       *irdflds = SC_get_IRD(stmt);
+#endif /* ODBCVER */
+       /* save the last_fetch_count */
+       int             last_fetch = stmt->last_fetch_count;
+       int             bind_save = stmt->bind_row;
+
+#ifdef DRIVER_CURSOR_IMPLEMENT
+       if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
+               SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0);
+#endif   /* DRIVER_CURSOR_IMPLEMENT */
+       stmt->bind_row = irow;
+       ret = SC_fetch(stmt);
+       /* restore the last_fetch_count */
+       stmt->last_fetch_count = last_fetch;
+       stmt->bind_row = bind_save;
+#if (ODBCVER >= 0x0300)
+       if (irdflds->rowStatusArray)
+       {
+               switch (ret)
+               {
+                       case SQL_ERROR:
+                               irdflds->rowStatusArray[irow] = SQL_ROW_ERROR;
+                               break;
+                       case SQL_SUCCESS:
+                               irdflds->rowStatusArray[irow] = SQL_ROW_SUCCESS;
+                               break;
+                       default:
+                               irdflds->rowStatusArray[irow] = ret;
+                               break;
+               }
+       }
+#endif /* ODBCVER */
+
+       return SQL_SUCCESS;
+}
+
 /*
  *     This positions the cursor within a rowset, that was positioned using SQLExtendedFetch.
  *     This will be useful (so far) only when using SQLGetData after SQLExtendedFetch.
@@ -2023,10 +2150,13 @@ PGAPI_SetPos(
        static char *func = "PGAPI_SetPos";
        RETCODE ret;
        StatementClass *stmt = (StatementClass *) hstmt;
+       ConnectionClass *conn = SC_get_conn(stmt);
        QResultClass *res;
-       int                     num_cols,
-                               i;
-       BindInfoClass *bindings = stmt->bindings;
+       int             num_cols, i, start_row, end_row, processed;
+       ARDFields       *opts;
+       BindInfoClass *bindings;
+       UDWORD          global_ridx, fcount;
+       BOOL            auto_commit_needed = FALSE;
 
        if (!stmt)
        {
@@ -2034,6 +2164,8 @@ PGAPI_SetPos(
                return SQL_INVALID_HANDLE;
        }
 
+       opts = SC_get_ARD(stmt);
+       bindings = opts->bindings;
 #ifdef DRIVER_CURSOR_IMPLEMENT
        mylog("%s fOption=%d irow=%d lock=%d currt=%d\n", func, fOption, irow, fLock, stmt->currTuple);
        if (stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
@@ -2055,12 +2187,9 @@ PGAPI_SetPos(
                SC_log_error(func, "", stmt);
                return SQL_ERROR;
        }
-       num_cols = QR_NumResultCols(res);
 
        if (irow == 0) /* bulk operation */
        {
-               int     processed;
-
                if (SQL_POSITION == fOption)
                {
                        stmt->errornumber = STMT_ROW_OUT_OF_RANGE;
@@ -2068,78 +2197,86 @@ PGAPI_SetPos(
                        SC_log_error(func, "", stmt);
                        return SQL_ERROR;
                }
-               ret = SQL_SUCCESS;
-               for (i = 0, processed = 0; i < stmt->options.rowset_size; i++)
-               {
-#if (ODBCVER >= 0x0300)
-                       if (!stmt->options.row_operation_ptr || stmt->options.row_operation_ptr[i] == SQL_ROW_PROCEED)
-                       {
-#endif /* ODBCVER */
-                               if (ret = PGAPI_SetPos(hstmt, (UWORD) (i + 1), fOption, fLock), SQL_ERROR == ret)
-                                       break;
-                               processed++;
-#if (ODBCVER >= 0x0300)
-                       }
-#endif /* ODBCVER */
-               }
-               if (processed > 0 && SQL_ERROR == ret)
-               {
-                       processed++;
-                       ret = SQL_SUCCESS_WITH_INFO;
-                       stmt->errornumber = STMT_ERROR_IN_ROW;
-               }
-               if (stmt->options.rowsFetched)
-                       *stmt->options.rowsFetched = processed;
-               return ret; 
+               start_row = 0;
+               end_row = opts->rowset_size - 1;
        }
-
-       if (irow > stmt->last_fetch_count)
+       else
        {
-               stmt->errornumber = STMT_ROW_OUT_OF_RANGE;
-               stmt->errormsg = "Row value out of range";
-               SC_log_error(func, "", stmt);
-               return SQL_ERROR;
+               if (irow > stmt->last_fetch_count)
+               {
+                       stmt->errornumber = STMT_ROW_OUT_OF_RANGE;
+                       stmt->errormsg = "Row value out of range";
+                       SC_log_error(func, "", stmt);
+                       return SQL_ERROR;
+               }
+               start_row = end_row = irow - 1;
        }
 
-       irow--;
-
+       num_cols = QR_NumResultCols(res);
+       /* Reset for SQLGetData */
+       if (bindings)
+               for (i = 0; i < num_cols; i++)
+                       bindings[i].data_left = -1;
+       ret = SQL_SUCCESS;
+       fcount = res->fcount;
 #ifdef DRIVER_CURSOR_IMPLEMENT
        switch (fOption)
        {
                case SQL_UPDATE:
-                       return SC_pos_update(stmt, irow);
                case SQL_DELETE:
-                       return SC_pos_delete(stmt, irow);
                case SQL_ADD:
-                       return SC_pos_add(stmt, irow);
+                       if (auto_commit_needed = CC_is_in_autocommit(conn), auto_commit_needed)
+                               PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
+                       break;
        }
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
-       /* Reset for SQLGetData */
-       for (i = 0; i < num_cols; i++)
-               bindings[i].data_left = -1;
-
-       if (fOption == SQL_REFRESH)
+       for (i = start_row, processed = 0; i <= end_row; i++)
        {
-               /* save the last_fetch_count */
-               int                     last_fetch = stmt->last_fetch_count;
-               int                     bind_save = stmt->bind_row;
-
+#if (ODBCVER >= 0x0300)
+               if (0 != irow || !opts->row_operation_ptr || opts->row_operation_ptr[i] == SQL_ROW_PROCEED)
+               {
+#endif /* ODBCVER */
+                       global_ridx = i + stmt->rowset_start;
+                       switch (fOption)
+                       {
 #ifdef DRIVER_CURSOR_IMPLEMENT
-               if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
-                       SC_pos_reload(stmt, irow, (UWORD *) 0);
+                               case SQL_UPDATE:
+                                       ret = SC_pos_update(stmt, (UWORD) i, global_ridx);
+                                       break;
+                               case SQL_DELETE:
+                                       ret = SC_pos_delete(stmt, (UWORD) i, global_ridx);
+                                       break;
+                               case SQL_ADD:
+                                       ret = SC_pos_add(stmt, (UWORD) i);
+                                       break;
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
-               stmt->currTuple = stmt->rowset_start + irow - 1;
-               stmt->bind_row = irow;
-               SC_fetch(stmt);
-               /* restore the last_fetch_count */
-               stmt->last_fetch_count = last_fetch;
-               stmt->bind_row = bind_save;
+                               case SQL_REFRESH:
+                                       ret = SC_pos_refresh(stmt, (UWORD) i, global_ridx);
+                                       break;
+                       }
+                       processed++;
+                       if (SQL_ERROR == ret)
+                               break;
+#if (ODBCVER >= 0x0300)
+               }
+#endif /* ODBCVER */
        }
-       else
-               stmt->currTuple = stmt->rowset_start + irow;
-       QR_set_position(res, irow);
-
-       return SQL_SUCCESS;
+       if (SQL_ERROR == ret)
+               res->fcount = fcount; /* restore the count */
+       if (auto_commit_needed)
+               PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
+       if (irow > 0)
+       {
+               if (SQL_ADD != fOption) /* for SQLGetData */
+               { 
+                       stmt->currTuple = stmt->rowset_start + irow - 1;
+                       QR_set_position(res, irow - 1);
+               }
+       }
+       else if (SC_get_IRD(stmt)->rowsFetched)
+                       *SC_get_IRD(stmt)->rowsFetched = processed;
+inolog("rowset=%d processed=%d ret=%d\n", opts->rowset_size, processed, ret);
+       return ret; 
 }
 
 
index 0175d69..f243f0e 100644 (file)
@@ -56,7 +56,7 @@ typedef struct tagSETUPDLG
 
 /* Prototypes */
 void INTFUNC CenterDialog(HWND hdlg);
-int CALLBACK ConfigDlgProc(HWND hdlg, WORD wMsg, WPARAM wParam, LPARAM lParam);
+int CALLBACK ConfigDlgProc(HWND hdlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
 void INTFUNC ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg);
 BOOL INTFUNC SetDSNAttributes(HWND hwnd, LPSETUPDLG lpsetupdlg);
 
@@ -211,7 +211,7 @@ CenterDialog(HWND hdlg)
  */
 int                    CALLBACK
 ConfigDlgProc(HWND hdlg,
-                         WORD wMsg,
+                         UINT wMsg,
                          WPARAM wParam,
                          LPARAM lParam)
 {
index b33ccc2..f48a172 100644 (file)
@@ -117,6 +117,10 @@ PGAPI_AllocStmt(HDBC hdbc,
 
        /* Copy default statement options based from Connection options */
        stmt->options = conn->stmtOptions;
+       stmt->ardopts = conn->ardOptions;
+       stmt->ardopts.bookmark = (BindInfoClass *) malloc(sizeof(BindInfoClass));
+       stmt->ardopts.bookmark->buffer = NULL;
+       stmt->ardopts.bookmark->used = NULL;
 
        stmt->stmt_size_limit = CC_get_max_query_len(conn);
        /* Save the handle for later */
@@ -205,17 +209,35 @@ void
 InitializeStatementOptions(StatementOptions *opt)
 {
        memset(opt, 0, sizeof(StatementOptions));
-       opt->maxRows = 0;                       /* driver returns all rows */
-       opt->maxLength = 0;                     /* driver returns all data for char/binary */
-       opt->rowset_size = 1;
+       opt->maxRows = 0;               /* driver returns all rows */
+       opt->maxLength = 0;             /* driver returns all data for char/binary */
        opt->keyset_size = 0;           /* fully keyset driven is the default */
        opt->scroll_concurrency = SQL_CONCUR_READ_ONLY;
        opt->cursor_type = SQL_CURSOR_FORWARD_ONLY;
-       opt->bind_size = 0;                     /* default is to bind by column */
        opt->retrieve_data = SQL_RD_ON;
        opt->use_bookmarks = SQL_UB_OFF;
+}
+
+
+/*
+ * ARDFields initialize
+ */
+void
+InitializeARDFields(ARDFields *opt)
+{
+       memset(opt, 0, sizeof(ARDFields));
+       opt->rowset_size = 1;
+       opt->bind_size = 0;             /* default is to bind by column */
+}
+/*
+ * APDFields initialize
+ */
+void
+InitializeAPDFields(APDFields *opt)
+{
+       memset(opt, 0, sizeof(APDFields));
        opt->paramset_size = 1;
-       opt->param_bind_type = 0;       /* default is column-wise binding */
+       opt->param_bind_type = 0;       /* default is to bind by column */
 }
 
 
@@ -246,15 +268,6 @@ SC_Constructor(void)
                rv->stmt_size_limit = -1;
                rv->statement_type = STMT_TYPE_UNKNOWN;
 
-               rv->bindings = NULL;
-               rv->bindings_allocated = 0;
-
-               rv->bookmark.buffer = NULL;
-               rv->bookmark.used = NULL;
-
-               rv->parameters_allocated = 0;
-               rv->parameters = 0;
-
                rv->currTuple = -1;
                rv->rowset_start = -1;
                rv->current_col = -1;
@@ -274,22 +287,65 @@ SC_Constructor(void)
 
                /* Parse Stuff */
                rv->ti = NULL;
-               rv->fi = NULL;
                rv->ntab = 0;
-               rv->nfld = 0;
                rv->parse_status = STMT_PARSE_NONE;
 
                /* Clear Statement Options -- defaults will be set in AllocStmt */
                memset(&rv->options, 0, sizeof(StatementOptions));
+               memset(&rv->ardopts, 0, sizeof(ARDFields));
+               memset(&rv->apdopts, 0, sizeof(APDFields));
+               memset(&rv->irdopts, 0, sizeof(IRDFields));
+               memset(&rv->ipdopts, 0, sizeof(IPDFields));
 
                rv->pre_executing = FALSE;
                rv->inaccurate_result = FALSE;
                rv->miscinfo = 0;
+               rv->updatable = FALSE;
        }
        return rv;
 }
 
 
+void ARDFields_free(ARDFields * self)
+{
+       if (self->bookmark)
+       {
+               free(self->bookmark);
+               self->bookmark = NULL;
+       }
+       /*
+        * 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
+        * have to care
+        */
+       ARD_unbind_cols(self, TRUE);
+}
+
+void APDFields_free(APDFields * self)
+{
+       /* param bindings */
+       APD_free_params(self, STMT_FREE_PARAMS_ALL);
+}
+
+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])
+                               free(self->fi[i]);
+               free(self->fi);
+               self->fi = NULL;
+       }
+}
+
+void IPDFields_free(IPDFields * self)
+{
+}
+
 char
 SC_Destructor(StatementClass *self)
 {
@@ -322,47 +378,25 @@ SC_Destructor(StatementClass *self)
        if (self->load_statement)
                free(self->load_statement);
 
-       SC_free_params(self, STMT_FREE_PARAMS_ALL);
-
-       /*
-        * 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
-        * have to care
-        */
-       /* about that here. */
-       if (self->bindings)
-       {
-               int                     lf;
-
-               for (lf = 0; lf < self->bindings_allocated; lf++)
-               {
-                       if (self->bindings[lf].ttlbuf != NULL)
-                               free(self->bindings[lf].ttlbuf);
-               }
-               free(self->bindings);
-       }
-
-       /* Free the parsed table information */
+        /* Free the parsed table information */
        if (self->ti)
        {
-               int                     i;
+               int     i;
 
                for (i = 0; i < self->ntab; i++)
-                       free(self->ti[i]);
+                       if (self->ti[i]);
+                               free(self->ti[i]);
 
                free(self->ti);
+               self->ti = NULL;
        }
 
        /* Free the parsed field information */
-       if (self->fi)
-       {
-               int                     i;
-
-               for (i = 0; i < self->nfld; i++)
-                       free(self->fi[i]);
-               free(self->fi);
-       }
-
+       ARDFields_free(&(self->ardopts));
+       APDFields_free(&(self->apdopts));
+       IRDFields_free(&(self->irdopts));
+       IPDFields_free(&(self->ipdopts));
+       
        free(self);
 
        mylog("SC_Destructor: EXIT\n");
@@ -378,46 +412,16 @@ SC_Destructor(StatementClass *self)
 void
 SC_free_params(StatementClass *self, char option)
 {
-       int                     i;
-
-       mylog("SC_free_params:  ENTER, self=%d\n", self);
-
-       if (!self->parameters)
-               return;
-
-       for (i = 0; i < self->parameters_allocated; i++)
-       {
-               if (self->parameters[i].data_at_exec == TRUE)
-               {
-                       if (self->parameters[i].EXEC_used)
-                       {
-                               free(self->parameters[i].EXEC_used);
-                               self->parameters[i].EXEC_used = NULL;
-                       }
-
-                       if (self->parameters[i].EXEC_buffer)
-                       {
-                               if (self->parameters[i].SQLType != SQL_LONGVARBINARY)
-                                       free(self->parameters[i].EXEC_buffer);
-                               self->parameters[i].EXEC_buffer = NULL;
-                       }
-               }
-       }
+       APD_free_params(SC_get_APD(self), option);
        self->data_at_exec = -1;
        self->current_exec_param = -1;
        self->put_data = FALSE;
-
        if (option == STMT_FREE_PARAMS_ALL)
        {
-               free(self->parameters);
-               self->parameters = NULL;
-               self->parameters_allocated = 0;
                self->exec_start_row = -1;
                self->exec_end_row = -1;
                self->exec_current_row = -1;
        }
-
-       mylog("SC_free_params:  EXIT\n");
 }
 
 
@@ -493,31 +497,22 @@ SC_recycle_statement(StatementClass *self)
                        return FALSE;
        }
 
-       /* Free the parsed table information */
+        /* Free the parsed table information */
        if (self->ti)
        {
-               int                     i;
+               int     i;
 
                for (i = 0; i < self->ntab; i++)
-                       free(self->ti[i]);
-
-               free(self->ti);
+                       if (self->ti)
+                               free(self->ti);
                self->ti = NULL;
                self->ntab = 0;
        }
-
        /* Free the parsed field information */
-       if (self->fi)
-       {
-               int                     i;
+       IRDFields_free(SC_get_IRD(self));
 
-               for (i = 0; i < self->nfld; i++)
-                       free(self->fi[i]);
-               free(self->fi);
-               self->fi = NULL;
-               self->nfld = 0;
-       }
        self->parse_status = STMT_PARSE_NONE;
+       self->updatable = FALSE;
 
        /* Free any cursors */
        if (res = SC_get_Result(self), res)
@@ -605,19 +600,11 @@ SC_pre_execute(StatementClass *self)
 char
 SC_unbind_cols(StatementClass *self)
 {
-       Int2            lf;
-
-       for (lf = 0; lf < self->bindings_allocated; lf++)
-       {
-               self->bindings[lf].data_left = -1;
-               self->bindings[lf].buflen = 0;
-               self->bindings[lf].buffer = NULL;
-               self->bindings[lf].used = NULL;
-               self->bindings[lf].returntype = SQL_C_CHAR;
-       }
+       ARDFields       *opts = SC_get_ARD(self);
 
-       self->bookmark.buffer = NULL;
-       self->bookmark.used = NULL;
+       ARD_unbind_cols(opts, FALSE);
+       opts->bookmark->buffer = NULL;
+       opts->bookmark->used = NULL;
 
        return 1;
 }
@@ -732,6 +719,7 @@ SC_fetch(StatementClass *self)
 {
        static char *func = "SC_fetch";
        QResultClass *res = SC_get_Curres(self);
+       ARDFields       *opts;
        int                     retval,
                                result;
 
@@ -791,25 +779,26 @@ SC_fetch(StatementClass *self)
        result = SQL_SUCCESS;
        self->last_fetch_count = 1;
 
+       opts = SC_get_ARD(self);
        /*
         * If the bookmark column was bound then return a bookmark. Since this
         * is used with SQLExtendedFetch, and the rowset size may be greater
         * than 1, and an application can use row or column wise binding, use
         * the code in copy_and_convert_field() to handle that.
         */
-       if (self->bookmark.buffer)
+       if (opts->bookmark->buffer)
        {
                char            buf[32];
-               UInt4   offset = self->options.row_offset_ptr ? *self->options.row_offset_ptr : 0;
+               UInt4   offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
 
                sprintf(buf, "%ld", SC_get_bookmark(self));
                result = copy_and_convert_field(self, 0, buf,
-                        SQL_C_ULONG, self->bookmark.buffer + offset, 0,
-                       self->bookmark.used ? self->bookmark.used + (offset >> 2) : NULL);
+                        SQL_C_ULONG, opts->bookmark->buffer + offset, 0,
+                       opts->bookmark->used ? opts->bookmark->used + (offset >> 2) : NULL);
        }
 
 #ifdef DRIVER_CURSOR_IMPLEMENT
-       if (self->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
+       if (res->haskeyset)
        {
                num_cols -= 2;
        }
@@ -818,12 +807,12 @@ SC_fetch(StatementClass *self)
                return SQL_SUCCESS;
        for (lf = 0; lf < num_cols; lf++)
        {
-               mylog("fetch: cols=%d, lf=%d, self = %u, self->bindings = %u, buffer[] = %u\n", num_cols, lf, self, self->bindings, self->bindings[lf].buffer);
+               mylog("fetch: cols=%d, lf=%d, opts = %u, opts->bindings = %u, buffer[] = %u\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer);
 
                /* reset for SQLGetData */
-               self->bindings[lf].data_left = -1;
+               opts->bindings[lf].data_left = -1;
 
-               if (self->bindings[lf].buffer != NULL)
+               if (opts->bindings[lf].buffer != NULL)
                {
                        /* this column has a binding */
 
@@ -871,7 +860,7 @@ SC_fetch(StatementClass *self)
                                        self->errornumber = STMT_TRUNCATED;
                                        self->errormsg = "Fetched item was truncated.";
                                        qlog("The %dth item was truncated\n", lf + 1);
-                                       qlog("The buffer size = %d", self->bindings[lf].buflen);
+                                       qlog("The buffer size = %d", opts->bindings[lf].buflen);
                                        qlog(" and the value is '%s'\n", value);
                                        result = SQL_SUCCESS_WITH_INFO;
                                        break;
@@ -905,12 +894,14 @@ SC_execute(StatementClass *self)
 {
        static char *func = "SC_execute";
        ConnectionClass *conn;
+       APDFields       *apdopts;
        char            was_ok, was_nonfatal;
        QResultClass    *res = NULL;
        Int2            oldstatus,
                                numcols;
        QueryInfo       qi;
        ConnInfo   *ci;
+       UDWORD          qflag = 0;
 
 
        conn = SC_get_conn(self);
@@ -931,13 +922,15 @@ SC_execute(StatementClass *self)
                 (!CC_is_in_autocommit(conn) && self->statement_type != STMT_TYPE_OTHER)))
        {
                mylog("   about to begin a transaction on statement = %u\n", self);
-               if (!CC_begin(conn))
-               {
-                       self->errormsg = "Could not begin a transaction";
-                       self->errornumber = STMT_EXEC_ERROR;
-                       SC_log_error(func, "", self);
-                       return SQL_ERROR;
-               }
+               if (PG_VERSION_GE(conn, 7.1))
+                       qflag |= GO_INTO_TRANSACTION;
+                else if (!CC_begin(conn))
+                {
+                        self->errormsg = "Could not begin a transaction";
+                        self->errornumber = STMT_EXEC_ERROR;
+                        SC_log_error(func, "", self);
+                        return SQL_ERROR;
+                }
        }
 
        oldstatus = conn->status;
@@ -954,7 +947,7 @@ SC_execute(StatementClass *self)
        if (self->statement_type == STMT_TYPE_SELECT)
        {
                char            fetch[128];
-               UDWORD  qflag = (SQL_CONCUR_ROWVER == self->options.scroll_concurrency ? CREATE_KEYSET : 0); 
+               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);
 
@@ -964,6 +957,7 @@ SC_execute(StatementClass *self)
                        QR_command_successful(res))
                {
                        QR_Destructor(res);
+                       qflag &= (~ GO_INTO_TRANSACTION);
 
                        /*
                         * That worked, so now send the fetch to start getting data
@@ -990,7 +984,7 @@ SC_execute(StatementClass *self)
        {
                /* 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, 0);
+               res = CC_send_query(conn, self->stmt_with_params, NULL, qflag);
 
                /*
                 * We shouldn't send COMMIT. Postgres backend does the autocommit
@@ -1037,8 +1031,9 @@ SC_execute(StatementClass *self)
                        /* now allocate the array to hold the binding info */
                        if (numcols > 0)
                        {
-                               extend_bindings(self, numcols);
-                               if (self->bindings == NULL)
+                               ARDFields       *opts = SC_get_ARD(self);
+                               extend_column_bindings(opts, numcols);
+                               if (opts->bindings == NULL)
                                {
                                        QR_Destructor(res);
                                        self->errornumber = STMT_NO_MEMORY_ERROR;
@@ -1083,12 +1078,13 @@ SC_execute(StatementClass *self)
                last->next = res;
        }
 
+       apdopts = SC_get_APD(self);
        if (self->statement_type == STMT_TYPE_PROCCALL &&
                (self->errornumber == STMT_OK ||
                 self->errornumber == STMT_INFO_ONLY) &&
-               self->parameters &&
-               self->parameters[0].buffer &&
-               self->parameters[0].paramType == SQL_PARAM_OUTPUT)
+               apdopts->parameters &&
+               apdopts->parameters[0].buffer &&
+               apdopts->parameters[0].paramType == SQL_PARAM_OUTPUT)
        {                                                       /* get the return value of the procedure
                                                                 * call */
                RETCODE         ret;
@@ -1097,7 +1093,7 @@ SC_execute(StatementClass *self)
                ret = SC_fetch(hstmt);
                if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
                {
-                       ret = PGAPI_GetData(hstmt, 1, self->parameters[0].CType, self->parameters[0].buffer, self->parameters[0].buflen, self->parameters[0].used);
+                       ret = PGAPI_GetData(hstmt, 1, apdopts->parameters[0].CType, apdopts->parameters[0].buffer, apdopts->parameters[0].buflen, apdopts->parameters[0].used);
                        if (ret != SQL_SUCCESS)
                        {
                                self->errornumber = STMT_EXEC_ERROR;
@@ -1133,19 +1129,21 @@ SC_log_error(const char *func, const char *desc, const StatementClass *self)
        if (self)
        {
                QResultClass *res = SC_get_Result(self);
+               const ARDFields *opts = SC_get_ARD(self);
+               const APDFields *apdopts = SC_get_APD(self);
 
                qlog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg));
                mylog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg));
                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", self->bindings, self->bindings_allocated);
-               qlog("                 parameters=%u, parameters_allocated=%d\n", self->parameters, self->parameters_allocated);
+               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, self->options.rowset_size, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency);
+               qlog("                 maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->options.maxRows, opts->rowset_size, 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");
index 74583fb..65fa088 100644 (file)
@@ -12,6 +12,7 @@
 #include "psqlodbc.h"
 
 #include "bind.h"
+#include "descriptor.h"
 
 
 #ifndef FALSE
@@ -77,6 +78,7 @@ typedef enum
 #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
 
 /* statement types */
 enum
@@ -115,33 +117,6 @@ enum
        STMT_FETCH_EXTENDED,
 };
 
-typedef struct
-{
-       COL_INFO   *col_info;           /* cached SQLColumns info for this table */
-       char            name[MAX_TABLE_LEN + 1];
-       char            alias[MAX_TABLE_LEN + 1];
-} TABLE_INFO;
-
-typedef struct
-{
-       TABLE_INFO *ti;                         /* resolve to explicit table names */
-       int                     precision;
-       int                     scale;
-       int                     display_size;
-       int                     length;
-       int                     type;
-       char            nullable;
-       char            func;
-       char            expr;
-       char            quote;
-       char            dquote;
-       char            numeric;
-       char            updatable;
-       char            dot[MAX_TABLE_LEN + 1];
-       char            name[MAX_COLUMN_LEN + 1];
-       char            alias[MAX_COLUMN_LEN + 1];
-} FIELD_INFO;
-
 
 /********      Statement Handle        ***********/
 struct StatementClass_
@@ -152,19 +127,23 @@ struct StatementClass_
        QResultClass *curres;           /* the current result in the chain */
        HSTMT FAR  *phstmt;
        StatementOptions options;
+       ARDFields ardopts;
+       IRDFields irdopts;
+       APDFields apdopts;
+       IPDFields ipdopts;
 
        STMT_Status status;
        char       *errormsg;
        int                     errornumber;
 
        /* information on bindings */
-       BindInfoClass *bindings;        /* array to store the binding information */
-       BindInfoClass bookmark;
-       int                     bindings_allocated;
+       /*** BindInfoClass *bindings; ***/      /* array to store the binding information */
+       /*** BindInfoClass bookmark;
+       int                     bindings_allocated; ***/
 
        /* information on statement parameters */
-       int                     parameters_allocated;
-       ParameterInfoClass *parameters;
+       /*** int                        parameters_allocated;
+       ParameterInfoClass *parameters; ***/
 
        Int4            currTuple;              /* current absolute row number (GetData,
                                                                 * SetPos, SQLFetch) */
@@ -184,8 +163,6 @@ struct StatementClass_
                                                                 * statement that has been executed */
 
        TABLE_INFO **ti;
-       FIELD_INFO **fi;
-       int                     nfld;
        int                     ntab;
 
        int                     parse_status;
@@ -219,6 +196,7 @@ struct StatementClass_
        char            inaccurate_result;              /* Current status is PREMATURE but
                                                                                 * result is inaccurate */
        char            miscinfo;
+       char            updatable;
        SWORD           errorpos;
        SWORD           error_recsize;
        char            *load_statement; /* to (re)load updatable individual rows */
@@ -231,6 +209,10 @@ struct StatementClass_
 #define SC_get_Result(a)  (a->result)
 #define SC_set_Curres(a, b)  (a->curres = b)
 #define SC_get_Curres(a)  (a->curres)
+#define SC_get_ARD(a)  (&(a->ardopts))
+#define SC_get_APD(a)  (&(a->apdopts))
+#define SC_get_IRD(a)  (&(a->irdopts))
+#define SC_get_IPD(a)  (&(a->ipdopts))
 
 /*     options for SC_free_params() */
 #define STMT_FREE_PARAMS_ALL                           0
@@ -262,5 +244,9 @@ 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);
 unsigned long 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);
+RETCODE                SC_pos_add(StatementClass *self, UWORD irow);
 
 #endif
index 388f9fa..eb00cfd 100644 (file)
@@ -38,10 +38,21 @@ struct KeySet_
        UDWORD  blocknum;
        UDWORD  oid;
 };
-#define        KEYSET_INFO_PUBLIC      0x0f
-#define        DRV_SELF_ADDED          (1L << 4)
-#define        DRV_SELF_DELETED        (1L << 5)
-#define        DRV_SELF_UPDATED        (1L << 6)
+/*     Rollback(index + original TID) info */
+struct Rollback_
+{
+       UDWORD  index;
+       UDWORD  blocknum;
+       UWORD   offset;
+};
+#define        KEYSET_INFO_PUBLIC      0x07
+#define        CURS_SELF_ADDING        (1L << 3)
+#define        CURS_SELF_DELETING      (1L << 4)
+#define        CURS_SELF_UPDATING      (1L << 5)
+#define        CURS_SELF_ADDED         (1L << 6)
+#define        CURS_SELF_DELETED       (1L << 7)
+#define        CURS_SELF_UPDATED       (1L << 8)
+#define        CURS_NEEDS_REREAD       (1L << 9)
 
 /*     These macros are wrappers for the corresponding set_tuplefield functions
        but these handle automatic NULL determination and call set_tuplefield_null()
index 637e376..1614f4f 100644 (file)
@@ -96,9 +96,9 @@ CLEAN :
 
 CPP=cl.exe
 !IF "$(CFG)" == "MultibyteRelease"
-CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "MULTIBYTE" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "MULTIBYTE" /D "DRIVER_CURSOR_IMPLEMENT" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
 !ELSE
-CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "DRIVER_CURSOR_IMPLEMENT" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
 !ENDIF
 
 .c{$(INTDIR)}.obj::
index 4455069..e4dd84a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # File:                        win32_30w.mak
 #
-# Description:         psqlodbc30 Unicode version Makefile for Win32.
+# Description:         psqlodbc30w Unicode version Makefile for Win32.
 #
 # Configurations:      Unicode30Debug, Unicode30
 # Build Types:         ALL, CLEAN
@@ -45,7 +45,7 @@ OUTDIR=.\Unicode30
 OUTDIRBIN=.\Unicode30
 INTDIR=.\Unicode30
 
-ALL : "$(OUTDIRBIN)\psqlodbc30.dll"
+ALL : "$(OUTDIRBIN)\psqlodbc30w.dll"
 
 
 CLEAN :
@@ -82,7 +82,7 @@ CLEAN :
        -@erase "$(INTDIR)\odbcapi.obj"
        -@erase "$(INTDIR)\odbcapi30.obj"
        -@erase "$(INTDIR)\vc60.idb"
-       -@erase "$(OUTDIR)\psqlodbc30.dll"
+       -@erase "$(OUTDIR)\psqlodbc30w.dll"
        -@erase "$(OUTDIR)\psqlodbc.exp"
        -@erase "$(OUTDIR)\psqlodbc.lib"
 
@@ -131,7 +131,7 @@ BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc"
 BSC32_SBRS= \
        
 LINK32=link.exe
-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:"psqlodbc_api30w.def" /out:"$(OUTDIRBIN)\psqlodbc30.dll" /implib:"$(OUTDIR)\psqlodbc.lib" 
+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:"psqlodbc_api30w.def" /out:"$(OUTDIRBIN)\psqlodbc30w.dll" /implib:"$(OUTDIR)\psqlodbc.lib" 
 DEF_FILE= "psqlodbc_api30w.def"
 LINK32_OBJS= \
        "$(INTDIR)\bind.obj" \
@@ -167,14 +167,14 @@ LINK32_OBJS= \
        "$(INTDIR)\odbcapi30.obj" \
        "$(INTDIR)\psqlodbc.res"
 
-"$(OUTDIRBIN)\psqlodbc30.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+"$(OUTDIRBIN)\psqlodbc30w.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
     $(LINK32) @<<
   $(LINK32_FLAGS) $(LINK32_OBJS)
 <<
 
 !ELSEIF  "$(CFG)" == "Unicode30Debug"
 
-ALL : "$(OUTDIR)\psqlodbc30.dll"
+ALL : "$(OUTDIR)\psqlodbc30w.dll"
 
 
 CLEAN :
@@ -212,7 +212,7 @@ CLEAN :
        -@erase "$(INTDIR)\odbcapi30.obj"
        -@erase "$(INTDIR)\vc60.idb"
        -@erase "$(INTDIR)\vc60.pdb"
-       -@erase "$(OUTDIR)\psqlodbc30.dll"
+       -@erase "$(OUTDIR)\psqlodbc30w.dll"
        -@erase "$(OUTDIR)\psqlodbc.exp"
        -@erase "$(OUTDIR)\psqlodbc.ilk"
        -@erase "$(OUTDIR)\psqlodbc.lib"
@@ -263,7 +263,7 @@ BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc"
 BSC32_SBRS= \
        
 LINK32=link.exe
-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:"psqlodbc_api30w.def" /out:"$(OUTDIR)\psqlodbc30.dll" /implib:"$(OUTDIR)\psqlodbc.lib" /pdbtype:sept 
+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:"psqlodbc_api30w.def" /out:"$(OUTDIR)\psqlodbc30w.dll" /implib:"$(OUTDIR)\psqlodbc.lib" /pdbtype:sept 
 DEF_FILE= "psqlodbc_api30w.def"
 LINK32_OBJS= \
        "$(INTDIR)\bind.obj" \
@@ -299,7 +299,7 @@ LINK32_OBJS= \
        "$(INTDIR)\odbcapi30.obj" \
        "$(INTDIR)\psqlodbc.res"
 
-"$(OUTDIR)\psqlodbc30.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+"$(OUTDIR)\psqlodbc30w.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
     $(LINK32) @<<
   $(LINK32_FLAGS) $(LINK32_OBJS)
 <<