OSDN Git Service

1) Support Keyset Driven driver cursors.
authorHiroshi Inoue <inoue@tpf.co.jp>
Wed, 22 May 2002 05:51:03 +0000 (05:51 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Wed, 22 May 2002 05:51:03 +0000 (05:51 +0000)
2) Supprt ARD precision/scale and SQL_C_NUEMRIC.
3) Minimal implementation of SQLGetDiagField().
4) SQLRowCount() reports the result of SQLSetPos and SQLBulkOperation.
5) int8 -> SQL_NUMERIC for Microsoft Jet.
6) Support isolation level change.
7) ODBC3.0 SQLSTATE code.
8) Append mode log files.

29 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
src/interfaces/odbc/dlg_specific.c
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/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/psqlodbc.h
src/interfaces/odbc/psqlodbc.rc
src/interfaces/odbc/qresult.c
src/interfaces/odbc/qresult.h
src/interfaces/odbc/results.c
src/interfaces/odbc/statement.c
src/interfaces/odbc/statement.h
src/interfaces/odbc/tuple.h

index e931b8b..e6deeda 100644 (file)
@@ -69,6 +69,23 @@ PGAPI_BindParameter(
        opts->parameters[ipar].SQLType = fSqlType;
        opts->parameters[ipar].column_size = cbColDef;
        opts->parameters[ipar].decimal_digits = ibScale;
+       opts->parameters[ipar].precision = 0;
+       opts->parameters[ipar].scale = 0;
+#if (ODBCVER >= 0x0300)
+       switch (fCType)
+       {
+               case SQL_C_NUMERIC:
+                       if (cbColDef > 0)
+                               opts->parameters[ipar].precision = (UInt2) cbColDef;
+                       if (ibScale > 0)
+                               opts->parameters[ipar].scale = ibScale;
+                       break;
+               case SQL_C_TYPE_TIMESTAMP:
+                       if (ibScale > 0)
+                               opts->parameters[ipar].precision = ibScale;
+                       break;
+       }
+#endif /* ODBCVER */
 
        /*
         * If rebinding a parameter that had data-at-exec stuff in it, then
@@ -210,6 +227,8 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
                        free(opts->bindings[icol].ttlbuf);
                opts->bindings[icol].ttlbuf = NULL;
                opts->bindings[icol].ttlbuflen = 0;
+               opts->bindings[icol].precision = 0;
+               opts->bindings[icol].scale = 0;
        }
        else
        {
@@ -218,6 +237,13 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
                opts->bindings[icol].buffer = rgbValue;
                opts->bindings[icol].used = pcbValue;
                opts->bindings[icol].returntype = fCType;
+#if (ODBCVER >= 0x0300)
+               if (SQL_C_NUMERIC == fCType)
+                       opts->bindings[icol].precision = 32;
+               else
+#endif /* ODBCVER */
+                       opts->bindings[icol].precision = 0;
+               opts->bindings[icol].scale = 0;
 
                mylog("       bound buffer[%d] = %u\n", icol, opts->bindings[icol].buffer);
        }
@@ -460,6 +486,8 @@ reset_a_parameter_binding(APDFields *self, int ipar)
        self->parameters[ipar].SQLType = 0;
        self->parameters[ipar].column_size = 0;
        self->parameters[ipar].decimal_digits = 0;
+       self->parameters[ipar].precision = 0;
+       self->parameters[ipar].scale = 0;
        self->parameters[ipar].data_at_exec = FALSE;
        self->parameters[ipar].lobj_oid = 0;
 }
index 7eadea9..f2467c7 100644 (file)
@@ -27,6 +27,8 @@ struct BindInfoClass_
        Int2            returntype;             /* kind of conversion to be applied when
                                                                 * returning (SQL_C_DEFAULT,
                                                                 * SQL_C_CHAR...) */
+       Int2    precision;              /* the precision for numeric or timestamp type */
+       Int2    scale;                  /* the scale for numeric type */
 };
 
 /*
@@ -40,12 +42,14 @@ struct ParameterInfoClass_
        Int2            paramType;
        Int2            CType;
        Int2            SQLType;
-       UInt4           column_size;
        Int2            decimal_digits;
+       UInt4           column_size;
        Oid                     lobj_oid;
        Int4       *EXEC_used;          /* amount of data OR the oid of the large
                                                                 * object */
        char       *EXEC_buffer;        /* the data or the FD of the large object */
+       Int2            precision;      /* the precision for numeric or timestamp type */
+       Int2            scale;          /* the scale for numeric type */
        char            data_at_exec;
 };
 
index 2b0d67a..81ed7d5 100644 (file)
@@ -237,7 +237,7 @@ CC_conninfo_init(ConnInfo *conninfo)
 {
                memset(conninfo, 0, sizeof(ConnInfo));
                conninfo->disallow_premature = -1;
-               conninfo->updatable_cursors = -1;
+               conninfo->allow_keyset = -1;
                conninfo->lf_conversion = -1;
                conninfo->true_is_minus1 = -1;
                memcpy(&(conninfo->drivers), &globals, sizeof(globals));
@@ -293,6 +293,7 @@ CC_Constructor()
                rv->unicode = 0;
                rv->result_uncommitted = 0;
                rv->schema_support = 0;
+               rv->isolation = SQL_TXN_READ_COMMITTED;
 #ifdef MULTIBYTE
                rv->client_encoding = NULL;
                rv->server_encoding = NULL;
@@ -996,6 +997,12 @@ another_version_retry:
        }
 #endif /* UNICODE_SUPPORT */
 #endif /* MULTIBYTE */
+       ci->updatable_cursors = 0;
+#ifdef DRIVER_CURSOR_IMPLEMENT
+       if (!ci->drivers.use_declarefetch &&
+               PG_VERSION_GE(self, 7.0)) /* Tid scan since 7.0 */
+               ci->updatable_cursors = ci->allow_keyset;
+#endif /* DRIVER_CURSOR_IMPLEMENT */
 
        CC_clear_error(self);           /* clear any initial command errors */
        self->status = CONN_CONNECTED;
@@ -1130,7 +1137,7 @@ void      CC_on_commit(ConnectionClass *conn)
        }
        conn->result_uncommitted = 0;
 }
-void   CC_on_abort(ConnectionClass *conn, BOOL set_no_trans)
+void   CC_on_abort(ConnectionClass *conn, UDWORD opt)
 {
        if (CC_is_in_trans(conn))
        {
@@ -1138,9 +1145,11 @@ void     CC_on_abort(ConnectionClass *conn, BOOL set_no_trans)
                if (conn->result_uncommitted)
                        ProcessRollback(conn, TRUE);
 #endif /* DRIVER_CURSOR_IMPLEMENT */
-               if (set_no_trans)
+               if (0 != (opt & NO_TRANS))
                        CC_set_no_trans(conn);
        }
+       if (0 != (opt & CONN_DEAD))
+               conn->status = CONN_DOWN;
        conn->result_uncommitted = 0;
 }
 
@@ -1162,8 +1171,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
        BOOL    clear_result_on_abort = ((flag & CLEAR_RESULT_ON_ABORT) != 0),
                create_keyset = ((flag & CREATE_KEYSET) != 0),
                issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self));
-       char            swallow,
-                          *wq;
+       char            swallow, *wq, *ptr;
        int                     id;
        SocketClass *sock = self->sock;
        int                     maxlen,
@@ -1173,8 +1181,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,
-                               set_no_trans;
+                               used_passed_result_object = FALSE;
+       UDWORD          abort_opt;
 
        /* ERROR_MSG_LENGTH is suffcient */
        static char msgbuffer[ERROR_MSG_LENGTH + 1];
@@ -1201,7 +1209,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_on_abort(self, TRUE);
+               CC_on_abort(self, NO_TRANS | CONN_DEAD);
                return NULL;
        }
 
@@ -1210,7 +1218,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_on_abort(self, TRUE);
+               CC_on_abort(self, NO_TRANS | CONN_DEAD);
                return NULL;
        }
 
@@ -1223,7 +1231,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_on_abort(self, TRUE);
+               CC_on_abort(self, NO_TRANS | CONN_DEAD);
                return NULL;
        }
 
@@ -1260,7 +1268,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_on_abort(self, TRUE);
+                       CC_on_abort(self, NO_TRANS | CONN_DEAD);
                        ReadyToReturn = TRUE;
                        retres = NULL;
                        break;
@@ -1284,7 +1292,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_on_abort(self, TRUE);
+                                       CC_on_abort(self, NO_TRANS | CONN_DEAD);
                                        ReadyToReturn = TRUE;
                                        retres = NULL;
                                }
@@ -1312,11 +1320,20 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
                                        else if (strnicmp(cmdbuffer, "COMMIT", 6) == 0)
                                                CC_on_commit(self);
                                        else if (strnicmp(cmdbuffer, "ROLLBACK", 8) == 0)
-                                               CC_on_abort(self, TRUE);
+                                               CC_on_abort(self, NO_TRANS);
                                        else if (strnicmp(cmdbuffer, "END", 3) == 0)
                                                CC_on_commit(self);
                                        else if (strnicmp(cmdbuffer, "ABORT", 5) == 0)
-                                               CC_on_abort(self, TRUE);
+                                               CC_on_abort(self, NO_TRANS);
+                                       else
+                                       {
+                                               trim(cmdbuffer); /* get rid of trailing space */ 
+                                               ptr = strrchr(cmdbuffer, ' ');
+                                               if (ptr)
+                                                       res->recent_processed_row_count = atoi(ptr + 1);
+                                               else
+                                                       res->recent_processed_row_count = -1;
+                                       }
 
                                        if (QR_command_successful(res))
                                                QR_set_status(res, PGRES_COMMAND_OK);
@@ -1400,15 +1417,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;
+                               abort_opt = 0;
                                if (!strncmp(msgbuffer, "FATAL", 5))
                                {
                                        self->errornumber = CONNECTION_SERVER_REPORTED_ERROR;
-                                       set_no_trans = TRUE;
+                                       abort_opt = NO_TRANS | CONN_DEAD;
                                }
                                else
                                        self->errornumber = CONNECTION_SERVER_REPORTED_WARNING;
-                               CC_on_abort(self, set_no_trans);
+                               CC_on_abort(self, abort_opt);
                                QR_set_status(res, PGRES_FATAL_ERROR);
                                QR_set_message(res, msgbuffer);
                                QR_set_aborted(res, TRUE);
@@ -1497,7 +1514,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_on_abort(self, TRUE);
+                               CC_on_abort(self, NO_TRANS | CONN_DEAD);
 
                                mylog("send_query: error - %s\n", self->errormsg);
                                ReadyToReturn = TRUE;
@@ -1585,7 +1602,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_on_abort(self, TRUE);
+               CC_on_abort(self, NO_TRANS | CONN_DEAD);
                return FALSE;
        }
 
@@ -1594,7 +1611,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_on_abort(self, TRUE);
+               CC_on_abort(self, NO_TRANS | CONN_DEAD);
                return FALSE;
        }
 
@@ -1643,7 +1660,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);
+                               CC_on_abort(self, 0);
 
                                mylog("send_function(V): 'E' - %s\n", self->errormsg);
                                qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
@@ -1656,7 +1673,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_on_abort(self, TRUE);
+                               CC_on_abort(self, NO_TRANS | CONN_DEAD);
 
                                mylog("send_function: error - %s\n", self->errormsg);
                                return FALSE;
@@ -1690,7 +1707,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);
+                               CC_on_abort(self, 0);
                                mylog("send_function(G): 'E' - %s\n", self->errormsg);
                                qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
 
@@ -1711,7 +1728,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_on_abort(self, TRUE);
+                               CC_on_abort(self, NO_TRANS | CONN_DEAD);
 
                                mylog("send_function: error - %s\n", self->errormsg);
                                return FALSE;
index 849350d..3bd8632 100644 (file)
@@ -166,6 +166,7 @@ typedef struct
        char            translation_option[SMALL_REGISTRY_LEN];
        char            focus_password;
        char            disallow_premature;
+       char            allow_keyset;
        char            updatable_cursors;
        char            lf_conversion;
        char            true_is_minus1;
@@ -290,12 +291,13 @@ struct ConnectionClass_
        char            result_uncommitted;
        char            schema_support;
 #ifdef MULTIBYTE
-       char       *client_encoding;
-       char       *server_encoding;
+       char            *client_encoding;
+       char            *server_encoding;
 #endif   /* MULTIBYTE */
-       int     ccsc;
+       int             ccsc;
        int             be_pid; /* pid returned by backend */
        int             be_key; /* auth code needed to send cancel */
+       UInt4           isolation;
 };
 
 
@@ -339,11 +341,15 @@ void              CC_log_error(const char *func, const char *desc, const ConnectionClass *se
 int                    CC_get_max_query_len(const ConnectionClass *self);
 int            CC_send_cancel_request(const ConnectionClass *conn);
 void           CC_on_commit(ConnectionClass *conn);
-void           CC_on_abort(ConnectionClass *conn, BOOL set_no_trans);
+void           CC_on_abort(ConnectionClass *conn, UDWORD opt);
 void           ProcessRollback(ConnectionClass *conn, BOOL undo);
 
-/* CC_send_query_options */
+/* 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
+/* CC_on_abort options */
+#define        NO_TRANS                1L
+#define        CONN_DEAD               (1L << 1) /* connection is no longer valid */
+
+#endif /* __CONNECTION_H__ */
index 433f4b3..d33f390 100644 (file)
@@ -371,7 +371,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                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 ? */
+                                                * needed by ADO ? */
                if (pbic->data_left == 0)
                {
                        if (pbic->ttlbuf != NULL)
@@ -984,6 +984,90 @@ inolog("2stime fr=%d\n", st.fr);
 #endif /* HAVE_LOCALE_H */
                                break;
 
+#if (ODBCVER >= 0x0300)
+                        case SQL_C_NUMERIC:
+#ifdef HAVE_LOCALE_H
+                       /* strcpy(saved_locale, setlocale(LC_ALL, NULL));
+                       setlocale(LC_ALL, "C"); not needed currently */ 
+#endif /* HAVE_LOCALE_H */
+                       {
+                       SQL_NUMERIC_STRUCT      *ns;
+                       int     i, nlen, bit, hval, tv, dig, sta, olen;
+                       char    calv[SQL_MAX_NUMERIC_LEN * 3], *wv;
+                       BOOL    dot_exist;
+
+                       len = sizeof(SQL_NUMERIC_STRUCT);
+                       if (bind_size > 0)
+                               ns = (SQL_NUMERIC_STRUCT *) ((char *) rgbValue + (bind_row * bind_size));
+                       else
+                               ns = (SQL_NUMERIC_STRUCT *) rgbValue + bind_row;
+                       for (wv = neut_str; *wv && isspace(*wv); wv++)
+                               ;
+                       ns->sign = 1;
+                       if (*wv == '-')
+                       {
+                               ns->sign = 0;
+                               wv++;
+                       }
+                       else if (*wv == '+')
+                               wv++;
+                       while (*wv == '0') wv++;
+                       ns->precision = 0;
+                       ns->scale = 0;
+                       for (nlen = 0, dot_exist = FALSE;; wv++) 
+                       {
+                               if (*wv == '.')
+                               {
+                                       if (dot_exist)
+                                               break;
+                                       dot_exist = TRUE;
+                               }
+                               else if (!isdigit(*wv))
+                                               break;
+                               else
+                               {
+                                       if (dot_exist)
+                                               ns->scale++;
+                                       else
+                                               ns->precision++;
+                                       calv[nlen++] = *wv;
+                               }
+                       }
+                       memset(ns->val, 0, sizeof(ns->val));
+                       for (hval = 0, bit = 1L, sta = 0, olen = 0; sta < nlen;)
+                       {
+                               for (dig = 0, i = sta; i < nlen; i++)
+                               {
+                                       tv = dig * 10 + calv[i] - '0';
+                                       dig = tv % 2;
+                                       calv[i] = tv / 2 + '0';
+                                       if (i == sta && tv < 2)
+                                               sta++;
+                               }
+                               if (dig > 0)
+                                       hval |= bit;
+                               bit <<= 1;
+                               if (bit >= (1L << 8))
+                               {
+                                       ns->val[olen++] = hval;
+                                       hval = 0;
+                                       bit = 1L;
+                                       if (olen >= SQL_MAX_NUMERIC_LEN - 1)
+                                       {
+                                               ns->scale = sta - ns->precision;
+                                               break;
+                                       }
+                               } 
+                       }
+                       if (hval && olen < SQL_MAX_NUMERIC_LEN - 1)
+                               ns->val[olen++] = hval;
+                       }
+#ifdef HAVE_LOCALE_H
+                       /* setlocale(LC_ALL, saved_locale); */
+#endif /* HAVE_LOCALE_H */
+                       break;
+#endif /* ODBCVER */
+
                        case SQL_C_SSHORT:
                        case SQL_C_SHORT:
                                len = 2;
@@ -1179,6 +1263,8 @@ QP_initialize(QueryParse *q, const StatementClass *stmt)
 
 #define        FLGB_PRE_EXECUTING      1L
 #define        FLGB_INACCURATE_RESULT  (1L << 1)
+#define        FLGB_CREATE_KEYSET      (1L << 2)
+#define        FLGB_KEYSET_DRIVEN      (1L << 3)
 typedef struct _QueryBuild {
        char    *query_statement;
        UInt4   str_size_limit;
@@ -1589,10 +1675,16 @@ 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_FATAL)
+               {
                        stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
-               else*/ if (!stmt->updatable)
+                       return SQL_ERROR;
+               }
+               else if (!stmt->updatable)
+               {
                        stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
+                       stmt->options.cursor_type = SQL_CURSOR_STATIC;
+               }
                else
                {
                        qp->from_pos = stmt->from_pos;
@@ -1602,7 +1694,7 @@ copy_statement_with_parameters(StatementClass *stmt)
 #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;
+               stmt->options.cursor_type = SQL_CURSOR_STATIC;
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
 
        /* If the application hasn't set a cursor name, then generate one */
@@ -1641,6 +1733,12 @@ copy_statement_with_parameters(StatementClass *stmt)
                        qp->flags |= FLGP_CURSOR_CHECK_OK;
                        qp->declare_pos = qb->npos;
                }
+               else if (SQL_CONCUR_READ_ONLY != stmt->options.scroll_concurrency)
+               {
+                       qb->flags |= FLGB_CREATE_KEYSET;
+                       if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
+                               qb->flags |= FLGB_KEYSET_DRIVEN;
+               }
        }
 
        for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++)
@@ -1693,13 +1791,29 @@ copy_statement_with_parameters(StatementClass *stmt)
                UInt4   npos = qb->load_stmt_len;
 
                if (0 == npos)
+               {
                        npos = qb->npos;
+                       for (; npos > 0; npos--)
+                       {
+                               if (isspace(new_statement[npos - 1]))
+                                       continue;
+                               if (';' != new_statement[npos - 1])
+                                       break;
+                       }
+                       if (0 != (qb->flags & FLGB_KEYSET_DRIVEN))
+                       {
+                               qb->npos = npos;
+                               /* ----------
+                                * 1st query is for field information
+                                * 2nd query is keyset gathering
+                                */
+                               CVT_APPEND_STR(qb, " where ctid = '(,)';select ctid, oid from ");
+                               CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, npos - qp->from_pos - 5);
+                       }
+               }
                stmt->load_statement = malloc(npos + 1);
-               memcpy(stmt->load_statement, new_statement, npos);
-               if (stmt->load_statement[npos - 1] == ';')
-                       stmt->load_statement[npos - 1] = '\0';
-               else
-                       stmt->load_statement[npos] = '\0';
+               memcpy(stmt->load_statement, qb->query_statement, npos);
+               stmt->load_statement[npos] = '\0';
        }
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
        if (prepare_dummy_cursor && SC_is_pre_executable(stmt))
@@ -1732,7 +1846,14 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
                CVT_APPEND_STR(qb, ", CTID, OID ");
        }
        else if (qp->where_pos == (Int4) qp->opos)
+       {
                qb->load_stmt_len = qb->npos;
+               if (0 != (qb->flags & FLGB_KEYSET_DRIVEN))
+               {
+                       CVT_APPEND_STR(qb, "where ctid = '(,)';select CTID, OID from ");
+                       CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, qp->where_pos - qp->from_pos - 5);
+               }
+       }
 #ifdef MULTIBYTE
        oldchar = encoded_byte_check(&qp->encstr, qp->opos);
        if (ENCODE_STATUS(qp->encstr) != 0)
@@ -1836,6 +1957,7 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
                                                {
                                                        qp->flags |= FLGP_SELECT_INTO;
                                                        qp->flags &= ~FLGP_CURSOR_CHECK_OK;
+                                                       qb->flags &= ~FLGB_KEYSET_DRIVEN;
                                                        qp->statement_type = STMT_TYPE_CREATE;
                                                        memmove(qb->query_statement, qb->query_statement + qp->declare_pos, qb->npos - qp->declare_pos);
                                                        qb->npos -= qp->declare_pos;
@@ -1887,6 +2009,130 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
        return SQL_SUCCESS;
 }
 
+#if (ODBCVER >= 0x0300)
+static BOOL
+ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
+{
+       static int prec[] = {1, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 29, 32, 34, 37, 39};
+       Int4    i, j, k, ival, vlen, len, newlen;
+       unsigned char           calv[40];
+       const unsigned char     *val = (const unsigned char *) ns->val;
+       BOOL    next_figure;
+
+       if (0 == ns->precision)
+       {
+               strcpy(chrform, "0");
+               return TRUE;
+       }
+       else if (ns->precision < prec[sizeof(Int4)])
+       {
+               for (i = 0, ival = 0; i < sizeof(Int4) && prec[i] <= ns->precision; i++)
+               {
+                       ival += (val[i] << (8 * i)); /* ns->val is little endian */
+               }
+               if (0 == ns->scale)
+               {
+                       if (0 == ns->sign)
+                               ival *= -1;
+                       sprintf(chrform, "%d", ival);
+               }
+               else if (ns->scale > 0)
+               {
+                       Int4    i, div, o1val, o2val;
+
+                       for (i = 0, div = 1; i < ns->scale; i++)
+                               div *= 10;
+                       o1val = ival / div;
+                       o2val = ival % div;
+                       if (0 == ns->sign)
+                               o1val *= -1;
+                       sprintf(chrform, "%d.%0.*d", o1val, ns->scale, o2val);
+               }
+               return TRUE;
+       }
+
+       for (i = 0; i < SQL_MAX_NUMERIC_LEN && prec[i] <= ns->precision; i++)
+               ;
+       vlen = i;
+       len = 0;
+       memset(calv, 0, sizeof(calv));
+       for (i = vlen - 1; i >= 0; i--)
+       {
+               for (j = len - 1; j >= 0; j--)
+               {
+                       if (!calv[j])
+                               continue;
+                       ival = (((Int4)calv[j]) << 8);
+                       calv[j] = (ival % 10);
+                       ival /= 10;
+                       calv[j + 1] += (ival % 10);
+                       ival /= 10;
+                       calv[j + 2] += (ival % 10);
+                       ival /= 10;
+                       calv[j + 3] += ival;
+                       for (k = j;; k++)
+                       {
+                               next_figure = FALSE;
+                               if (calv[k] > 0)
+                               {
+                                       if (k >= len)
+                                               len = k + 1;
+                                       while (calv[k] > 9)
+                                       {
+                                               calv[k + 1]++;
+                                               calv[k] -= 10;
+                                               next_figure = TRUE;
+                                       }
+                               }
+                               if (k >= j + 3 && !next_figure)
+                                       break;
+                       }
+               }
+               ival = val[i];
+               if (!ival)
+                       continue;
+               calv[0] += (ival % 10);
+               ival /= 10;
+               calv[1] += (ival % 10);
+               ival /= 10;
+               calv[2] += ival;
+               for (j = 0;; j++)
+               {
+                       next_figure = FALSE;
+                       if (calv[j] > 0)
+                       {
+                               if (j >= len)
+                                       len = j + 1;
+                               while (calv[j] > 9)
+                               {
+                                       calv[j + 1]++;
+                                       calv[j] -= 10;
+                                       next_figure = TRUE;
+                               }
+                       }
+                       if (j >= 2 && !next_figure)
+                               break;
+               }
+       }
+       newlen = 0;
+       if (0 == ns->sign)
+               chrform[newlen++] = '-';
+       for (i = len - 1; i >= ns->scale; i--)
+               chrform[newlen++] = calv[i] + '0';
+       if (ns->scale > 0)
+       {
+               chrform[newlen++] = '.';
+               for (; i >= 0; i--)
+                       chrform[newlen++] = calv[i] + '0';
+       }
+       chrform[newlen] = '\0';
+       return TRUE;
+}
+#endif /* ODBCVER */
+
+/*
+ *
+ */
 static int
 ResolveOneParam(QueryBuild *qb)
 {
@@ -2138,6 +2384,11 @@ ResolveOneParam(QueryBuild *qb)
                                break;
 
                        }
+#if (ODBCVER >= 0x0300)
+               case SQL_C_NUMERIC:
+                       if (ResolveNumericParam((SQL_NUMERIC_STRUCT *) buffer, param_string))
+                               break;
+#endif
                default:
                        /* error */
                        qb->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters";
@@ -2336,16 +2587,16 @@ ResolveOneParam(QueryBuild *qb)
                        if (buf)
                        {
                                cbuf[0] = '\'';
-                               my_strcpy(cbuf + 1, sizeof(cbuf) - 12, buf, used);      /* 12 = 1('\'') +
-                                                                                                                                       * strlen("'::numeric")
+                               my_strcpy(cbuf + 1, sizeof(cbuf) - 3, buf, used);       /* 3 = 1('\'') +
+                                                                                                                                       * strlen("'")
                                                                                                                                        * + 1('\0') */
-                               strcat(cbuf, "'::numeric");
+                               strcat(cbuf, "'");
                        }
                        else
-                               sprintf(cbuf, "'%s'::numeric", param_string);
+                               sprintf(cbuf, "'%s'", param_string);
                        CVT_APPEND_STR(qb, cbuf);
                        break;
-                       default:                        /* a numeric type or SQL_BIT */
+               default:                        /* a numeric type or SQL_BIT */
                        if (param_sqltype == SQL_BIT)
                                CVT_APPEND_CHAR(qb, '\'');              /* Open Quote */
 
@@ -2938,7 +3189,7 @@ conv_from_octal(const unsigned char *s)
                                y = 0;
 
        for (i = 1; i <= 3; i++)
-               y += (s[i] - '0') << (3  * (3 - i));
+               y += (s[i] - '0') << (3 * (3 - i));
 
        return y;
 
index 59e4212..182142b 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:           See "notice.txt" for copyright and license information.
  *
- * $Id: descriptor.h,v 1.4 2002/04/10 08:18:54 inoue Exp $
+ * $Id: descriptor.h,v 1.5 2002/05/22 05:51:03 inoue Exp $
  *
  */
 
@@ -20,6 +20,7 @@ typedef struct
        char            schema[MAX_SCHEMA_LEN + 1];
        char            name[MAX_TABLE_LEN + 1];
        char            alias[MAX_TABLE_LEN + 1];
+       char            updatable;
 } TABLE_INFO;
 
 typedef struct
@@ -41,6 +42,8 @@ typedef struct
        char            name[MAX_COLUMN_LEN + 1];
        char            alias[MAX_COLUMN_LEN + 1];
 } FIELD_INFO;
+Int4 FI_precision(const FIELD_INFO *);
+Int4 FI_scale(const FIELD_INFO *);
 
 struct ARDFields_
 {
index a4423e4..259c7b3 100644 (file)
@@ -340,7 +340,7 @@ 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);
+                       CheckDlgButton(hdlg, DS_UPDATABLECURSORS, ci->allow_keyset);
 #ifndef DRIVER_CURSOR_IMPLEMENT
                        EnableWindow(GetDlgItem(hdlg, DS_UPDATABLECURSORS), FALSE);
 #endif /* DRIVER_CURSOR_IMPLEMENT */
@@ -382,7 +382,7 @@ ds_optionsProc(HWND hdlg,
                                        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);
+                                       ci->allow_keyset = IsDlgButtonChecked(hdlg, DS_UPDATABLECURSORS);
 #endif /* DRIVER_CURSOR_IMPLEMENT */
 
                                        /* OID Options */
@@ -590,7 +590,7 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
                                INI_LFCONVERSION,
                                ci->lf_conversion,
                                INI_UPDATABLECURSORS,
-                               ci->updatable_cursors,
+                               ci->allow_keyset,
                                INI_DISALLOWPREMATURE,
                                ci->disallow_premature,
                                INI_TRUEISMINUS1,
@@ -601,7 +601,7 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
                unsigned long flag = 0;
                if (ci->disallow_premature)
                        flag |= BIT_DISALLOWPREMATURE;
-               if (ci->updatable_cursors)
+               if (ci->allow_keyset)
                        flag |= BIT_UPDATABLECURSORS;
                if (ci->lf_conversion)
                        flag |= BIT_LFCONVERSION;
@@ -686,7 +686,7 @@ unfoldCXAttribute(ConnInfo *ci, const char *value)
                sscanf(value + 2, "%lx", &flag);
        }
        ci->disallow_premature = (char)((flag & BIT_DISALLOWPREMATURE) != 0);
-       ci->updatable_cursors = (char)((flag & BIT_UPDATABLECURSORS) != 0);
+       ci->allow_keyset = (char)((flag & BIT_UPDATABLECURSORS) != 0);
        ci->lf_conversion = (char)((flag & BIT_LFCONVERSION) != 0);
        if (count < 4)
                return;
@@ -770,7 +770,7 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
        else if (stricmp(attribute, INI_DISALLOWPREMATURE) == 0 || stricmp(attribute, "C3") == 0)
                ci->disallow_premature = atoi(value);
        else if (stricmp(attribute, INI_UPDATABLECURSORS) == 0 || stricmp(attribute, "C4") == 0)
-               ci->updatable_cursors = atoi(value);
+               ci->allow_keyset = atoi(value);
        else if (stricmp(attribute, INI_LFCONVERSION) == 0)
                ci->lf_conversion = atoi(value);
        else if (stricmp(attribute, INI_TRUEISMINUS1) == 0)
@@ -870,8 +870,8 @@ getDSNdefaults(ConnInfo *ci)
 
        if (ci->disallow_premature < 0)
                ci->disallow_premature = DEFAULT_DISALLOWPREMATURE;
-       if (ci->updatable_cursors < 0)
-               ci->updatable_cursors = DEFAULT_UPDATABLECURSORS;
+       if (ci->allow_keyset < 0)
+               ci->allow_keyset = DEFAULT_UPDATABLECURSORS;
        if (ci->lf_conversion < 0)
                ci->lf_conversion = DEFAULT_LFCONVERSION;
        if (ci->true_is_minus1 < 0)
@@ -960,11 +960,11 @@ getDSNinfo(ConnInfo *ci, char overwrite)
                        ci->disallow_premature = atoi(temp);
        }
 
-       if (ci->updatable_cursors < 0 || overwrite)
+       if (ci->allow_keyset < 0 || overwrite)
        {
                SQLGetPrivateProfileString(DSN, INI_UPDATABLECURSORS, "", temp, sizeof(temp), ODBC_INI);
                if (temp[0])
-                       ci->updatable_cursors = atoi(temp);
+                       ci->allow_keyset = atoi(temp);
        }
 
        if (ci->lf_conversion < 0 || overwrite)
@@ -1094,7 +1094,7 @@ writeDSNinfo(const ConnInfo *ci)
                                                                 INI_DISALLOWPREMATURE,
                                                                 temp,
                                                                 ODBC_INI);
-       sprintf(temp, "%d", ci->updatable_cursors);
+       sprintf(temp, "%d", ci->allow_keyset);
        SQLWritePrivateProfileString(DSN,
                                                                 INI_UPDATABLECURSORS,
                                                                 temp,
index 7c8f80d..9ac8f8e 100644 (file)
@@ -78,6 +78,12 @@ PGAPI_FreeEnv(HENV henv)
 }
 
 
+static void
+pg_sqlstate_set(const EnvironmentClass *env, UCHAR *szSqlState, const UCHAR *ver3str, const UCHAR *ver2str)
+{
+       strcpy(szSqlState, EN_is_odbc3(env) ? ver3str : ver2str);
+}
+
 #define        DRVMNGRDIV      511
 /*             Returns the next SQL error information. */
 RETCODE                SQL_API
@@ -92,6 +98,7 @@ PGAPI_StmtError(      HSTMT hstmt,
 {
        /* CC: return an error of a hstmt  */
        StatementClass *stmt = (StatementClass *) hstmt;
+       EnvironmentClass *env = (EnvironmentClass *) SC_get_conn(stmt)->henv;
        char            *msg;
        int             status;
        BOOL            partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
@@ -173,120 +180,124 @@ PGAPI_StmtError(        HSTMT hstmt,
                {
                                /* now determine the SQLSTATE to be returned */
                        case STMT_ROW_VERSION_CHANGED:
-                               strcpy(szSqlState, "01001");
+                               pg_sqlstate_set(env, szSqlState, "01001", "01001");
                                /* data truncated */
                                break;
                        case STMT_TRUNCATED:
-                               strcpy(szSqlState, "01004");
+                               pg_sqlstate_set(env, szSqlState, "01004", "01004");
                                /* data truncated */
                                break;
                        case STMT_INFO_ONLY:
-                               strcpy(szSqlState, "00000");
+                               pg_sqlstate_set(env, szSqlState, "00000", "0000");
                                /* just information that is returned, no error */
                                break;
                        case STMT_BAD_ERROR:
-                               strcpy(szSqlState, "08S01");
+                               pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
                                /* communication link failure */
                                break;
                        case STMT_CREATE_TABLE_ERROR:
-                               strcpy(szSqlState, "S0001");
+                               pg_sqlstate_set(env, szSqlState, "42S01", "S0001");
                                /* table already exists */
                                break;
                        case STMT_STATUS_ERROR:
                        case STMT_SEQUENCE_ERROR:
-                               strcpy(szSqlState, "S1010");
+                               pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
                                /* Function sequence error */
                                break;
                        case STMT_NO_MEMORY_ERROR:
-                               strcpy(szSqlState, "S1001");
+                               pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
                                /* memory allocation failure */
                                break;
                        case STMT_COLNUM_ERROR:
-                               strcpy(szSqlState, "S1002");
+                               pg_sqlstate_set(env, szSqlState, "07009", "S1002");
                                /* invalid column number */
                                break;
                        case STMT_NO_STMTSTRING:
-                               strcpy(szSqlState, "S1001");
+                               pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
                                /* having no stmtstring is also a malloc problem */
                                break;
                        case STMT_ERROR_TAKEN_FROM_BACKEND:
-                               strcpy(szSqlState, "S1000");
+                               pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
                                /* general error */
                                break;
                        case STMT_INTERNAL_ERROR:
-                               strcpy(szSqlState, "S1000");
+                               pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
                                /* general error */
                                break;
+                       case STMT_FETCH_OUT_OF_RANGE:
+                               pg_sqlstate_set(env, szSqlState, "HY106", "S1106");
+                               break;
+
                        case STMT_ROW_OUT_OF_RANGE:
-                               strcpy(szSqlState, "S1107");
+                               pg_sqlstate_set(env, szSqlState, "HY107", "S1107");
                                break;
 
                        case STMT_OPERATION_CANCELLED:
-                               strcpy(szSqlState, "S1008");
+                               pg_sqlstate_set(env, szSqlState, "HY008", "S1008");
                                break;
 
                        case STMT_NOT_IMPLEMENTED_ERROR:
-                               strcpy(szSqlState, "S1C00");    /* == 'driver not
+                               pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");     /* == 'driver not
                                                                                                         * capable' */
                                break;
                        case STMT_OPTION_OUT_OF_RANGE_ERROR:
-                               strcpy(szSqlState, "S1092");
+                               pg_sqlstate_set(env, szSqlState, "HY092", "S1092");
                                break;
                        case STMT_BAD_PARAMETER_NUMBER_ERROR:
-                               strcpy(szSqlState, "S1093");
+                               pg_sqlstate_set(env, szSqlState, "07009", "S1093");
                                break;
                        case STMT_INVALID_COLUMN_NUMBER_ERROR:
-                               strcpy(szSqlState, "S1002");
+                               pg_sqlstate_set(env, szSqlState, "07009", "S1002");
                                break;
                        case STMT_RESTRICTED_DATA_TYPE_ERROR:
-                               strcpy(szSqlState, "07006");
+                               pg_sqlstate_set(env, szSqlState, "07006", "07006");
                                break;
                        case STMT_INVALID_CURSOR_STATE_ERROR:
-                               strcpy(szSqlState, "24000");
+                               pg_sqlstate_set(env, szSqlState, "07005", "24000");
                                break;
                        case STMT_ERROR_IN_ROW:
-                               strcpy(szSqlState, "01S01");
+                               pg_sqlstate_set(env, szSqlState, "01S01", "01S01");
                                break;
                        case STMT_OPTION_VALUE_CHANGED:
-                               strcpy(szSqlState, "01S02");
+                               pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
                                break;
                        case STMT_POS_BEFORE_RECORDSET:
-                               strcpy(szSqlState, "01S06");
+                               pg_sqlstate_set(env, szSqlState, "01S06", "01S06");
                                break;
                        case STMT_INVALID_CURSOR_NAME:
-                               strcpy(szSqlState, "34000");
+                               pg_sqlstate_set(env, szSqlState, "34000", "34000");
                                break;
                        case STMT_NO_CURSOR_NAME:
-                               strcpy(szSqlState, "S1015");
+                               pg_sqlstate_set(env, szSqlState, "S1015", "S1015");
                                break;
                        case STMT_INVALID_ARGUMENT_NO:
-                               strcpy(szSqlState, "S1009");
+                               pg_sqlstate_set(env, szSqlState, "HY024", "S1009");
                                /* invalid argument value */
                                break;
                        case STMT_INVALID_CURSOR_POSITION:
-                               strcpy(szSqlState, "S1109");
+                               pg_sqlstate_set(env, szSqlState, "HY109", "S1109");
                                break;
                        case STMT_RETURN_NULL_WITHOUT_INDICATOR:
-                               strcpy(szSqlState, "22002");
+                               pg_sqlstate_set(env, szSqlState, "22002", "22002");
                                break;
                        case STMT_VALUE_OUT_OF_RANGE:
-                               strcpy(szSqlState, "22003");
+                               pg_sqlstate_set(env, szSqlState, "HY019", "22003");
                                break;
                        case STMT_OPERATION_INVALID:
-                               strcpy(szSqlState, "S1011");
+                               pg_sqlstate_set(env, szSqlState, "HY011", "S1011");
                                break;
                        case STMT_INVALID_DESCRIPTOR_IDENTIFIER:
-                               strcpy(szSqlState, "HY091");
+                               pg_sqlstate_set(env, szSqlState, "HY091", "HY091");
                                break;
                        case STMT_INVALID_OPTION_IDENTIFIER:
-                               strcpy(szSqlState, "HY092");
+                               pg_sqlstate_set(env, szSqlState, "HY092", "HY092");
                                break;
                        case STMT_OPTION_NOT_FOR_THE_DRIVER:
-                               strcpy(szSqlState, "HYC00");
+                               pg_sqlstate_set(env, szSqlState, "HYC00", "HYC00");
                                break;
                        case STMT_EXEC_ERROR:
                        default:
-                               strcpy(szSqlState, "S1000");
+                               pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
                                /* also a general error */
                                break;
                }
@@ -314,6 +325,7 @@ PGAPI_ConnectError( HDBC hdbc,
                        UWORD flag)
 {
        ConnectionClass *conn = (ConnectionClass *) hdbc;
+       EnvironmentClass *env = (EnvironmentClass *) conn->henv;
        char            *msg;
        int             status;
        BOOL    once_again = FALSE;
@@ -357,43 +369,43 @@ PGAPI_ConnectError(       HDBC hdbc,
                {
                        case STMT_OPTION_VALUE_CHANGED:
                        case CONN_OPTION_VALUE_CHANGED:
-                               strcpy(szSqlState, "01S02");
+                               pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
                                break;
                        case STMT_TRUNCATED:
                        case CONN_TRUNCATED:
-                               strcpy(szSqlState, "01004");
+                               pg_sqlstate_set(env, szSqlState, "01004", "01004");
                                /* data truncated */
                                break;
                        case CONN_INIREAD_ERROR:
-                               strcpy(szSqlState, "IM002");
+                               pg_sqlstate_set(env, szSqlState, "IM002", "IM002");
                                /* data source not found */
                                break;
                        case CONNECTION_SERVER_NOT_REACHED:
                        case CONN_OPENDB_ERROR:
-                               strcpy(szSqlState, "08001");
+                               pg_sqlstate_set(env, szSqlState, "08001", "08001");
                                /* unable to connect to data source */
                                break;
                        case CONN_INVALID_AUTHENTICATION:
                        case CONN_AUTH_TYPE_UNSUPPORTED:
-                               strcpy(szSqlState, "28000");
+                               pg_sqlstate_set(env, szSqlState, "28000", "28000");
                                break;
                        case CONN_STMT_ALLOC_ERROR:
-                               strcpy(szSqlState, "S1001");
+                               pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
                                /* memory allocation failure */
                                break;
                        case CONN_IN_USE:
-                               strcpy(szSqlState, "S1000");
+                               pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
                                /* general error */
                                break;
                        case CONN_UNSUPPORTED_OPTION:
-                               strcpy(szSqlState, "IM001");
+                               pg_sqlstate_set(env, szSqlState, "IM001", "IM001");
                                /* driver does not support this function */
                        case CONN_INVALID_ARGUMENT_NO:
-                               strcpy(szSqlState, "S1009");
+                               pg_sqlstate_set(env, szSqlState, "HY009", "S1009");
                                /* invalid argument value */
                                break;
                        case CONN_TRANSACT_IN_PROGRES:
-                               strcpy(szSqlState, "S1010");
+                               pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
 
                                /*
                                 * when the user tries to switch commit mode in a
@@ -402,21 +414,21 @@ PGAPI_ConnectError(       HDBC hdbc,
                                /* -> function sequence error */
                                break;
                        case CONN_NO_MEMORY_ERROR:
-                               strcpy(szSqlState, "S1001");
+                               pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
                                break;
                        case CONN_NOT_IMPLEMENTED_ERROR:
                        case STMT_NOT_IMPLEMENTED_ERROR:
-                               strcpy(szSqlState, "S1C00");
+                               pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");
                                break;
                        case STMT_RETURN_NULL_WITHOUT_INDICATOR:
-                               strcpy(szSqlState, "22002");
+                               pg_sqlstate_set(env, szSqlState, "22002", "22002");
                                break;
                        case CONN_VALUE_OUT_OF_RANGE:
                        case STMT_VALUE_OUT_OF_RANGE:
-                               strcpy(szSqlState, "22003");
+                               pg_sqlstate_set(env, szSqlState, "HY019", "22003");
                                break;
                        default:
-                               strcpy(szSqlState, "S1000");
+                               pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
                                /* general error */
                                break;
                }
@@ -455,7 +467,7 @@ PGAPI_EnvError(             HENV henv,
                        mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
                
                if (NULL != szSqlState)
-                       strcpy(szSqlState, "00000");
+                       pg_sqlstate_set(env, szSqlState, "00000", "00000");
                if (NULL != pcbErrorMsg)
                        *pcbErrorMsg = 0;
                if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
@@ -478,10 +490,10 @@ PGAPI_EnvError(           HENV henv,
                {
                        case ENV_ALLOC_ERROR:
                                /* memory allocation failure */
-                               strcpy(szSqlState, "S1001");
+                               pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
                                break;
                        default:
-                               strcpy(szSqlState, "S1000");
+                               pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
                                /* general error */
                                break;
                }
index f82a327..164debb 100644 (file)
@@ -212,6 +212,7 @@ PGAPI_Execute(
        int                     i,
                                retval, start_row, end_row;
        int     cursor_type, scroll_concurrency;
+       QResultClass    *res;
 
        mylog("%s: entering...\n", func);
 
@@ -403,6 +404,23 @@ next_param_row:
                {
                        if (ipdopts->param_processed_ptr)
                                (*ipdopts->param_processed_ptr)++;
+                       /* special handling of result for keyset driven cursors */
+                       if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
+                           SQL_CONCUR_READ_ONLY != stmt->options.scroll_concurrency)
+                       {
+                               QResultClass    *kres;
+
+                               res = SC_get_Result(stmt);
+                               if (kres = res->next, kres)
+                               {
+                                       kres->fields = res->fields;
+                                       res->fields = NULL;
+                                       kres->num_fields = res->num_fields;
+                                       res->next = NULL;
+                                       QR_Destructor(res);
+                                       SC_set_Result(stmt, kres);
+                               }
+                       }
                }
 #if (ODBCVER >= 0x0300)
                if (ipdopts->param_status_ptr)
@@ -440,7 +458,7 @@ next_param_row:
                BOOL            in_trans = CC_is_in_trans(conn);
                BOOL            issued_begin = FALSE,
                                        begin_included = FALSE;
-               QResultClass *res, *curres;
+               QResultClass *curres;
 
                if (strnicmp(stmt->stmt_with_params, "BEGIN;", 6) == 0)
                        begin_included = TRUE;
@@ -474,8 +492,10 @@ next_param_row:
                stmt->status = STMT_FINISHED;
                return SQL_SUCCESS;
        }
-       else if (stmt->options.cursor_type != cursor_type ||
-                stmt->options.scroll_concurrency != scroll_concurrency)
+       if (res = SC_get_Curres(stmt), res)
+               stmt->diag_row_count = res->recent_processed_row_count;
+       if (stmt->options.cursor_type != cursor_type ||
+           stmt->options.scroll_concurrency != scroll_concurrency)
        {
                stmt->errornumber = STMT_OPTION_VALUE_CHANGED;
                stmt->errormsg = "cursor updatability changed";
@@ -548,7 +568,7 @@ PGAPI_Transact(
                if (!res)
                {
                        /* error msg will be in the connection */
-                       CC_on_abort(conn, TRUE);
+                       CC_on_abort(conn, NO_TRANS);
                        CC_log_error(func, "", conn);
                        return SQL_ERROR;
                }
@@ -558,7 +578,7 @@ PGAPI_Transact(
 
                if (!ok)
                {
-                       CC_on_abort(conn, TRUE);
+                       CC_on_abort(conn, NO_TRANS);
                        CC_log_error(func, "", conn);
                        return SQL_ERROR;
                }
index 75deea4..9b9844e 100644 (file)
@@ -210,7 +210,10 @@ PGAPI_GetInfo(
 
                case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */
                        len = 4;
-                       value = SQL_TXN_READ_COMMITTED;         /* SQL_TXN_SERIALIZABLE; */
+                       if (PG_VERSION_LT(conn, 6.5))
+                               value = SQL_TXN_SERIALIZABLE;
+                       else
+                               value = SQL_TXN_READ_COMMITTED;
                        break;
 
                case SQL_DRIVER_NAME:   /* ODBC 1.0 */
@@ -505,7 +508,7 @@ 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);
+                       value = (SQL_POS_POSITION | SQL_POS_REFRESH);
 #ifdef DRIVER_CURSOR_IMPLEMENT
                        if (ci->updatable_cursors)
                                value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD);
@@ -557,32 +560,29 @@ PGAPI_GetInfo(
                         * Driver doesn't support keyset-driven or mixed cursors, so
                         * not much point in saying row updates are supported
                         */
-                       p = (ci->drivers.lie || ci->updatable_cursors) ? "Y" : "N";
+                       p = (ci->updatable_cursors) ? "Y" : "N";
                        break;
 
                case SQL_SCROLL_CONCURRENCY:    /* ODBC 1.0 */
                        len = 4;
-                       value = ci->drivers.lie ? (SQL_SCCO_READ_ONLY |
-                                                                          SQL_SCCO_LOCK |
-                                                                          SQL_SCCO_OPT_ROWVER |
-                                                                          SQL_SCCO_OPT_VALUES) :
-                               (SQL_SCCO_READ_ONLY);
+                       value = SQL_SCCO_READ_ONLY;
 #ifdef DRIVER_CURSOR_IMPLEMENT
                        if (ci->updatable_cursors)
                                value |= SQL_SCCO_OPT_ROWVER;
 #endif /* DRIVER_CURSOR_IMPLEMENT */
+                       if (ci->drivers.lie)
+                               value |= (SQL_SCCO_LOCK | SQL_SCCO_OPT_VALUES);
                        break;
 
                case SQL_SCROLL_OPTIONS:                /* ODBC 1.0 */
                        len = 4;
-                       value = ci->drivers.lie ? (SQL_SO_FORWARD_ONLY |
-                                                                          SQL_SO_STATIC |
-                                                                          SQL_SO_KEYSET_DRIVEN |
-                                                                          SQL_SO_DYNAMIC |
-                                                                          SQL_SO_MIXED)
-                               : (ci->drivers.use_declarefetch ? SQL_SO_FORWARD_ONLY : (SQL_SO_FORWARD_ONLY | SQL_SO_STATIC));
+                       value = SQL_SO_FORWARD_ONLY;
+                       if (!ci->drivers.use_declarefetch)
+                               value |= SQL_SO_STATIC;
                        if (ci->updatable_cursors)
-                               value |= 0;             /* SQL_SO_KEYSET_DRIVEN in the furure */
+                               value |= SQL_SO_KEYSET_DRIVEN;
+                       if (ci->drivers.lie)
+                               value |= (SQL_SO_DYNAMIC | SQL_SO_MIXED);
                        break;
 
                case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
@@ -602,7 +602,7 @@ 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;
+                       value = 0;
 #ifdef DRIVER_CURSOR_IMPLEMENT
                        if (ci->updatable_cursors)
                                value |= (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES);
@@ -666,7 +666,12 @@ PGAPI_GetInfo(
 
                case SQL_TXN_ISOLATION_OPTION:  /* ODBC 1.0 */
                        len = 4;
-                       value = SQL_TXN_READ_COMMITTED;         /* SQL_TXN_SERIALIZABLE; */
+                       if (PG_VERSION_LT(conn, 6.5))
+                               value = SQL_TXN_SERIALIZABLE;
+                       else if (PG_VERSION_GE(conn, 7.1))
+                               value = SQL_TXN_READ_COMMITTED | SQL_TXN_SERIALIZABLE;
+                       else
+                               value = SQL_TXN_READ_COMMITTED;
                        break;
 
                case SQL_UNION: /* ODBC 2.0 */
@@ -2097,7 +2102,7 @@ PGAPI_SpecialColumns(
        RETCODE         result;
        char            relhasrules[MAX_INFO_STRING];
 
-       mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
+       mylog("%s: entering...stmt=%u scnm=%x len=%d colType=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType);
 
        if (!stmt)
        {
@@ -2221,6 +2226,43 @@ PGAPI_SpecialColumns(
                        }
                }
        }
+       else
+       {
+               /* use the oid value for the rowid */
+               if (fColType == SQL_BEST_ROWID)
+               {
+                       row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField));
+
+                       set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION);
+                       set_tuplefield_string(&row->tuple[1], "oid");
+                       set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, PG_TYPE_OID));
+                       set_tuplefield_string(&row->tuple[3], "OID");
+                       set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
+                       set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
+                       set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, PG_TYPE_OID, PG_STATIC));
+                       set_tuplefield_int2(&row->tuple[7], SQL_PC_NOT_PSEUDO);
+
+                       QR_add_tuple(res, row);
+
+               }
+               else if (fColType == SQL_ROWVER)
+               {
+                       Int2            the_type = PG_TYPE_TID;
+
+                       row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField));
+
+                       set_tuplefield_null(&row->tuple[0]);
+                       set_tuplefield_string(&row->tuple[1], "ctid");
+                       set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type));
+                       set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type));
+                       set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
+                       set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
+                       set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
+                       set_tuplefield_int2(&row->tuple[7], SQL_PC_NOT_PSEUDO);
+
+                       QR_add_tuple(res, row);
+               }
+       }
 
        stmt->status = STMT_FINISHED;
        stmt->currTuple = -1;
@@ -3124,7 +3166,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName,
        {
                if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res)
                {
-                       if (QR_get_num_tuples(res) > 0)
+                       if (QR_get_num_backend_tuples(res) > 0)
                                conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
                        QR_Destructor(res);
                }
@@ -3140,7 +3182,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName,
                        relid, serverColumnName);
                if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
                {
-                       if (QR_get_num_tuples(res) > 0)
+                       if (QR_get_num_backend_tuples(res) > 0)
                        {
                                strcpy(saveattnum, QR_get_value_backend_row(res, 0, 0));
                        }
@@ -3165,7 +3207,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName,
        sprintf(query, "select attname from pg_attribute where attrelid = %u and attnum = %s", relid, saveattnum);
        if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
        {
-               if (QR_get_num_tuples(res) > 0)
+               if (QR_get_num_backend_tuples(res) > 0)
                {
                        ret = strdup(QR_get_value_backend_row(res, 0, 0));
                        *nameAlloced = TRUE;
@@ -4135,7 +4177,7 @@ PGAPI_Procedures(
         * The following seems the simplest implementation
         */
        if (conn->schema_support)
-               strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", case when nspname = 'PUBLIC' then ''::text else nspname end as " "PROCEDURE_SCHEM" ","
+               strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", nspname as " "PROCEDURE_SCHEM" ","
                " proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" ","
                   " '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
                   " '' as " "REMARKS" ","
@@ -4204,7 +4246,7 @@ usracl_auth(char *usracl, const char *auth)
 static void
 useracl_upd(char (*useracl)[ACLMAX], QResultClass *allures, const char *user, const char *auth)
 {
-       int usercount = QR_get_num_tuples(allures), i, addcnt = 0;
+       int usercount = QR_get_num_backend_tuples(allures), i, addcnt = 0;
 
 mylog("user=%s auth=%s\n", user, auth);
        if (user[0])
@@ -4315,7 +4357,7 @@ PGAPI_TablePrivileges(
                return SQL_ERROR;
        }
        strncpy_null(proc_query, "select usename, usesysid, usesuper from pg_user", sizeof(proc_query));
-       tablecount = QR_get_num_tuples(res);
+       tablecount = QR_get_num_backend_tuples(res);
        if (allures = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !allures)
        {
                QR_Destructor(res);
@@ -4323,7 +4365,7 @@ PGAPI_TablePrivileges(
                stmt->errormsg = "PGAPI_TablePrivileges query error";
                return SQL_ERROR;
        }
-       usercount = QR_get_num_tuples(allures);
+       usercount = QR_get_num_backend_tuples(allures);
        useracl = (char (*)[ACLMAX]) malloc(usercount * sizeof(char [ACLMAX]));
        for (i = 0; i < tablecount; i++)
        { 
index f92c2ab..5024534 100644 (file)
@@ -38,12 +38,11 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
 
                case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
                        len = 4;
-                       value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
-                               SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK;
+                       value = SQL_CA1_NEXT; /* others aren't allowed in ODBC spec */
                        break;
                case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
                        len = 4;
-                       value = 0;
+                       value = SQL_CA2_READ_ONLY_CONCURRENCY;
                        break;
                case SQL_KEYSET_CURSOR_ATTRIBUTES1:
                        len = 4;
@@ -71,6 +70,8 @@ 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_CRC_APPROXIMATE*/
+                               | SQL_CA2_CRC_EXACT
                                | SQL_CA2_SENSITIVITY_DELETIONS
                                | SQL_CA2_SENSITIVITY_UPDATES
                                /* | SQL_CA2_SENSITIVITY_ADDITIONS */
@@ -85,8 +86,6 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
                                | SQL_CA2_MAX_ROWS_UPDATE
                                | SQL_CA2_MAX_ROWS_CATALOG
                                | SQL_CA2_MAX_ROWS_AFFECTS_ALL
-                               | SQL_CA2_CRC_EXACT
-                               | SQL_CA2_CRC_APPROXIMATE
                                | SQL_CA2_SIMULATE_NON_UNIQUE
                                | SQL_CA2_SIMULATE_TRY_UNIQUE
                                | SQL_CA2_SIMULATE_UNIQUE
@@ -101,6 +100,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
                                | SQL_CA1_POS_REFRESH;
                        if (ci->updatable_cursors)
                                value |= (SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
+                               | SQL_CA1_BULK_ADD
                                );
                        break;
                case SQL_STATIC_CURSOR_ATTRIBUTES2:
@@ -108,6 +108,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
                        value = SQL_CA2_READ_ONLY_CONCURRENCY;
                        if (ci->updatable_cursors)
                                value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
+                               | SQL_CA2_CRC_EXACT
                                /* | SQL_CA2_SENSITIVITY_ADDITIONS
                                | SQL_CA2_SENSITIVITY_DELETIONS
                                | SQL_CA2_SENSITIVITY_UPDATES */
@@ -117,6 +118,8 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
                case SQL_ODBC_INTERFACE_CONFORMANCE:
                        len = 4;
                        value = SQL_OIC_CORE;
+                       if (ci->drivers.lie)
+                               value = SQL_OIC_LEVEL2;
                        break;
                case SQL_ACTIVE_ENVIRONMENTS:
                        len = 2;
index df99994..e482845 100644 (file)
@@ -105,7 +105,7 @@ mylog(char *fmt,...)
                if (!LOGFP)
                {
                        generate_filename(MYLOGDIR, MYLOGFILE, filebuf);
-                       LOGFP = fopen(filebuf, PG_BINARY_W);
+                       LOGFP = fopen(filebuf, PG_BINARY_A);
                        setbuf(LOGFP, NULL);
                }
 
@@ -138,7 +138,7 @@ qlog(char *fmt,...)
                if (!LOGFP)
                {
                        generate_filename(QLOGDIR, QLOGFILE, filebuf);
-                       LOGFP = fopen(filebuf, PG_BINARY_W);
+                       LOGFP = fopen(filebuf, PG_BINARY_A);
                        setbuf(LOGFP, NULL);
                }
 
@@ -284,8 +284,13 @@ schema_strcat(char *buf, const char *fmt, const char *s, int len, const char *tb
 {
        if (!s || 0 == len)
        {
-               if (tbname && (tbnmlen > 0 || tbnmlen == SQL_NTS))
-                       return my_strcat(buf, fmt, "public", 6);
+               /*
+                *      I can find no appropriate way to find
+                *      the CURRENT SCHEMA. If you are lucky
+                *      you can get expected result.
+                */
+               /***** if (tbname && (tbnmlen > 0 || tbnmlen == SQL_NTS))
+                       return my_strcat(buf, fmt, "public", 6); *****/
                return NULL;
        }
        return my_strcat(buf, fmt, s, len);
index fe946ee..161920f 100644 (file)
@@ -77,10 +77,12 @@ extern void qlog(char *fmt,...);
 #define PG_BINARY                      O_BINARY
 #define PG_BINARY_R                    "rb"
 #define PG_BINARY_W                    "wb"
+#define PG_BINARY_A                    "ab"
 #else
 #define PG_BINARY                      0
 #define PG_BINARY_R                    "r"
 #define PG_BINARY_W                    "w"
+#define PG_BINARY_A                    "a"
 #endif
 
 
@@ -91,7 +93,8 @@ char     *make_string(const char *s, int len, char *buf);
 char      *my_strcat(char *buf, const char *fmt, const char *s, int len);
 char      *schema_strcat(char *buf, const char *fmt, const char *s, int len,
                        const char *, int);
-#define        GET_SCHEMA_NAME(nspname)        (stricmp(nspname, "public") ? nspname : "")
+/* #define     GET_SCHEMA_NAME(nspname)        (stricmp(nspname, "public") ? nspname : "") */
+#define        GET_SCHEMA_NAME(nspname)        (nspname)
 
 /* defines for return value of my_strcpy */
 #define STRCPY_SUCCESS         1
index d116d00..6a4a618 100644 (file)
@@ -54,6 +54,7 @@ SQLAllocStmt(HDBC ConnectionHandle,
                         HSTMT *StatementHandle)
 {
        mylog("[SQLAllocStmt]");
+       CC_clear_error((ConnectionClass *) ConnectionHandle);
        return PGAPI_AllocStmt(ConnectionHandle, StatementHandle);
 }
 
@@ -64,6 +65,7 @@ SQLBindCol(HSTMT StatementHandle,
                   SQLINTEGER *StrLen_or_Ind)
 {
        mylog("[SQLBindCol]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_BindCol(StatementHandle, ColumnNumber,
                                   TargetType, TargetValue, BufferLength, StrLen_or_Ind);
 }
@@ -72,6 +74,7 @@ RETCODE               SQL_API
 SQLCancel(HSTMT StatementHandle)
 {
        mylog("[SQLCancel]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_Cancel(StatementHandle);
 }
 
@@ -83,6 +86,7 @@ SQLColumns(HSTMT StatementHandle,
                   SQLCHAR *ColumnName, SQLSMALLINT NameLength4)
 {
        mylog("[SQLColumns]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_Columns(StatementHandle, CatalogName, NameLength1,
                                        SchemaName, NameLength2, TableName, NameLength3,
                                        ColumnName, NameLength4, 0);
@@ -96,6 +100,7 @@ SQLConnect(HDBC ConnectionHandle,
                   SQLCHAR *Authentication, SQLSMALLINT NameLength3)
 {
        mylog("[SQLConnect]");
+       CC_clear_error((ConnectionClass *) ConnectionHandle);
        return PGAPI_Connect(ConnectionHandle, ServerName, NameLength1,
                                         UserName, NameLength2, Authentication, NameLength3);
 }
@@ -111,6 +116,7 @@ SQLDriverConnect(HDBC hdbc,
                                 UWORD fDriverCompletion)
 {
        mylog("[SQLDriverConnect]");
+       CC_clear_error((ConnectionClass *) hdbc);
        return PGAPI_DriverConnect(hdbc, hwnd, szConnStrIn, cbConnStrIn,
                szConnStrOut, cbConnStrOutMax, pcbConnStrOut, fDriverCompletion);
 }
@@ -124,6 +130,7 @@ SQLBrowseConnect(
                                 SQLSMALLINT *pcbConnStrOut)
 {
        mylog("[SQLBrowseConnect]");
+       CC_clear_error((ConnectionClass *) hdbc);
        return PGAPI_BrowseConnect(hdbc, szConnStrIn, cbConnStrIn,
                                                   szConnStrOut, cbConnStrOutMax, pcbConnStrOut);
 }
@@ -153,6 +160,7 @@ SQLDescribeCol(HSTMT StatementHandle,
                           SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable)
 {
        mylog("[SQLDescribeCol]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_DescribeCol(StatementHandle, ColumnNumber,
                                                         ColumnName, BufferLength, NameLength,
                                                  DataType, ColumnSize, DecimalDigits, Nullable);
@@ -162,6 +170,7 @@ RETCODE             SQL_API
 SQLDisconnect(HDBC ConnectionHandle)
 {
        mylog("[SQLDisconnect]");
+       CC_clear_error((ConnectionClass *) ConnectionHandle);
        return PGAPI_Disconnect(ConnectionHandle);
 }
 
@@ -183,6 +192,7 @@ SQLExecDirect(HSTMT StatementHandle,
                          SQLCHAR *StatementText, SQLINTEGER TextLength)
 {
        mylog("[SQLExecDirect]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_ExecDirect(StatementHandle, StatementText, TextLength);
 }
 
@@ -190,6 +200,7 @@ RETCODE             SQL_API
 SQLExecute(HSTMT StatementHandle)
 {
        mylog("[SQLExecute]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_Execute(StatementHandle);
 }
 
@@ -202,6 +213,7 @@ SQLFetch(HSTMT StatementHandle)
        StatementClass *stmt = (StatementClass *) StatementHandle;
        ConnectionClass *conn = SC_get_conn(stmt);
 
+       SC_clear_error(stmt);
        if (conn->driver_version >= 0x0300)
        {
                IRDFields       *irdopts = SC_get_IRD(stmt);
@@ -210,7 +222,7 @@ SQLFetch(HSTMT StatementHandle)
 
                mylog("[[%s]]", func);
                return PGAPI_ExtendedFetch(StatementHandle, SQL_FETCH_NEXT, 0,
-                                                                  pcRow, rowStatusArray);
+                                                                  pcRow, rowStatusArray, 0);
        }
 #endif
        mylog("[%s]", func);
@@ -244,6 +256,7 @@ SQLGetConnectOption(HDBC ConnectionHandle,
                                        SQLUSMALLINT Option, PTR Value)
 {
        mylog("[SQLGetConnectOption]");
+       CC_clear_error((ConnectionClass *) ConnectionHandle);
        return PGAPI_GetConnectOption(ConnectionHandle, Option, Value);
 }
 RETCODE                SQL_API
@@ -252,6 +265,7 @@ SQLGetCursorName(HSTMT StatementHandle,
                                 SQLSMALLINT *NameLength)
 {
        mylog("[SQLGetCursorName]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_GetCursorName(StatementHandle, CursorName, BufferLength,
                                                           NameLength);
 }
@@ -263,6 +277,7 @@ SQLGetData(HSTMT StatementHandle,
                   SQLINTEGER *StrLen_or_Ind)
 {
        mylog("[SQLGetData]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_GetData(StatementHandle, ColumnNumber, TargetType,
                                                 TargetValue, BufferLength, StrLen_or_Ind);
 }
@@ -272,6 +287,7 @@ SQLGetFunctions(HDBC ConnectionHandle,
                                SQLUSMALLINT FunctionId, SQLUSMALLINT *Supported)
 {
        mylog("[SQLGetFunctions]");
+       CC_clear_error((ConnectionClass *) ConnectionHandle);
 #if (ODBCVER >= 0x0300)
        if (FunctionId == SQL_API_ODBC3_ALL_FUNCTIONS)
                return PGAPI_GetFunctions30(ConnectionHandle, FunctionId, Supported);
@@ -315,6 +331,7 @@ SQLGetStmtOption(HSTMT StatementHandle,
                                 SQLUSMALLINT Option, PTR Value)
 {
        mylog("[SQLGetStmtOption]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_GetStmtOption(StatementHandle, Option, Value);
 }
 
@@ -323,6 +340,7 @@ SQLGetTypeInfo(HSTMT StatementHandle,
                           SQLSMALLINT DataType)
 {
        mylog("[SQLGetTypeInfo]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_GetTypeInfo(StatementHandle, DataType);
 }
 
@@ -331,6 +349,7 @@ SQLNumResultCols(HSTMT StatementHandle,
                                 SQLSMALLINT *ColumnCount)
 {
        mylog("[SQLNumResultCols]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_NumResultCols(StatementHandle, ColumnCount);
 }
 
@@ -339,6 +358,7 @@ SQLParamData(HSTMT StatementHandle,
                         PTR *Value)
 {
        mylog("[SQLParamData]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_ParamData(StatementHandle, Value);
 }
 
@@ -347,6 +367,7 @@ SQLPrepare(HSTMT StatementHandle,
                   SQLCHAR *StatementText, SQLINTEGER TextLength)
 {
        mylog("[SQLPrepare]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_Prepare(StatementHandle, StatementText, TextLength);
 }
 
@@ -355,6 +376,7 @@ SQLPutData(HSTMT StatementHandle,
                   PTR Data, SQLINTEGER StrLen_or_Ind)
 {
        mylog("[SQLPutData]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_PutData(StatementHandle, Data, StrLen_or_Ind);
 }
 
@@ -363,6 +385,7 @@ SQLRowCount(HSTMT StatementHandle,
                        SQLINTEGER *RowCount)
 {
        mylog("[SQLRowCount]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_RowCount(StatementHandle, RowCount);
 }
 
@@ -371,6 +394,7 @@ SQLSetConnectOption(HDBC ConnectionHandle,
                                        SQLUSMALLINT Option, SQLUINTEGER Value)
 {
        mylog("[SQLSetConnectionOption]");
+       CC_clear_error((ConnectionClass *) ConnectionHandle);
        return PGAPI_SetConnectOption(ConnectionHandle, Option, Value);
 }
 
@@ -379,6 +403,7 @@ SQLSetCursorName(HSTMT StatementHandle,
                                 SQLCHAR *CursorName, SQLSMALLINT NameLength)
 {
        mylog("[SQLSetCursorName]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_SetCursorName(StatementHandle, CursorName, NameLength);
 }
 
@@ -390,6 +415,7 @@ SQLSetParam(HSTMT StatementHandle,
                        SQLINTEGER *StrLen_or_Ind)
 {
        mylog("[SQLSetParam]");
+       SC_clear_error((StatementClass *) StatementHandle);
 
        /*
         * return PGAPI_SetParam(StatementHandle, ParameterNumber, ValueType,
@@ -404,6 +430,7 @@ SQLSetStmtOption(HSTMT StatementHandle,
                                 SQLUSMALLINT Option, SQLUINTEGER Value)
 {
        mylog("[SQLSetStmtOption]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_SetStmtOption(StatementHandle, Option, Value);
 }
 
@@ -416,6 +443,7 @@ SQLSpecialColumns(HSTMT StatementHandle,
                                  SQLUSMALLINT Nullable)
 {
        mylog("[SQLSpecialColumns]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_SpecialColumns(StatementHandle, IdentifierType, CatalogName,
                        NameLength1, SchemaName, NameLength2, TableName, NameLength3,
                                                                Scope, Nullable);
@@ -429,6 +457,7 @@ SQLStatistics(HSTMT StatementHandle,
                          SQLUSMALLINT Unique, SQLUSMALLINT Reserved)
 {
        mylog("[SQLStatistics]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_Statistics(StatementHandle, CatalogName, NameLength1,
                                 SchemaName, NameLength2, TableName, NameLength3, Unique,
                                                        Reserved);
@@ -442,6 +471,7 @@ SQLTables(HSTMT StatementHandle,
                  SQLCHAR *TableType, SQLSMALLINT NameLength4)
 {
        mylog("[SQLTables]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_Tables(StatementHandle, CatalogName, NameLength1,
                                                SchemaName, NameLength2, TableName, NameLength3,
                                                TableType, NameLength4);
@@ -466,6 +496,7 @@ SQLColAttributes(
                                 SQLINTEGER *pfDesc)
 {
        mylog("[SQLColAttributes]");
+       SC_clear_error((StatementClass *) hstmt);
        return PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc,
                                                           cbDescMax, pcbDesc, pfDesc);
 }
@@ -483,6 +514,7 @@ SQLColumnPrivileges(
                                        SQLSMALLINT cbColumnName)
 {
        mylog("[SQLColumnPrivileges]");
+       SC_clear_error((StatementClass *) hstmt);
        return PGAPI_ColumnPrivileges(hstmt, szCatalogName, cbCatalogName,
                                        szSchemaName, cbSchemaName, szTableName, cbTableName,
                                                                  szColumnName, cbColumnName);
@@ -498,6 +530,7 @@ SQLDescribeParam(
                                 SQLSMALLINT *pfNullable)
 {
        mylog("[SQLDescribeParam]");
+       SC_clear_error((StatementClass *) hstmt);
        return PGAPI_DescribeParam(hstmt, ipar, pfSqlType, pcbParamDef,
                                                           pibScale, pfNullable);
 }
@@ -511,7 +544,8 @@ SQLExtendedFetch(
                                 SQLUSMALLINT *rgfRowStatus)
 {
        mylog("[SQLExtendedFetch]");
-       return PGAPI_ExtendedFetch(hstmt, fFetchType, irow, pcrow, rgfRowStatus);
+       SC_clear_error((StatementClass *) hstmt);
+       return PGAPI_ExtendedFetch(hstmt, fFetchType, irow, pcrow, rgfRowStatus, 0);
 }
 
 RETCODE                SQL_API
@@ -531,6 +565,7 @@ SQLForeignKeys(
                           SQLSMALLINT cbFkTableName)
 {
        mylog("[SQLForeignKeys]");
+       SC_clear_error((StatementClass *) hstmt);
        return PGAPI_ForeignKeys(hstmt, szPkCatalogName, cbPkCatalogName,
                                                   szPkSchemaName, cbPkSchemaName, szPkTableName,
                                                 cbPkTableName, szFkCatalogName, cbFkCatalogName,
@@ -541,6 +576,7 @@ RETCODE             SQL_API
 SQLMoreResults(HSTMT hstmt)
 {
        mylog("[SQLMoreResults]");
+       SC_clear_error((StatementClass *) hstmt);
        return PGAPI_MoreResults(hstmt);
 }
 
@@ -554,6 +590,7 @@ SQLNativeSql(
                         SQLINTEGER *pcbSqlStr)
 {
        mylog("[SQLNativeSql]");
+       CC_clear_error((ConnectionClass *) hdbc);
        return PGAPI_NativeSql(hdbc, szSqlStrIn, cbSqlStrIn, szSqlStr,
                                                   cbSqlStrMax, pcbSqlStr);
 }
@@ -564,6 +601,7 @@ SQLNumParams(
                         SQLSMALLINT *pcpar)
 {
        mylog("[SQLNumParams]");
+       SC_clear_error((StatementClass *) hstmt);
        return PGAPI_NumParams(hstmt, pcpar);
 }
 
@@ -574,6 +612,7 @@ SQLParamOptions(
                                SQLUINTEGER *pirow)
 {
        mylog("[SQLParamOptions]");
+       SC_clear_error((StatementClass *) hstmt);
        return PGAPI_ParamOptions(hstmt, crow, pirow);
 }
 
@@ -588,6 +627,7 @@ SQLPrimaryKeys(
                           SQLSMALLINT cbTableName)
 {
        mylog("[SQLPrimaryKeys]");
+       SC_clear_error((StatementClass *) hstmt);
        return PGAPI_PrimaryKeys(hstmt, szCatalogName, cbCatalogName,
                                   szSchemaName, cbSchemaName, szTableName, cbTableName);
 }
@@ -605,6 +645,7 @@ SQLProcedureColumns(
                                        SQLSMALLINT cbColumnName)
 {
        mylog("[SQLProcedureColumns]");
+       SC_clear_error((StatementClass *) hstmt);
        return PGAPI_ProcedureColumns(hstmt, szCatalogName, cbCatalogName,
                                          szSchemaName, cbSchemaName, szProcName, cbProcName,
                                                                  szColumnName, cbColumnName);
@@ -621,6 +662,7 @@ SQLProcedures(
                          SQLSMALLINT cbProcName)
 {
        mylog("[SQLProcedures]");
+       SC_clear_error((StatementClass *) hstmt);
        return PGAPI_Procedures(hstmt, szCatalogName, cbCatalogName,
                                         szSchemaName, cbSchemaName, szProcName, cbProcName);
 }
@@ -633,6 +675,7 @@ SQLSetPos(
                  SQLUSMALLINT fLock)
 {
        mylog("[SQLSetPos]");
+       SC_clear_error((StatementClass *) hstmt);
        return PGAPI_SetPos(hstmt, irow, fOption, fLock);
 }
 
@@ -647,6 +690,7 @@ SQLTablePrivileges(
                                   SQLSMALLINT cbTableName)
 {
        mylog("[SQLTablePrivileges]");
+       SC_clear_error((StatementClass *) hstmt);
        return PGAPI_TablePrivileges(hstmt, szCatalogName, cbCatalogName,
                                   szSchemaName, cbSchemaName, szTableName, cbTableName, 0);
 }
@@ -665,6 +709,7 @@ SQLBindParameter(
                                 SQLINTEGER *pcbValue)
 {
        mylog("[SQLBindParameter]");
+       SC_clear_error((StatementClass *) hstmt);
        return PGAPI_BindParameter(hstmt, ipar, fParamType, fCType,
                                           fSqlType, cbColDef, ibScale, rgbValue, cbValueMax,
                                                           pcbValue);
index 0c03007..cf73924 100644 (file)
@@ -61,6 +61,7 @@ SQLBindParam(HSTMT StatementHandle,
        int                     BufferLength = 512;             /* Is it OK ? */
 
        mylog("[[SQLBindParam]]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_BindParameter(StatementHandle, ParameterNumber, SQL_PARAM_INPUT, ValueType, ParameterType, LengthPrecision, ParameterScale, ParameterValue, BufferLength, StrLen_or_Ind);
 }
 
@@ -69,6 +70,7 @@ RETCODE               SQL_API
 SQLCloseCursor(HSTMT StatementHandle)
 {
        mylog("[[SQLCloseCursor]]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_FreeStmt(StatementHandle, SQL_CLOSE);
 }
 
@@ -80,6 +82,7 @@ SQLColAttribute(HSTMT StatementHandle,
                                SQLSMALLINT *StringLength, PTR NumericAttribute)
 {
        mylog("[[SQLColAttribute]]");
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_ColAttributes(StatementHandle, ColumnNumber,
                                           FieldIdentifier, CharacterAttribute, BufferLength,
                                                           StringLength, NumericAttribute);
@@ -140,6 +143,7 @@ SQLEndTran(SQLSMALLINT HandleType, SQLHANDLE Handle,
                case SQL_HANDLE_ENV:
                        return PGAPI_Transact(Handle, SQL_NULL_HDBC, CompletionType);
                case SQL_HANDLE_DBC:
+                       CC_clear_error((ConnectionClass *) Handle);
                        return PGAPI_Transact(SQL_NULL_HENV, Handle, CompletionType);
                default:
                        break;
@@ -157,16 +161,18 @@ SQLFetchScroll(HSTMT StatementHandle,
        RETCODE         ret;
        IRDFields       *irdopts = SC_get_IRD(stmt);
        SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray;
-       SQLINTEGER *pcRow = irdopts->rowsFetched;
+       SQLINTEGER *pcRow = irdopts->rowsFetched, bkmarkoff = 0;
 
        mylog("[[%s]] %d,%d\n", func, FetchOrientation, FetchOffset);
+       SC_clear_error(stmt);
        if (FetchOrientation == SQL_FETCH_BOOKMARK)
        {
                if (stmt->options.bookmark_ptr)
-{
-                       FetchOffset += *((Int4 *) stmt->options.bookmark_ptr);
-mylog("real FetchOffset = %d\n", FetchOffset);
-}
+               {
+                       bkmarkoff = FetchOffset;
+                       FetchOffset = *((Int4 *) stmt->options.bookmark_ptr);
+mylog("bookmark=%u FetchOffset = %d\n", FetchOffset, bkmarkoff);
+               }
                else
                {
                        stmt->errornumber = STMT_SEQUENCE_ERROR;
@@ -176,7 +182,7 @@ mylog("real FetchOffset = %d\n", FetchOffset);
                }
        }
        ret = PGAPI_ExtendedFetch(StatementHandle, FetchOrientation, FetchOffset,
-                                                         pcRow, rowStatusArray);
+                               pcRow, rowStatusArray, bkmarkoff);
        if (ret != SQL_SUCCESS)
                mylog("%s return = %d\n", func, ret);
        return ret;
@@ -288,6 +294,7 @@ SQLGetConnectAttr(HDBC ConnectionHandle,
                                  SQLINTEGER BufferLength, SQLINTEGER *StringLength)
 {
        mylog("[[SQLGetConnectAttr]] %d\n", Attribute);
+       CC_clear_error((ConnectionClass *) ConnectionHandle);
        return PGAPI_GetConnectAttr(ConnectionHandle, Attribute,Value,
                        BufferLength, StringLength);
 }
@@ -301,6 +308,7 @@ SQLGetStmtAttr(HSTMT StatementHandle,
        static char *func = "SQLGetStmtAttr";
 
        mylog("[[%s]] Handle=%u %d\n", func, StatementHandle, Attribute);
+       SC_clear_error((StatementClass *) StatementHandle);
        return PGAPI_GetStmtAttr(StatementHandle, Attribute, Value,
                        BufferLength, StringLength);
 }
@@ -314,6 +322,7 @@ SQLSetConnectAttr(HDBC ConnectionHandle,
        ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
 
        mylog("[[SQLSetConnectAttr]] %d\n", Attribute);
+       CC_clear_error(conn);
        return PGAPI_SetConnectAttr(ConnectionHandle, Attribute, Value,
                                  StringLength);
 }
@@ -396,6 +405,7 @@ SQLSetStmtAttr(HSTMT StatementHandle,
        StatementClass *stmt = (StatementClass *) StatementHandle;
 
        mylog("[[%s]] Handle=%u %d,%u\n", func, StatementHandle, Attribute, Value);
+       SC_clear_error(stmt);
        return PGAPI_SetStmtAttr(StatementHandle, Attribute, Value, StringLength);
 }
 
@@ -409,6 +419,7 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
        ConnectionClass *conn = (ConnectionClass *) hdbc;
        ConnInfo        *ci = &(conn->connInfo);
 
+       CC_clear_error(conn);
        if (fFunction != SQL_API_ODBC3_ALL_FUNCTIONS)
                return SQL_ERROR;
        memset(pfExists, 0, sizeof(UWORD) * SQL_API_ODBC3_ALL_FUNCTIONS_SIZE);
@@ -497,12 +508,12 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
        SQL_FUNC_ESET(pfExists, SQL_API_SQLENDTRAN);            /* 1005 */
        SQL_FUNC_ESET(pfExists, SQL_API_SQLFREEHANDLE);         /* 1006 */
        SQL_FUNC_ESET(pfExists, SQL_API_SQLGETCONNECTATTR);     /* 1007 */
+       SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCFIELD);       /* 1008 */
        if (ci->drivers.lie)
        {
-               SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCFIELD); /* 1008 not implemented yet */
                SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCREC); /* 1009 not implemented yet */
-               SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGFIELD); /* 1010 not implemented yet */
        }
+       SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGFIELD); /* 1010 minimal implementation */
        SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGREC);         /* 1011 */
        SQL_FUNC_ESET(pfExists, SQL_API_SQLGETENVATTR);         /* 1012 */
        SQL_FUNC_ESET(pfExists, SQL_API_SQLGETSTMTATTR);        /* 1014 */
@@ -525,72 +536,15 @@ RETCODE   SQL_API
 SQLBulkOperations(HSTMT hstmt, SQLSMALLINT operation)
 {
        static char     *func = "SQLBulkOperations";
-       StatementClass  *stmt = (StatementClass *) hstmt;
 #ifndef        DRIVER_CURSOR_IMPLEMENT
+       StatementClass  *stmt = (StatementClass *) hstmt;
        stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
        stmt->errormsg = "driver must be compiled with the DRIVER_CURSOR_IMPLEMENT option";
        SC_log_error(func, "", stmt);
        return SQL_ERROR;
 #else
-       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;
+       mylog("[[%s]] Handle=%u %d\n", func, hstmt, operation);
+       SC_clear_error((StatementClass *) hstmt);
+       return  PGAPI_BulkOperations(hstmt, operation);
 #endif /* DRIVER_CURSOR_IMPLEMENT */
 }      
index ac0f1d9..8992353 100644 (file)
@@ -30,6 +30,7 @@ RETCODE       SQL_API SQLGetStmtAttrW(SQLHSTMT hstmt,
        RETCODE ret;
 
        mylog("[SQLGetStmtAttrW]");
+       SC_clear_error((StatementClass *) hstmt);
        ret = PGAPI_GetStmtAttr(hstmt, fAttribute, rgbValue,
                cbValueMax, pcbValue);
        return ret;
@@ -43,6 +44,7 @@ RETCODE SQL_API       SQLSetStmtAttrW(SQLHSTMT hstmt,
        RETCODE ret;
 
        mylog("[SQLSetStmtAttrW]");
+       SC_clear_error((StatementClass *) hstmt);
        ret = PGAPI_SetStmtAttr(hstmt, fAttribute, rgbValue,
                cbValueMax);
        return ret;
@@ -57,6 +59,7 @@ RETCODE SQL_API       SQLGetConnectAttrW(HDBC hdbc,
        RETCODE ret;
 
        mylog("[SQLGetConnectAttrW]");
+       CC_clear_error((ConnectionClass *) hdbc);
        ret = PGAPI_GetConnectAttr(hdbc, fAttribute, rgbValue,
                cbValueMax, pcbValue);
        return ret;
@@ -70,6 +73,7 @@ RETCODE SQL_API       SQLSetConnectAttrW(HDBC hdbc,
        RETCODE ret;
 
        mylog("[SQLSetConnectAttrW]");
+       CC_clear_error((ConnectionClass *) hdbc);
        ret = PGAPI_SetConnectAttr(hdbc, fAttribute, rgbValue,
                cbValue);
        return ret;
@@ -229,6 +233,7 @@ RETCODE SQL_API SQLColAttributeW(
         char    *rgbD = NULL;
 
        mylog("[SQLColAttributeW]");
+       SC_clear_error((StatementClass *) hstmt);
        switch (fDescType)
        { 
                case SQL_DESC_BASE_COLUMN_NAME:
index ab974c3..f4a510a 100644 (file)
@@ -95,9 +95,13 @@ set_statement_option(ConnectionClass *conn,
                                ;
                        else if (SQL_CURSOR_STATIC == vParam)
                                setval = vParam;
-                       /** else if (SQL_CURSOR_KEYSET_DRIVEN == vParam && ci->updatable)
-                               setval = vParam; **/
-
+                       else if (SQL_CURSOR_KEYSET_DRIVEN == vParam)
+                       {
+                               if (ci->updatable_cursors)
+                                       setval = vParam;
+                               else
+                                       setval = SQL_CURSOR_STATIC; /* at least scrollable */
+                       }
                        if (conn)
                                conn->stmtOptions.cursor_type = setval;
                        else if (stmt)
@@ -372,6 +376,60 @@ PGAPI_SetConnectOption(
                        break;
 
                case SQL_TXN_ISOLATION: /* ignored */
+                       retval = SQL_SUCCESS;
+                        if (CC_is_in_trans(conn))
+                       {
+                               conn->errormsg = "Cannot switch isolation level while a transaction is in progress";
+                               conn->errornumber = CONN_TRANSACT_IN_PROGRES;
+                               CC_log_error(func, "", conn);
+                               return SQL_ERROR;
+                       }
+                       if (conn->isolation == vParam)
+                               break; 
+                       switch (vParam)
+                       {
+                               case SQL_TXN_SERIALIZABLE:
+                                       if (PG_VERSION_GE(conn, 6.5) &&
+                                           PG_VERSION_LE(conn, 7.0))
+                                               retval = SQL_ERROR;
+                                       break;
+                               case SQL_TXN_READ_COMMITTED:
+                                       if (PG_VERSION_LT(conn, 6.5))
+                                               retval = SQL_ERROR;
+                                       break;
+                               default:
+                                       retval = SQL_ERROR;
+                       }
+                       if (SQL_ERROR == retval)
+                       {
+                               conn->errornumber = CONN_INVALID_ARGUMENT_NO;
+                               conn->errormsg = "Illegal parameter value for SQL_TXN_ISOLATION";
+                               CC_log_error(func, "", conn);
+                               return SQL_ERROR;
+                       }
+                       else
+                       {
+                               char *query;
+                               QResultClass *res;
+
+                               if (vParam == SQL_TXN_SERIALIZABLE)
+                                       query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE";
+                               else
+                                       query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED";
+                               res = CC_send_query(conn, query, NULL, 0);
+                               if (!res || !QR_command_maybe_successful(res))
+                                       retval = SQL_ERROR;
+                               else
+                                       conn->isolation = vParam;
+                               if (res)
+                                       QR_Destructor(res);
+                               if (SQL_ERROR == retval)
+                               {
+                                       conn->errornumber = STMT_EXEC_ERROR;
+                                       conn->errormsg = "ISOLATION change request to the server error";
+                                       return SQL_ERROR;
+                               }
+                       }
                        break;
 
                        /* These options should be handled by driver manager */
@@ -476,8 +534,8 @@ PGAPI_GetConnectOption(
                        *((UDWORD *) pvParam) = (UDWORD) NULL;
                        break;
 
-               case SQL_TXN_ISOLATION: /* NOT SUPPORTED */
-                       *((UDWORD *) pvParam) = SQL_TXN_READ_COMMITTED;
+               case SQL_TXN_ISOLATION:
+                       *((UDWORD *) pvParam) = conn->isolation;
                        break;
 
                        /* These options should be handled by driver manager */
@@ -567,7 +625,7 @@ PGAPI_GetStmtOption(
                        {
                                /* make sure we're positioned on a valid row */
                                if ((stmt->currTuple < 0) ||
-                                       (stmt->currTuple >= QR_get_num_tuples(res)))
+                                       (stmt->currTuple >= QR_get_num_backend_tuples(res)))
                                {
                                        stmt->errormsg = "Not positioned on a valid row.";
                                        stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
index cb77fdd..2ca0ef0 100644 (file)
@@ -50,6 +50,29 @@ char    *getNextToken(char *s, char *token, int smax, char *delim, char *quote,
 void           getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
 char           searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
 
+Int4 FI_precision(const FIELD_INFO *fi)
+{
+       if (!fi)        return -1;
+       switch (fi->type)
+       {
+               case PG_TYPE_NUMERIC:
+                       return fi->column_size;
+               case PG_TYPE_DATETIME:
+               case PG_TYPE_TIMESTAMP_NO_TMZONE:
+                       return fi->decimal_digits;
+       }
+       return 0;
+}
+Int4 FI_scale(const FIELD_INFO *fi)
+{
+       if (!fi)        return -1;
+       switch (fi->type)
+       {
+               case PG_TYPE_NUMERIC:
+                       return fi->decimal_digits;
+       }
+       return 0;
+}
 
 char *
 getNextToken(
@@ -265,7 +288,7 @@ searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
                                cmp;
        char       *col;
 
-       for (k = 0; k < QR_get_num_tuples(col_info->result); k++)
+       for (k = 0; k < QR_get_num_backend_tuples(col_info->result); k++)
        {
                col = QR_get_value_manual(col_info->result, k, 3);
                if (fi->dquote)
@@ -291,7 +314,7 @@ char
 parse_statement(StatementClass *stmt)
 {
        static char *func = "parse_statement";
-       char            token[256];
+       char            token[256], stoken[256];
        char            delim,
                                quote,
                                dquote,
@@ -315,7 +338,7 @@ parse_statement(StatementClass *stmt)
                                i,
                                k = 0,
                                n,
-                               blevel = 0;
+                               blevel = 0, old_blevel, subqlevel = 0;
        FIELD_INFO **fi;
        TABLE_INFO **ti;
        char            parse;
@@ -347,42 +370,43 @@ parse_statement(StatementClass *stmt)
 
                mylog("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delim, token, ptr);
 
-               if (in_select && unquoted && blevel == 0)
+               old_blevel = blevel;
+               if (unquoted && blevel == 0)
                {
-                       if (!stricmp(token, "distinct"))
+                       if (in_select)
                        {
-                               in_distinct = TRUE;
-                               updatable = FALSE;
+                               if (!stricmp(token, "distinct"))
+                               {
+                                       in_distinct = TRUE;
+                                       updatable = FALSE;
 
-                               mylog("DISTINCT\n");
-                               continue;
-                       }
-                       if (!stricmp(token, "into"))
-                       {
-                               in_select = FALSE;
-                               mylog("INTO\n");
-                               stmt->statement_type = STMT_TYPE_CREATE;
-                               stmt->parse_status = STMT_PARSE_FATAL;
-                               return FALSE;
-                       }
-                       if (!stricmp(token, "from"))
-                       {
-                               in_select = FALSE;
-                               in_from = TRUE;
-                               if (stmt->from_pos < 0 &&
-                                       (!strnicmp(pptr, "from", 4)))
+                                       mylog("DISTINCT\n");
+                                       continue;
+                               }
+                               else if (!stricmp(token, "into"))
                                {
-                                       mylog("First ");
-                                       stmt->from_pos = pptr - stmt->statement;
+                                       in_select = FALSE;
+                                       mylog("INTO\n");
+                                       stmt->statement_type = STMT_TYPE_CREATE;
+                                       stmt->parse_status = STMT_PARSE_FATAL;
+                                       return FALSE;
                                }
+                               else if (!stricmp(token, "from"))
+                               {
+                                       in_select = FALSE;
+                                       in_from = TRUE;
+                                       if (stmt->from_pos < 0 &&
+                                               (!strnicmp(pptr, "from", 4)))
+                                       {
+                                               mylog("First ");
+                                               stmt->from_pos = pptr - stmt->statement;
+                                       }
 
-                               mylog("FROM\n");
-                               continue;
-                       }
-               } /* in_select && unquoted && blevel == 0 */
-               if (unquoted && blevel == 0)
-               {
-                       if ((!stricmp(token, "where") ||
+                                       mylog("FROM\n");
+                                       continue;
+                               }
+                       } /* in_select && unquoted && blevel == 0 */
+                       else if ((!stricmp(token, "where") ||
                                 !stricmp(token, "union") ||
                                 !stricmp(token, "intersect") ||
                                 !stricmp(token, "except") ||
@@ -390,7 +414,6 @@ parse_statement(StatementClass *stmt)
                                 !stricmp(token, "group") ||
                                 !stricmp(token, "having")))
                        {
-                               in_select = FALSE;
                                in_from = FALSE;
                                in_where = TRUE;
 
@@ -406,54 +429,82 @@ parse_statement(StatementClass *stmt)
                                continue;
                        }
                } /* unquoted && blevel == 0 */
-               if (in_select && (in_expr || in_func))
+               /* check the change of blevel etc */
+               if (unquoted)
                {
-                       /* just eat the expression */
-                       mylog("in_expr=%d or func=%d\n", in_expr, in_func);
-
-                       if (unquoted)
+                       if (!stricmp(token, "select"))
                        {
-                               if (token[0] == '(')
+                               stoken[0] = '\0';
+                               if (0 == blevel)
                                {
-                                       blevel++;
-                                       mylog("blevel++ = %d\n", blevel);
+                                       in_select = TRUE; 
+                                       mylog("SELECT\n");
+                                       continue;
                                }
-                               else if (token[0] == ')')
+                               else
                                {
-                                       blevel--;
-                                       mylog("blevel-- = %d\n", blevel);
+                                       mylog("SUBSELECT\n");
+                                       if (0 == subqlevel)
+                                               subqlevel = blevel;
                                }
                        }
-                       if (blevel == 0)
+                       else if (token[0] == '(')
                        {
-                               if (delim == ',')
+                               blevel++;
+                               mylog("blevel++ = %d\n", blevel);
+                               /* aggregate function ? */
+                               if (stoken[0] && updatable && 0 == subqlevel)
                                {
-                                       mylog("**** Got comma in_expr/func\n");
-                                       in_func = FALSE;
-                                       in_expr = FALSE;
-                                       in_field = FALSE;
-                               }
-                               else if (unquoted && !stricmp(token, "as"))
-                               {
-                                       mylog("got AS in_expr\n");
-                                       in_func = FALSE;
-                                       in_expr = FALSE;
-                                       in_as = TRUE;
-                                       in_field = TRUE;
+                                       if (stricmp(stoken, "count") == 0 ||
+                                           stricmp(stoken, "sum") == 0 ||
+                                           stricmp(stoken, "avg") == 0 ||
+                                           stricmp(stoken, "max") == 0 ||
+                                           stricmp(stoken, "min") == 0 ||
+                                           stricmp(stoken, "variance") == 0 ||
+                                           stricmp(stoken, "stddev") == 0)
+                                               updatable = FALSE;
                                }
                        }
-                       continue;
-               } /* in_select && (in_expr || in_func) */
-
-               if (unquoted && !stricmp(token, "select"))
-               {
-                       in_select = TRUE;
-
-                       mylog("SELECT\n");
-                       continue;
+                       else if (token[0] == ')')
+                       {
+                               blevel--;
+                               mylog("blevel-- = %d\n", blevel);
+                               if (blevel < subqlevel)
+                                       subqlevel = 0;
+                       }
+                       if (blevel >= old_blevel && ',' != delim)
+                               strcpy(stoken, token);
+                       else
+                               stoken[0] = '\0';
                }
                if (in_select)
                {
+                       if (in_expr || in_func)
+                       {
+                               /* just eat the expression */
+                               mylog("in_expr=%d or func=%d\n", in_expr, in_func);
+
+                               if (blevel == 0)
+                               {
+                                       if (delim == ',')
+                                       {
+                                               mylog("**** Got comma in_expr/func\n");
+                                               in_func = FALSE;
+                                               in_expr = FALSE;
+                                               in_field = FALSE;
+                                       }
+                                       else if (unquoted && !stricmp(token, "as"))
+                                       {
+                                               mylog("got AS in_expr\n");
+                                               in_func = FALSE;
+                                               in_expr = FALSE;
+                                               in_as = TRUE;
+                                               in_field = TRUE;
+                                       }
+                               }
+                               continue;
+                       } /* (in_expr || in_func) && in_select */
+
                        if (in_distinct)
                        {
                                mylog("in distinct\n");
@@ -515,12 +566,11 @@ parse_statement(StatementClass *stmt)
                                        mylog("**** got numeric: nfld = %d\n", irdflds->nfields);
                                        fi[irdflds->nfields]->numeric = TRUE;
                                }
-                               else if (token[0] == '(')
+                               else if (0 == old_blevel && blevel > 0)
                                {                               /* expression */
                                        mylog("got EXPRESSION\n");
                                        fi[irdflds->nfields++]->expr = TRUE;
                                        in_expr = TRUE;
-                                       blevel = 1;
                                        continue;
                                }
                                else
@@ -579,11 +629,10 @@ parse_statement(StatementClass *stmt)
                        }
 
                        /* Function */
-                       if (token[0] == '(')
+                       if (0 == old_blevel && blevel > 0)
                        {
                                in_dot = FALSE;
                                in_func = TRUE;
-                               blevel = 1;
                                fi[irdflds->nfields - 1]->func = TRUE;
 
                                /*
@@ -654,6 +703,7 @@ parse_statement(StatementClass *stmt)
 
                                ti[stmt->ntab]->schema[0] = '\0';
                                ti[stmt->ntab]->alias[0] = '\0';
+                               ti[stmt->ntab]->updatable = 1;
 
                                strcpy(ti[stmt->ntab]->name, token);
                                if (!dquote)
@@ -845,6 +895,37 @@ parse_statement(StatementClass *stmt)
                        col_stmt = (StatementClass *) hcol_stmt;
                        col_stmt->internal = TRUE;
 
+                       if (!ti[i]->schema[0] && conn->schema_support)
+                       {
+                               QResultClass    *res;
+                               BOOL            tblFound = FALSE;
+
+                               /* Unfortunately CURRENT_SCHEMA doesn't exist
+                                * in PostgreSQL and we have to check as follows.
+                                */
+                               sprintf(token, "select nspname from pg_namespace n, pg_class c"
+                                       " where c.relnamespace=n.oid and c.oid='%s'::regclass", ti[i]->name);
+                               res = CC_send_query(conn, token, NULL, CLEAR_RESULT_ON_ABORT);
+                               if (res)
+                               {
+                                       if (QR_get_num_total_tuples(res) == 1)
+                                       {
+                                               tblFound = TRUE;
+                                               strcpy(ti[i]->schema, QR_get_value_backend_row(res, 0, 0));
+                                       }
+                                       QR_Destructor(res);
+                               }
+                               else
+                                       CC_abort(conn);
+                               if (!tblFound)
+                               {
+                                       stmt->parse_status = STMT_PARSE_FATAL;
+                                       stmt->errornumber = STMT_EXEC_ERROR;
+                                       stmt->errormsg = "Table not found";
+                                       stmt->updatable = FALSE;
+                                       return FALSE;
+                               }
+                       }
                        result = PGAPI_Columns(hcol_stmt, "", 0, ti[i]->schema,
                                         SQL_NTS, ti[i]->name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN);
 
@@ -907,6 +988,8 @@ parse_statement(StatementClass *stmt)
        /*
         * Now resolve the fields to point to column info
         */
+       if (updatable && 1 == stmt->ntab)
+               updatable = stmt->ti[0]->updatable;
        for (i = 0; i < (int) irdflds->nfields;)
        {
                fi[i]->updatable = updatable;
@@ -934,14 +1017,14 @@ parse_statement(StatementClass *stmt)
 
                        if (fi[i]->ti)          /* The star represents only the qualified
                                                                 * table */
-                               total_cols = QR_get_num_tuples(fi[i]->ti->col_info->result);
+                               total_cols = QR_get_num_backend_tuples(fi[i]->ti->col_info->result);
 
                        else
                        {                                       /* The star represents all tables */
 
                                /* Calculate the total number of columns after expansion */
                                for (k = 0; k < stmt->ntab; k++)
-                                       total_cols += QR_get_num_tuples(ti[k]->col_info->result);
+                                       total_cols += QR_get_num_backend_tuples(ti[k]->col_info->result);
                        }
                        increased_cols = total_cols - 1;
 
@@ -988,7 +1071,7 @@ parse_statement(StatementClass *stmt)
                        {
                                TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
 
-                               cols = QR_get_num_tuples(the_ti->col_info->result);
+                               cols = QR_get_num_backend_tuples(the_ti->col_info->result);
 
                                for (n = 0; n < cols; n++)
                                {
index e737739..7fd6c9a 100644 (file)
@@ -25,6 +25,7 @@
 #include "connection.h"
 #include "statement.h"
 #include "descriptor.h"
+#include "qresult.h"
 #include "pgapifunc.h"
 
 static HSTMT statementHandleFromDescHandle(SQLHDESC, SQLINTEGER *descType); 
@@ -69,13 +70,22 @@ PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
        return ret;
 }
 
+/*
+ *     Minimal implementation. 
+ *
+ */
 RETCODE                SQL_API
 PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
                SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier,
                PTR DiagInfoPtr, SQLSMALLINT BufferLength,
                SQLSMALLINT *StringLengthPtr)
 {
-       RETCODE         ret = SQL_ERROR;
+       RETCODE         ret = SQL_ERROR, rtn;
+       ConnectionClass *conn;
+       SQLHANDLE       stmtHandle;
+       StatementClass  *stmt;
+       SDWORD          rc;
+       SWORD           pcbErrm;
        static const char *func = "PGAPI_GetDiagField";
 
        mylog("%s entering rec=%d", func, RecNumber);
@@ -87,43 +97,243 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
                                case SQL_DIAG_CLASS_ORIGIN:
                                case SQL_DIAG_SUBCLASS_ORIGIN:
                                case SQL_DIAG_CONNECTION_NAME:
+                               case SQL_DIAG_SERVER_NAME:
+                                       strcpy((char *) DiagInfoPtr, "");
+                                       if (StringLengthPtr)
+                                               *StringLengthPtr = 0;
+                                       ret = SQL_SUCCESS;
+                                       break;
                                case SQL_DIAG_MESSAGE_TEXT:
+                                       ret = PGAPI_EnvError(Handle, RecNumber,
+                                               NULL, NULL, DiagInfoPtr,
+                                               BufferLength, StringLengthPtr, 0);  
+                                       break;
                                case SQL_DIAG_NATIVE:
+                                       ret = PGAPI_EnvError(Handle, RecNumber,
+                                               NULL, DiagInfoPtr, NULL,
+                                               0, NULL, 0);  
+                                       if (StringLengthPtr)  
+                                               *StringLengthPtr = sizeof(SQLINTEGER);  
+                                       if (SQL_SUCCESS_WITH_INFO == ret)  
+                                               ret = SQL_SUCCESS;
+                                       break;
                                case SQL_DIAG_NUMBER:
-                               case SQL_DIAG_RETURNCODE:
-                               case SQL_DIAG_SERVER_NAME:
+                                       ret = PGAPI_EnvError(Handle, RecNumber,
+                                               NULL, NULL, NULL,
+                                               0, NULL, 0);
+                                       if (SQL_SUCCESS == ret ||
+                                           SQL_SUCCESS_WITH_INFO == ret)
+                                       {
+                                               *((SQLINTEGER *) DiagInfoPtr) = 1;
+                                               if (StringLengthPtr)
+                                                       *StringLengthPtr = sizeof(SQLINTEGER);
+                                               ret = SQL_SUCCESS;
+                                       }
+                                       break;
                                case SQL_DIAG_SQLSTATE:
+                                       ret = PGAPI_EnvError(Handle, RecNumber,
+                                               DiagInfoPtr, NULL, NULL,
+                                               0, NULL, 0);
+                                       if (StringLengthPtr)  
+                                               *StringLengthPtr = 5;  
+                                       if (SQL_SUCCESS_WITH_INFO == ret)  
+                                               ret = SQL_SUCCESS;
+                                       break;
+                               case SQL_DIAG_RETURNCODE: /* driver manager returns */
+                                       break;
+                               case SQL_DIAG_CURSOR_ROW_COUNT:
+                               case SQL_DIAG_ROW_COUNT:
+                               case SQL_DIAG_DYNAMIC_FUNCTION:
+                               case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
+                                       /* options for statement type only */
                                        break;
                        }
                        break;
                case SQL_HANDLE_DBC:
+                       conn = (ConnectionClass *) Handle;
                        switch (DiagIdentifier)
                        {
                                case SQL_DIAG_CLASS_ORIGIN:
                                case SQL_DIAG_SUBCLASS_ORIGIN:
                                case SQL_DIAG_CONNECTION_NAME:
+                                       strcpy((char *) DiagInfoPtr, "");
+                                       if (StringLengthPtr)
+                                               *StringLengthPtr = 0;
+                                       ret = SQL_SUCCESS;
+                                       break;
+                               case SQL_DIAG_SERVER_NAME:
+                                       strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
+                                       if (StringLengthPtr)
+                                               *StringLengthPtr = strlen(CC_get_DSN(conn));
+                                       ret = SQL_SUCCESS;
+                                       break;
                                case SQL_DIAG_MESSAGE_TEXT:
+                                       ret = PGAPI_ConnectError(Handle, RecNumber,
+                                               NULL, NULL, DiagInfoPtr,
+                                               BufferLength, StringLengthPtr, 0);  
+                                       break;
                                case SQL_DIAG_NATIVE:
+                                       ret = PGAPI_ConnectError(Handle, RecNumber,
+                                               NULL, DiagInfoPtr, NULL,
+                                               0, NULL, 0);  
+                                       if (StringLengthPtr)  
+                                               *StringLengthPtr = sizeof(SQLINTEGER);  
+                                       if (SQL_SUCCESS_WITH_INFO == ret)  
+                                               ret = SQL_SUCCESS;
+                                       break;
                                case SQL_DIAG_NUMBER:
-                               case SQL_DIAG_RETURNCODE:
-                               case SQL_DIAG_SERVER_NAME:
+                                       ret = PGAPI_ConnectError(Handle, RecNumber,
+                                               NULL, NULL, NULL,
+                                               0, NULL, 0);
+                                       if (SQL_SUCCESS == ret ||
+                                           SQL_SUCCESS_WITH_INFO == ret)
+                                       {
+                                               *((SQLINTEGER *) DiagInfoPtr) = 1;
+                                               if (StringLengthPtr)
+                                                       *StringLengthPtr = sizeof(SQLINTEGER);
+                                               ret = SQL_SUCCESS;
+                                       }
+                                       break;  
                                case SQL_DIAG_SQLSTATE:
+                                       ret = PGAPI_ConnectError(Handle, RecNumber,
+                                               DiagInfoPtr, NULL, NULL,
+                                               0, NULL, 0);
+                                       if (StringLengthPtr)  
+                                               *StringLengthPtr = 5;  
+                                       if (SQL_SUCCESS_WITH_INFO == ret)  
+                                               ret = SQL_SUCCESS;
+                                       break;
+                               case SQL_DIAG_RETURNCODE: /* driver manager returns */
+                                       break;
+                               case SQL_DIAG_CURSOR_ROW_COUNT:
+                               case SQL_DIAG_ROW_COUNT:
+                               case SQL_DIAG_DYNAMIC_FUNCTION:
+                               case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
+                                       /* options for statement type only */
                                        break;
                        }
                        break;
                case SQL_HANDLE_STMT:
+                       conn = (ConnectionClass *) SC_get_conn(((StatementClass *) Handle));
                        switch (DiagIdentifier)
                        {
                                case SQL_DIAG_CLASS_ORIGIN:
                                case SQL_DIAG_SUBCLASS_ORIGIN:
                                case SQL_DIAG_CONNECTION_NAME:
+                                       strcpy((char *) DiagInfoPtr, "");
+                                       if (StringLengthPtr)
+                                               *StringLengthPtr = 0;
+                                       ret = SQL_SUCCESS;
+                                       break;
+                               case SQL_DIAG_SERVER_NAME:
+                                       strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
+                                       if (StringLengthPtr)
+                                               *StringLengthPtr = strlen(CC_get_DSN(conn));
+                                       ret = SQL_SUCCESS;
+                                       break;
                                case SQL_DIAG_MESSAGE_TEXT:
+                                       ret = PGAPI_StmtError(Handle, RecNumber,
+                                               NULL, NULL, DiagInfoPtr,
+                                               BufferLength, StringLengthPtr, 0);  
+                                       break;
                                case SQL_DIAG_NATIVE:
+                                       ret = PGAPI_StmtError(Handle, RecNumber,
+                                               NULL, DiagInfoPtr, NULL,
+                                               0, NULL, 0);  
+                                       if (StringLengthPtr)  
+                                               *StringLengthPtr = sizeof(SQLINTEGER);  
+                                       if (SQL_SUCCESS_WITH_INFO == ret)  
+                                               ret = SQL_SUCCESS;
+                                       break;
                                case SQL_DIAG_NUMBER:
-                               case SQL_DIAG_RETURNCODE:
+                                       *((SQLINTEGER *) DiagInfoPtr) = 0;
+                                       ret = SQL_NO_DATA_FOUND;
+                                       stmt = (StatementClass *) Handle;
+                                       do
+                                       {
+                                               rtn = PGAPI_StmtError(Handle, RecNumber,
+                                                       NULL, NULL, NULL,
+                                                       0, &pcbErrm, 0);
+                                               if (SQL_SUCCESS == rtn ||
+                                                   SQL_SUCCESS_WITH_INFO == rtn)
+                                               {
+                                                       *((SQLINTEGER *) DiagInfoPtr)++;
+                                                       ret = SQL_SUCCESS;
+                                               }
+                                       } while (pcbErrm >= stmt->error_recsize);
+                                       if (StringLengthPtr)
+                                               *StringLengthPtr = sizeof(SQLINTEGER);
+                                       break;
+                               case SQL_DIAG_SQLSTATE:
+                                       ret = PGAPI_StmtError(Handle, RecNumber,
+                                               DiagInfoPtr, NULL, NULL,
+                                               0, NULL, 0);
+                                       if (StringLengthPtr)  
+                                               *StringLengthPtr = 5;
+                                       if (SQL_SUCCESS_WITH_INFO == ret)  
+                                               ret = SQL_SUCCESS;
+                                       break;
+                               case SQL_DIAG_CURSOR_ROW_COUNT:
+                                       stmt = (StatementClass *) Handle;
+                                       rc = -1;
+                                       if (stmt->status == STMT_FINISHED)
+                                       {
+                                               QResultClass *res = SC_get_Curres(stmt);
+
+                                               if (res && QR_NumResultCols(res) > 0 && !SC_is_fetchcursor(stmt))
+                                                       rc = QR_get_num_total_tuples(res) - res->dl_count;
+                                       } 
+                                       *((SQLINTEGER *) DiagInfoPtr) = rc;
+                                       if (StringLengthPtr)
+                                               *StringLengthPtr = sizeof(SQLINTEGER);
+                                       ret = SQL_SUCCESS;
+                                       break;
+                               case SQL_DIAG_ROW_COUNT:
+                                       stmt = (StatementClass *) Handle;
+                                       *((SQLINTEGER *) DiagInfoPtr) = stmt->diag_row_count;
+                                       if (StringLengthPtr)
+                                               *StringLengthPtr = sizeof(SQLINTEGER);
+                                       ret = SQL_SUCCESS;
+                                       break;
+                               case SQL_DIAG_RETURNCODE: /* driver manager returns */
+                                       break;
+                       }
+                       break;
+               case SQL_HANDLE_DESC:
+                       stmtHandle = statementHandleFromDescHandle(Handle, NULL); 
+                       conn = (ConnectionClass *) SC_get_conn(((StatementClass *) stmtHandle)); 
+                       switch (DiagIdentifier)
+                       {
+                               case SQL_DIAG_CLASS_ORIGIN:
+                               case SQL_DIAG_SUBCLASS_ORIGIN:
+                               case SQL_DIAG_CONNECTION_NAME:
+                                       strcpy((char *) DiagInfoPtr, "");
+                                       if (StringLengthPtr)
+                                               *StringLengthPtr = 0;
+                                       ret = SQL_SUCCESS;
+                                       break;
                                case SQL_DIAG_SERVER_NAME:
+                                       strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
+                                       if (StringLengthPtr)
+                                               *StringLengthPtr = strlen(CC_get_DSN(conn));
+                                       ret = SQL_SUCCESS;
                                        break;
+                               case SQL_DIAG_MESSAGE_TEXT:
+                               case SQL_DIAG_NATIVE:
+                               case SQL_DIAG_NUMBER:
                                case SQL_DIAG_SQLSTATE:
+                                       ret = PGAPI_GetDiagField(SQL_HANDLE_STMT,
+                                               stmtHandle, RecNumber,
+                                               DiagIdentifier, DiagInfoPtr,
+                                               BufferLength, StringLengthPtr);
+                                       break;
+                               case SQL_DIAG_RETURNCODE: /* driver manager returns */
+                                       break;
+                               case SQL_DIAG_CURSOR_ROW_COUNT:
+                               case SQL_DIAG_ROW_COUNT:
+                               case SQL_DIAG_DYNAMIC_FUNCTION:
+                               case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
+                                       /* options for statement type only */
                                        break;
                        }
                        break;
@@ -155,12 +365,7 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
                        *((SQLUINTEGER *) Value) = SQL_FALSE;
                        break;
                case SQL_ATTR_CONNECTION_DEAD:
-                       if (CC_is_in_trans(conn))
-                               *((SQLUINTEGER *) Value) = SQL_CD_FALSE;
-                       else if (conn->num_stmts > 0)
-                               *((SQLUINTEGER *) Value) = SQL_CD_FALSE;
-                       else
-                               *((SQLUINTEGER *) Value) = SQL_CD_FALSE;
+                       *((SQLUINTEGER *) Value) = (conn->status == CONN_NOT_CONNECTED || conn->status == CONN_DOWN);
                        break;
                case SQL_ATTR_CONNECTION_TIMEOUT:
                        *((SQLUINTEGER *) Value) = 0;
@@ -348,12 +553,24 @@ ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
                                opts->bindings[RecNumber - 1].buflen = (Int4) Value;
                        }
                        break;
+               case SQL_DESC_PRECISION:
+                       if (RecNumber)
+                       {
+                               column_bindings_set(opts, RecNumber, TRUE);
+                               opts->bindings[RecNumber - 1].precision = (Int2) Value;
+                       }
+                       break;
+               case SQL_DESC_SCALE:
+                       if (RecNumber)
+                       {
+                               column_bindings_set(opts, RecNumber, TRUE);
+                               opts->bindings[RecNumber - 1].scale = (Int4) Value;
+                       }
+                       break;
                case SQL_DESC_ALLOC_TYPE: /* read-only */
                case SQL_DESC_DATETIME_INTERVAL_PRECISION:
                case SQL_DESC_LENGTH:
                case SQL_DESC_NUM_PREC_RADIX:
-               case SQL_DESC_PRECISION:
-               case SQL_DESC_SCALE:
                default:ret = SQL_ERROR;
                        stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
        }
@@ -460,12 +677,18 @@ APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
                case SQL_DESC_COUNT:
                        parameter_bindings_set(opts, (SQLUINTEGER) Value, FALSE);
                        break; 
+               case SQL_DESC_PRECISION:
+                       parameter_bindings_set(opts, RecNumber, TRUE);
+                       opts->parameters[RecNumber - 1].precision = (Int2) Value;
+                       break;
+               case SQL_DESC_SCALE:
+                       parameter_bindings_set(opts, RecNumber, TRUE);
+                       opts->parameters[RecNumber - 1].scale = (Int2) 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_DESCRIPTOR_IDENTIFIER; 
        }
@@ -710,11 +933,23 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
                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:
+                       if (RecNumber)
+                       {
+                               ival = opts->bindings[RecNumber - 1].precision;
+                       }
+                       break;
                case SQL_DESC_SCALE:
+                       if (RecNumber)
+                       {
+                               ival = opts->bindings[RecNumber - 1].scale;
+                       }
+                       break;
+               case SQL_DESC_NUM_PREC_RADIX:
+                       ival = 10;
+                       break;
+               case SQL_DESC_DATETIME_INTERVAL_PRECISION:
+               case SQL_DESC_LENGTH:
                default:ret = SQL_ERROR;
                        stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
        }
@@ -818,11 +1053,17 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
                case SQL_DESC_ALLOC_TYPE: /* read-only */
                        ival = SQL_DESC_ALLOC_AUTO;
                        break;
+               case SQL_DESC_NUM_PREC_RADIX:
+                       ival = 10;
+                       break;
                case SQL_DESC_PRECISION:
+                       ival = opts->parameters[RecNumber - 1].precision;
+                       break;
                case SQL_DESC_SCALE:
+                       ival = opts->parameters[RecNumber - 1].scale;
+                       break;
                case SQL_DESC_DATETIME_INTERVAL_PRECISION:
                case SQL_DESC_LENGTH:
-               case SQL_DESC_NUM_PREC_RADIX:
                default:ret = SQL_ERROR;
                        stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
        }
@@ -1339,3 +1580,77 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle,
        }
        return SQL_SUCCESS;
 }
+
+#ifdef DRIVER_CURSOR_IMPLEMENT
+RETCODE        SQL_API
+PGAPI_BulkOperations(HSTMT hstmt, SQLSMALLINT operation)
+{
+       static char     *func = "PGAPI_BulkOperations";
+       StatementClass  *stmt = (StatementClass *) hstmt;
+       ARDFields       *opts = SC_get_ARD(stmt);
+       RETCODE         ret;
+       UInt4           offset, bind_size = opts->bind_size, *bmark = NULL;
+       int             i, processed;
+       ConnectionClass *conn;
+       BOOL            auto_commit_needed = FALSE;
+       QResultClass    *res;
+
+       mylog("%s operation = %d\n", func, operation);
+       SC_clear_error(stmt);
+       offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
+       
+       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 (SQL_ADD != operation)
+       {
+               if (bmark = (UInt4 *) opts->bookmark->buffer, !bmark)
+               {
+                       stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
+                       stmt->errormsg = "bookmark isn't specified";
+                       return SQL_ERROR;
+               }
+               bmark += (offset >> 4);
+       }
+       for (i = 0, processed = 0; i < opts->rowset_size; i++)
+       {
+               /* Note opts->row_operation_ptr is ignored */
+               switch (operation)
+               {
+                       case SQL_ADD:
+                               ret = SC_pos_add(stmt, (UWORD) i);
+                               break;
+                       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 (SQL_ADD != operation)
+               {
+                       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;
+
+       if (res = SC_get_Curres(stmt), res)
+               res->recent_processed_row_count = stmt->diag_row_count = processed;
+       return ret;
+}      
+#endif /* DRIVER_CURSOR_IMPLEMENT */
index f4c740b..756a49d 100644 (file)
@@ -172,7 +172,8 @@ RETCODE SQL_API PGAPI_ExtendedFetch(
                                        SQLUSMALLINT fFetchType,
                                        SQLINTEGER irow,
                                        SQLUINTEGER *pcrow,
-                                       SQLUSMALLINT *rgfRowStatus);
+                                       SQLUSMALLINT *rgfRowStatus,
+                                       SQLINTEGER FetchOffset);
 RETCODE SQL_API PGAPI_ForeignKeys(
                                  HSTMT hstmt,
                                  SQLCHAR *szPkCatalogName,
@@ -281,6 +282,8 @@ RETCODE SQL_API PGAPI_SetConnectAttr(HDBC ConnectionHandle,
 RETCODE SQL_API PGAPI_SetStmtAttr(HSTMT StatementHandle,
                SQLINTEGER Attribute, PTR Value,
                SQLINTEGER StringLength);
+RETCODE SQL_API PGAPI_BulkOperations(HSTMT StatementHandle,
+                       SQLSMALLINT operation);
 RETCODE SQL_API PGAPI_SetDescField(SQLHDESC DescriptorHandle,
                        SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
                        PTR Value, SQLINTEGER BufferLength);
index 74df2a7..fe0d5b8 100644 (file)
@@ -101,7 +101,8 @@ Int2                sqlTypes[] = {
 };
 
 #if (ODBCVER >= 0x0300) && defined(OBDCINT64)
-#define        ALLOWED_C_BIGINT        SQL_C_SBIGINT
+/* #define     ALLOWED_C_BIGINT        SQL_C_SBIGINT */
+#define        ALLOWED_C_BIGINT        SQL_C_CHAR /* Delphi should be either ? */
 #else
 #define        ALLOWED_C_BIGINT        SQL_C_CHAR
 #endif
@@ -286,11 +287,13 @@ pgtype_to_concise_type(StatementClass *stmt, Int4 type)
 
                        /* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */
                case PG_TYPE_INT8:
+                       if (conn->ms_jet) 
+                               return SQL_NUMERIC; /* maybe a little better than SQL_VARCHAR */
 #if (ODBCVER >= 0x0300)
-                       if (!conn->ms_jet)
-                               return SQL_BIGINT;
-#endif /* ODBCVER */
+                       return SQL_BIGINT;
+#else
                        return SQL_VARCHAR;
+#endif /* ODBCVER */
 
                case PG_TYPE_NUMERIC:
                        return SQL_NUMERIC;
index 3a2d8c9..6d39e63 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:           See "notice.txt" for copyright and license information.
  *
- * $Id: psqlodbc.h,v 1.65 2002/04/15 02:46:00 inoue Exp $
+ * $Id: psqlodbc.h,v 1.66 2002/05/22 05:51:03 inoue Exp $
  *
  */
 
@@ -20,6 +20,8 @@
 
 #include <stdio.h>                             /* for FILE* pointers: see GLOBAL_VALUES */
 
+#include "version.h"
+
 /* Must come before sql.h */
 #ifndef ODBCVER
 #define ODBCVER                                                0x0250
@@ -87,8 +89,6 @@ typedef UInt4 Oid;
 #define DBMS_NAME                                      "PostgreSQL"
 #endif   /* ODBCVER */
 
-#define POSTGRESDRIVERVERSION          "07.02.0001"
-
 #ifdef WIN32
 #if (ODBCVER >= 0x0300)
 #ifdef UNICODE_SUPPORT
index 050b45d..9cbb44b 100644 (file)
@@ -1,6 +1,7 @@
 //Microsoft Developer Studio generated resource script.
 //
 #include "resource.h"
+#include "version.h"
 
 #define APSTUDIO_READONLY_SYMBOLS
 /////////////////////////////////////////////////////////////////////////////
@@ -366,8 +367,8 @@ END
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 7,2,0,01
- PRODUCTVERSION 7,2,0,01
+ FILEVERSION PG_DRVFILE_VERSION
+ PRODUCTVERSION PG_DRVFILE_VERSION
  FILEFLAGSMASK 0x3L
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -389,14 +390,14 @@ BEGIN
             VALUE "CompanyName", "Insight Distribution Systems\0"
 #endif
             VALUE "FileDescription", "PostgreSQL Driver\0"
-            VALUE "FileVersion", " 07.02.0001\0"
+            VALUE "FileVersion", POSTGRES_RESOURCE_VERSION
             VALUE "InternalName", "psqlodbc\0"
             VALUE "LegalCopyright", "\0"
             VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation.  Microsoft® is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
             VALUE "OriginalFilename", "psqlodbc.dll\0"
             VALUE "PrivateBuild", "\0"
             VALUE "ProductName", "Microsoft Open Database Connectivity\0"
-            VALUE "ProductVersion", " 07.02.0001\0"
+            VALUE "ProductVersion", POSTGRES_RESOURCE_VERSION
             VALUE "SpecialBuild", "\0"
         END
     END
index 2817a7f..b104082 100644 (file)
@@ -110,9 +110,13 @@ QR_Constructor()
                rv->conn = NULL;
                rv->next = NULL;
                rv->inTuples = FALSE;
-               rv->fcount = 0;
+               rv->count_backend_allocated = 0;
+               rv->count_keyset_allocated = 0;
+               rv->num_total_rows = 0;
+               rv->num_backend_rows = 0;
                rv->fetch_count = 0;
                rv->base = 0;
+               rv->recent_processed_row_count = -1;
                rv->currTuple = -1;
                rv->num_fields = 0;
                rv->tupleField = NULL;
@@ -126,6 +130,9 @@ QR_Constructor()
                rv->rb_alloc = 0;
                rv->rb_count = 0;
                rv->rollback = NULL;
+               rv->dl_alloc = 0;
+               rv->dl_count = 0;
+               rv->deleted = NULL;
        }
 
        mylog("exit QR_Constructor\n");
@@ -202,14 +209,14 @@ QR_free_memory(QResultClass *self)
        register int lf,
                                row;
        register TupleField *tuple = self->backend_tuples;
-       int                     fcount = self->fcount;
+       int                     num_backend_rows = self->num_backend_rows;
        int                     num_fields = self->num_fields;
 
-       mylog("QResult: free memory in, fcount=%d\n", fcount);
+       mylog("QResult: free memory in, fcount=%d\n", num_backend_rows);
 
        if (self->backend_tuples)
        {
-               for (row = 0; row < fcount; row++)
+               for (row = 0; row < num_backend_rows; row++)
                {
                        mylog("row = %d, num_fields = %d\n", row, num_fields);
                        for (lf = 0; lf < num_fields; lf++)
@@ -224,12 +231,14 @@ QR_free_memory(QResultClass *self)
                }
 
                free(self->backend_tuples);
+               self->count_backend_allocated = 0;
                self->backend_tuples = NULL;
        }
        if (self->keyset)
        {
                free(self->keyset);
                self->keyset = NULL;
+               self->count_keyset_allocated = 0;
        }
        if (self->rollback)
        {
@@ -238,8 +247,16 @@ QR_free_memory(QResultClass *self)
                self->rb_count = 0;
                self->rollback = NULL;
        }
+       if (self->deleted)
+       {
+               free(self->deleted);
+               self->dl_alloc = 0;
+               self->dl_count = 0;
+               self->deleted = NULL;
+       }
 
-       self->fcount = 0;
+       self->num_total_rows = 0;
+       self->num_backend_rows = 0;
 
        mylog("QResult: free memory out\n");
 }
@@ -313,7 +330,7 @@ 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->count_backend_allocated = self->count_keyset_allocated = 0;
                if (self->num_fields > 0)
                {
                        self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size);
@@ -323,15 +340,24 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
                                QR_set_message(self, "Could not get memory for tuple cache.");
                                return FALSE;
                        }
+                       self->count_backend_allocated = tuple_size;
                }
                if (self->haskeyset)
-                       self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size);
-               self->count_allocated = tuple_size;
+               {
+                       if (self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size), !self->keyset)
+                       {
+                               self->status = PGRES_FATAL_ERROR;
+                               QR_set_message(self, "Could not get memory for tuple cache.");
+                               return FALSE;
+                       }
+                       self->count_keyset_allocated = tuple_size;
+               }
 
                self->inTuples = TRUE;
 
                /* Force a read to occur in next_tuple */
-               self->fcount = tuple_size + 1;
+               self->num_total_rows = tuple_size + 1;
+               self->num_backend_rows = tuple_size + 1;
                self->fetch_count = tuple_size + 1;
                self->base = 0;
 
@@ -415,7 +441,7 @@ QR_next_tuple(QResultClass *self)
 
        /* Speed up access */
        int                     fetch_count = self->fetch_count;
-       int                     fcount = self->fcount;
+       int                     num_backend_rows = self->num_backend_rows;
        int                     fetch_size,
                                offset = 0;
        int                     end_tuple = self->rowset_size + self->base;
@@ -430,21 +456,21 @@ QR_next_tuple(QResultClass *self)
        char            fetch[128];
        QueryInfo       qi;
        ConnInfo   *ci = NULL;
-       BOOL            set_no_trans;
+       UDWORD          abort_opt;
 
-       if (fetch_count < fcount)
+       if (fetch_count < num_backend_rows)
        {
                /* return a row from cache */
-               mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, fcount);
+               mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, num_backend_rows);
                self->tupleField = the_tuples + (fetch_count * self->num_fields);               /* next row */
                self->fetch_count++;
                return TRUE;
        }
-       else if (self->fcount < self->cache_size)
+       else if (self->num_backend_rows < self->cache_size)
        {
                /* last row from cache */
                /* We are done because we didn't even get CACHE_SIZE tuples */
-               mylog("next_tuple: fcount < CACHE_SIZE: fcount = %d, fetch_count = %d\n", fcount, fetch_count);
+               mylog("next_tuple: fcount < CACHE_SIZE: fcount = %d, fetch_count = %d\n", num_backend_rows, fetch_count);
                self->tupleField = NULL;
                self->status = PGRES_END_TUPLES;
                /* end of tuples */
@@ -464,13 +490,13 @@ QR_next_tuple(QResultClass *self)
                        ci = &(self->conn->connInfo);
                        if (!self->cursor || !ci->drivers.use_declarefetch)
                        {
-                               mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", fcount, fetch_count);
+                               mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", self->num_total_rows, fetch_count);
                                self->tupleField = NULL;
                                self->status = PGRES_END_TUPLES;
                                return -1;              /* end of tuples */
                        }
 
-                       if (self->base == fcount)
+                       if (self->base == num_backend_rows)
                        {
                                /* not a correction */
                                /* Determine the optimum cache size.  */
@@ -489,7 +515,7 @@ QR_next_tuple(QResultClass *self)
                                /* need to correct */
                                corrected = TRUE;
 
-                               fetch_size = end_tuple - fcount;
+                               fetch_size = end_tuple - num_backend_rows;
 
                                self->cache_size += fetch_size;
 
@@ -497,9 +523,9 @@ QR_next_tuple(QResultClass *self)
                                self->fetch_count++;
                        }
 
-                       if (!self->backend_tuples || self->cache_size > self->count_allocated)
+                       if (!self->backend_tuples || self->cache_size > self->count_backend_allocated)
                        {
-                               self->count_allocated = 0;
+                               self->count_backend_allocated = 0;
                                if (self->num_fields > 0)
                                {
                                        self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
@@ -510,10 +536,14 @@ QR_next_tuple(QResultClass *self)
                                                QR_set_message(self, "Out of memory while reading tuples.");
                                                return FALSE;
                                        }
+                                       self->count_backend_allocated = self->cache_size;
                                }
-                               if (self->haskeyset)
-                                       self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * self->cache_size); 
-                               self->count_allocated = self->cache_size;
+                       }
+                       if (self->haskeyset && (!self->keyset || self->cache_size > self->count_keyset_allocated))
+                       {
+                               self->count_keyset_allocated = 0;
+                               self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * self->cache_size); 
+                               self->count_keyset_allocated = self->cache_size;
                        }
                        sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor);
 
@@ -534,7 +564,7 @@ QR_next_tuple(QResultClass *self)
                }
                else
                {
-                       mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->fcount, self->fetch_count);
+                       mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->num_backend_rows, self->fetch_count);
 
                        /*
                         * This is a pre-fetch (fetching rows right after query but
@@ -548,7 +578,8 @@ QR_next_tuple(QResultClass *self)
        if (!corrected)
        {
                self->base = 0;
-               self->fcount = 0;
+               self->num_total_rows = 0; /* right ? */
+               self->num_backend_rows = 0;
        }
 
        sock = CC_get_socket(self->conn);
@@ -569,14 +600,15 @@ QR_next_tuple(QResultClass *self)
                        case 'B':                       /* Tuples in binary format */
                        case 'D':                       /* Tuples in ASCII format  */
 
-                               if ((!self->cursor || !ci->drivers.use_declarefetch) && self->fcount >= self->count_allocated)
-                               {
-                                       int                     tuple_size = self->count_allocated;
-
-                                       mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
-                                       tuple_size *= 2;
-                                       if (self->num_fields > 0)
+                               if (!self->cursor || !ci->drivers.use_declarefetch)
+                               { 
+                                       if (self->num_fields > 0 &&
+                                           self->num_total_rows >= self->count_backend_allocated)
                                        {
+                                               int     tuple_size = self->count_backend_allocated;
+
+                                               mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
+                                               tuple_size *= 2;
                                                self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
                                                        tuple_size * self->num_fields * sizeof(TupleField));
                                                if (!self->backend_tuples)
@@ -585,10 +617,16 @@ QR_next_tuple(QResultClass *self)
                                                        QR_set_message(self, "Out of memory while reading tuples.");
                                                        return FALSE;
                                                }
+                                               self->count_backend_allocated = tuple_size;
                                        }
-                                       if (self->haskeyset)
+                                       if (self->haskeyset &&
+                                           self->num_total_rows >= self->count_keyset_allocated)
+                                       {
+                                               int     tuple_size = self->count_keyset_allocated;
+                                               tuple_size *= 2;
                                                self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * tuple_size);
-                                       self->count_allocated = tuple_size;
+                                               self->count_keyset_allocated = tuple_size;
+                                       }
                                }
 
                                if (!QR_read_tuple(self, (char) (id == 0)))
@@ -597,7 +635,9 @@ QR_next_tuple(QResultClass *self)
                                        QR_set_message(self, "Error reading the tuple");
                                        return FALSE;
                                }
-                               self->fcount++;
+                               self->num_total_rows++;
+                               if (self->num_fields > 0)
+                                       self->num_backend_rows++;
                                break;                  /* continue reading */
 
                        case 'C':                       /* End of tuple list */
@@ -607,10 +647,10 @@ QR_next_tuple(QResultClass *self)
                                mylog("end of tuple list -- setting inUse to false: this = %u\n", self);
 
                                self->inTuples = FALSE;
-                               if (self->fcount > 0)
+                               if (self->num_total_rows > 0)
                                {
-                                       qlog("    [ fetched %d rows ]\n", self->fcount);
-                                       mylog("_next_tuple: 'C' fetch_max && fcount = %d\n", self->fcount);
+                                       qlog("    [ fetched %d rows ]\n", self->num_total_rows);
+                                       mylog("_next_tuple: 'C' fetch_max && fcount = %d\n", self->num_total_rows);
 
                                        /* set to first row */
                                        self->tupleField = self->backend_tuples + (offset * self->num_fields);
@@ -629,11 +669,15 @@ QR_next_tuple(QResultClass *self)
                                QR_set_message(self, msgbuffer);
                                self->status = PGRES_FATAL_ERROR;
 
-                               set_no_trans = FALSE;
+                               abort_opt = 0;
                                if (!strncmp(msgbuffer, "FATAL", 5))
-                                       set_no_trans = TRUE;
-                               CC_on_abort(self->conn, set_no_trans);
+                                       abort_opt = NO_TRANS | CONN_DEAD;
+                               CC_on_abort(self->conn, abort_opt);
+                               QR_set_status(self, PGRES_FATAL_ERROR);
+                               QR_set_message(self, msgbuffer);
+                               QR_set_aborted(self, TRUE);
 
+                               mylog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
                                qlog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
 
                                return FALSE;
@@ -651,7 +695,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_on_abort(self->conn, TRUE);
+                               CC_on_abort(self->conn, NO_TRANS | CONN_DEAD);
                                return FALSE;
                }
        }
@@ -681,16 +725,16 @@ QR_read_tuple(QResultClass *self, char binary)
 
        /* set the current row to read the fields into */
        effective_cols = ci_num_fields;
-       this_tuplefield = self->backend_tuples + (self->fcount * num_fields);
+       this_tuplefield = self->backend_tuples + (self->num_backend_rows * num_fields);
        if (self->haskeyset)
        {
-               this_keyset = self->keyset + self->fcount;
+               this_keyset = self->keyset + self->num_total_rows;
                this_keyset->status = 0;
                effective_cols -= 2;
        }
 
-       bitmaplen = (Int2) num_fields / BYTELEN;
-       if ((num_fields % BYTELEN) > 0)
+       bitmaplen = (Int2) ci_num_fields / BYTELEN;
+       if ((ci_num_fields % BYTELEN) > 0)
                bitmaplen++;
 
        /*
index b313cbc..03c4ed3 100644 (file)
@@ -48,15 +48,18 @@ struct QResultClass_
        QResultClass    *next;          /* the following result class */
 
        /* Stuff for declare/fetch tuples */
-       int                     count_allocated;        /* m(re)alloced count */
+       int                     num_total_rows; /* total count of rows read in */
+       int                     count_backend_allocated;/* m(re)alloced count */
+       int                     count_keyset_allocated; /* m(re)alloced count */
+       int                     num_backend_rows;       /* count of tuples kept in backend_tuples member */
        int                     fetch_count;    /* logical rows read so far */
-       int                     fcount;                 /* actual rows read in the fetch */
        int                     currTuple;
        int                     base;
 
        int                     num_fields;             /* number of fields in the result */
        int                     cache_size;
        int                     rowset_size;
+       Int4                    recent_processed_row_count;
 
        QueryResultCode status;
 
@@ -77,6 +80,9 @@ struct QResultClass_
        UInt2           rb_alloc;       /* count of allocated rollback info */  
        UInt2           rb_count;       /* count of rollback info */    
        Rollback        *rollback;      
+       UInt2           dl_alloc;       /* count of allocated deleted info */   
+       UInt2           dl_count;       /* count of deleted info */     
+       UInt4           *deleted;       
 };
 
 #define QR_get_fields(self)                                    (self->fields)
@@ -96,7 +102,8 @@ struct QResultClass_
 #define QR_get_field_type(self, fieldno_)      (CI_get_oid(self->fields, fieldno_))
 
 /*     These functions are used only for manual result sets */
-#define QR_get_num_tuples(self)                                (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->fcount)
+#define QR_get_num_total_tuples(self)          (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->num_total_rows)
+#define QR_get_num_backend_tuples(self)                (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->num_backend_rows)
 #define QR_add_tuple(self, new_tuple)          (TL_add_tuple(self->manual_tuples, new_tuple))
 #define QR_set_field_info(self, field_num, name, adtid, adtsize)  (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1))
 
index 937e275..0739167 100644 (file)
@@ -41,8 +41,6 @@ PGAPI_RowCount(
        static char *func = "PGAPI_RowCount";
        StatementClass *stmt = (StatementClass *) hstmt;
        QResultClass *res;
-       char       *msg,
-                          *ptr;
        ConnInfo   *ci;
 
        mylog("%s: entering...\n", func);
@@ -59,43 +57,32 @@ PGAPI_RowCount(
                return SQL_SUCCESS;
        }
 
-       if (stmt->statement_type == STMT_TYPE_SELECT)
+       res = SC_get_Curres(stmt);
+       if (res && pcrow)
        {
-               if (stmt->status == STMT_FINISHED)
+               if (stmt->status != STMT_FINISHED)
                {
-                       res = SC_get_Curres(stmt);
-
-                       if (res && pcrow)
-                       {
-                               *pcrow = SC_is_fetchcursor(stmt) ? -1 : QR_get_num_tuples(res);
-                               return SQL_SUCCESS;
-                       }
+                       stmt->errornumber = STMT_SEQUENCE_ERROR;
+                       stmt->errormsg = "Can't get row count while statement is still executing.";
+                       SC_log_error(func, "", stmt);
+                       return  SQL_ERROR;
                }
-       }
-       else
-       {
-               res = SC_get_Curres(stmt);
-               if (res && pcrow)
+               if (res->recent_processed_row_count >= 0)
                {
-                       msg = QR_get_command(res);
-                       mylog("*** msg = '%s'\n", msg);
-                       trim(msg);                      /* get rid of trailing spaces */
-                       ptr = strrchr(msg, ' ');
-                       if (ptr)
-                       {
-                               *pcrow = atoi(ptr + 1);
-                               mylog("**** PGAPI_RowCount(): THE ROWS: *pcrow = %d\n", *pcrow);
-                       }
-                       else
-                       {
-                               *pcrow = -1;
-                               mylog("**** PGAPI_RowCount(): NO ROWS: *pcrow = %d\n", *pcrow);
-                       }
+                       *pcrow = res->recent_processed_row_count;
+                       mylog("**** PGAPI_RowCount(): THE ROWS: *pcrow = %d\n", *pcrow);
 
                        return SQL_SUCCESS;
                }
+               else if (QR_NumResultCols(res) > 0)
+               {
+                       *pcrow = SC_is_fetchcursor(stmt) ? -1 : QR_get_num_total_tuples(res) - res->dl_count;
+                       mylog("RowCount=%d\n", *pcrow);
+                       return SQL_SUCCESS;
+               }
        }
 
+       stmt->errornumber = STMT_SEQUENCE_ERROR;
        SC_log_error(func, "Bad return value", stmt);
        return SQL_ERROR;
 }
@@ -685,6 +672,14 @@ inolog("COLUMN_TYPE=%d\n", value);
                         * else
                         */
                        value = fi ? (fi->updatable ? SQL_ATTR_WRITE : SQL_ATTR_READONLY) : SQL_ATTR_READWRITE_UNKNOWN;
+                       if (SQL_ATTR_READONLY != value)
+                       {
+                               const char *name = fi ? fi->name : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
+                               if (stricmp(name, "oid") == 0 ||
+                                   stricmp(name, "ctid") == 0 ||
+                                   stricmp(name, "xmin") == 0)
+                                       value = SQL_ATTR_READONLY;
+                       }
 
                        mylog("PGAPI_ColAttr: UPDATEABLE = %d\n", value);
                        break;
@@ -714,7 +709,8 @@ inolog("COLUMN_TYPE=%d\n", value);
                        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->column_size > 0) ? fi->column_size : pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
+                       if (value = FI_precision(fi), value <= 0)
+                               value = pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
                        if (value < 0)
                                value = 0;
 
@@ -881,7 +877,7 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
        if (stmt->manual_result || !SC_is_fetchcursor(stmt))
        {
                /* make sure we're positioned on a valid row */
-               num_rows = QR_get_num_tuples(res);
+               num_rows = QR_get_num_total_tuples(res);
                if ((stmt->currTuple < 0) ||
                        (stmt->currTuple >= num_rows))
                {
@@ -897,7 +893,12 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
                        if (stmt->manual_result)
                                value = QR_get_value_manual(res, stmt->currTuple, icol);
                        else
-                               value = QR_get_value_backend_row(res, stmt->currTuple, icol);
+                       {
+                               Int4    curt = res->base;
+                               if (stmt->rowset_start >= 0)
+                                       curt += (stmt->currTuple - stmt->rowset_start);
+                               value = QR_get_value_backend_row(res, curt, icol);
+                       }
                        mylog("     value = '%s'\n", value);
                }
        }
@@ -1046,12 +1047,93 @@ PGAPI_Fetch(
        }
 
        QR_set_rowset_size(res, 1);
-       QR_inc_base(res, stmt->last_fetch_count);
+       QR_inc_base(res, stmt->last_fetch_count_include_ommitted);
 
        return SC_fetch(stmt);
 }
 
+#ifdef DRIVER_CURSOR_IMPLEMENT
+static RETCODE SQL_API
+SC_pos_reload_needed(StatementClass *stmt, UDWORD flag);
+static Int4
+getNthValid(QResultClass *res, Int4 sta, UWORD orientation, UInt4 nth, Int4 *nearest)
+{
+       Int4    i, num_tuples = QR_get_num_total_tuples(res);
+       UInt4   count;
+       KeySet  *keyset;
+
+       if (0 == res->dl_count)
+       {
+               if (SQL_FETCH_PRIOR == orientation)
+               {       
+                       if (sta + 1 >= (Int4) nth)
+                       {
+                               *nearest = sta + 1 - nth;
+                               return nth;
+                       }
+                       *nearest = -1;
+                       return -(Int4)(sta + 1);
+               }
+               else
+               {       
+                       if ((*nearest = sta + nth - 1) < num_tuples)
+                               return nth;
+                       *nearest = num_tuples;
+                       return -(Int4)(num_tuples - sta);
+               }
+       }
+       count = 0;
+       if (SQL_FETCH_PRIOR == orientation)
+       {
+               for (i = sta, keyset = res->keyset + sta;
+                       i >= 0; i--, keyset--)
+               {
+                       if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETING | CURS_OTHER_DELETED)))
+                       {
+                               *nearest = i;
+                               if (++count == nth)
+                                       return count;
+                       }
+               }
+               *nearest = -1; 
+       }
+       else
+       {
+               for (i = sta, keyset = res->keyset + sta;
+                       i < num_tuples; i++, keyset++)
+               {
+                       if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETING | CURS_OTHER_DELETED)))
+                       {
+                               *nearest = i;
+                               if (++count == nth)
+                                       return count;
+                       }
+               }
+               *nearest = num_tuples; 
+       }
+       return -(Int4)count;
+}
+#endif /* DRIVER_CURSOR_IMPLEMENT */
 
+/*
+ *     return NO_DATA_FOUND macros
+ *       save_rowset_start or num_tuples must be defined 
+ */
+#define        EXTFETCH_RETURN_BOF(stmt, res) \
+{ \
+       stmt->rowset_start = -1; \
+       stmt->currTuple = -1; \
+       res->base += (stmt->rowset_start - save_rowset_start); \
+       return SQL_NO_DATA_FOUND; \
+}
+#define        EXTFETCH_RETURN_EOF(stmt, res) \
+{ \
+       stmt->rowset_start = num_tuples; \
+       stmt->currTuple = -1; \
+       res->base += (stmt->rowset_start - save_rowset_start); \
+       return SQL_NO_DATA_FOUND; \
+}
+       
 /*     This fetchs a block of data (rowset). */
 RETCODE                SQL_API
 PGAPI_ExtendedFetch(
@@ -1059,7 +1141,8 @@ PGAPI_ExtendedFetch(
                                        UWORD fFetchType,
                                        SDWORD irow,
                                        UDWORD FAR * pcrow,
-                                       UWORD FAR * rgfRowStatus)
+                                       UWORD FAR * rgfRowStatus,
+                                       SQLINTEGER bookmark_offset)
 {
        static char *func = "PGAPI_ExtendedFetch";
        StatementClass *stmt = (StatementClass *) hstmt;
@@ -1067,11 +1150,17 @@ PGAPI_ExtendedFetch(
        QResultClass *res;
        int                     num_tuples,
                                i,
-                               save_rowset_size;
+                               save_rowset_size,
+                               save_rowset_start,
+                               progress_size;
        RETCODE         result;
        char            truncated,
                                error;
        ConnInfo   *ci;
+       DWORD           currp;
+#ifdef DRIVER_CURSOR_IMPLEMENT
+       UWORD           pstatus;
+#endif /* DRIVER_CURSOR_IMPLEMENT */
 
        mylog("PGAPI_ExtendedFetch: stmt=%u\n", stmt);
 
@@ -1082,12 +1171,13 @@ PGAPI_ExtendedFetch(
        }
        ci = &(SC_get_conn(stmt)->connInfo);
 
-       if (SC_is_fetchcursor(stmt) && !stmt->manual_result)
+       /* if (SC_is_fetchcursor(stmt) && !stmt->manual_result) */
+       if (SQL_CURSOR_FORWARD_ONLY == stmt->options.cursor_type && !stmt->manual_result)
        {
                if (fFetchType != SQL_FETCH_NEXT)
                {
-                       stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
-                       stmt->errormsg = "Unsupported fetch type for PGAPI_ExtendedFetch with UseDeclareFetch option.";
+                       stmt->errornumber = STMT_FETCH_OUT_OF_RANGE;
+                       stmt->errormsg = "The fetch type for PGAPI_ExtendedFetch isn't allowed with ForwardOnly cursor.";
                        return SQL_ERROR;
                }
        }
@@ -1149,9 +1239,10 @@ PGAPI_ExtendedFetch(
        if (pcrow)
                *pcrow = 0;
 
-       num_tuples = QR_get_num_tuples(res);
+       num_tuples = QR_get_num_total_tuples(res);
 
        /* Save and discard the saved rowset size */
+       save_rowset_start = stmt->rowset_start;
        save_rowset_size = stmt->save_rowset_size;
        stmt->save_rowset_size = -1;
 
@@ -1165,11 +1256,29 @@ PGAPI_ExtendedFetch(
                         * SQL_FETCH_FIRST.
                         */
 
+                       progress_size = (save_rowset_size > 0 ? save_rowset_size : opts->rowset_size);
                        if (stmt->rowset_start < 0)
                                stmt->rowset_start = 0;
 
+#ifdef DRIVER_CURSOR_IMPLEMENT
+                       else if (res->keyset)
+                       {
+                               if (stmt->last_fetch_count <= progress_size)
+                               {
+                                       stmt->rowset_start += stmt->last_fetch_count_include_ommitted;
+                                       progress_size -= stmt->last_fetch_count;
+                               }
+                               if (progress_size > 0 &&
+                                   getNthValid(res, stmt->rowset_start,
+                                       SQL_FETCH_NEXT, progress_size + 1,
+                                       &stmt->rowset_start) <= 0)
+                               {
+                                       EXTFETCH_RETURN_EOF(stmt, res)
+                               }
+                       }
+#endif /* DRIVER_CURSOR_IMPLEMENT */
                        else
-                               stmt->rowset_start += (save_rowset_size > 0 ? save_rowset_size : opts->rowset_size);
+                               stmt->rowset_start += progress_size;
 
                        mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
                        break;
@@ -1182,6 +1291,10 @@ PGAPI_ExtendedFetch(
                         * RESULT SET, then this should be equivalent to
                         * SQL_FETCH_LAST.
                         */
+                       if (stmt->rowset_start <= 0)
+                       {
+                               EXTFETCH_RETURN_BOF(stmt, res)
+                       }
                        if (stmt->rowset_start >= num_tuples)
                        {
                                if (opts->rowset_size > num_tuples)
@@ -1194,12 +1307,27 @@ PGAPI_ExtendedFetch(
                        }
                        else
                        {
+#ifdef DRIVER_CURSOR_IMPLEMENT
+                               if (i = getNthValid(res, stmt->rowset_start - 1, SQL_FETCH_PRIOR, opts->rowset_size, &stmt->rowset_start), i < -1)
+                               {
+                                       stmt->errormsg = "fetch prior and before the beggining";
+                                       stmt->errornumber = STMT_POS_BEFORE_RECORDSET;
+                                       stmt->rowset_start = 0;
+                               }
+                               else if (i <= 0)
+                               {
+                                       EXTFETCH_RETURN_BOF(stmt, res)
+                               }
+#else
                                if (stmt->rowset_start < opts->rowset_size)
                                {
                                        stmt->errormsg = "fetch prior and before the beggining";
                                        stmt->errornumber = STMT_POS_BEFORE_RECORDSET;
+                                       stmt->rowset_start = 0;
                                }
-                               stmt->rowset_start -= opts->rowset_size;
+                               else
+                                       stmt->rowset_start -= opts->rowset_size;
+#endif /* DRIVER_CURSOR_IMPLEMENT */
                        }
                        break;
 
@@ -1221,16 +1349,32 @@ PGAPI_ExtendedFetch(
                        /* Position before result set, but dont fetch anything */
                        if (irow == 0)
                        {
-                               stmt->rowset_start = -1;
-                               stmt->currTuple = -1;
-                               return SQL_NO_DATA_FOUND;
+                               EXTFETCH_RETURN_BOF(stmt, res)
                        }
                        /* Position before the desired row */
                        else if (irow > 0)
+#ifdef DRIVER_CURSOR_IMPLEMENT
+                       {
+                               if (getNthValid(res, 0, SQL_FETCH_NEXT, irow, &stmt->rowset_start) <= 0)
+                               {
+                                       EXTFETCH_RETURN_EOF(stmt, res)
+                               }
+                       }
+#else
                                stmt->rowset_start = irow - 1;
+#endif /* DRIVER_CURSOR_IMPLEMENT */
                        /* Position with respect to the end of the result set */
                        else
+#ifdef DRIVER_CURSOR_IMPLEMENT
+                       {
+                               if (getNthValid(res, num_tuples - 1, SQL_FETCH_PRIOR, -irow, &stmt->rowset_start) <= 0)
+                               {
+                                       EXTFETCH_RETURN_BOF(stmt, res)
+                               }
+                       }
+#else
                                stmt->rowset_start = num_tuples + irow;
+#endif /* DRIVER_CURSOR_IMPLEMENT */
                        break;
 
                case SQL_FETCH_RELATIVE:
@@ -1242,11 +1386,43 @@ PGAPI_ExtendedFetch(
                        if (irow == 0)
                                break;
 
+#ifdef DRIVER_CURSOR_IMPLEMENT
+                       if (irow > 0)
+                       {
+                               if (getNthValid(res, stmt->rowset_start + 1, SQL_FETCH_NEXT, irow, &stmt->rowset_start) <= 0)
+                               {
+                                       EXTFETCH_RETURN_EOF(stmt, res)
+                               }
+                       }
+                       else
+                       {
+                               if (getNthValid(res, stmt->rowset_start - 1, SQL_FETCH_PRIOR, -irow, &stmt->rowset_start) <= 0)
+                               {
+                                       EXTFETCH_RETURN_BOF(stmt, res)
+                               }
+                       }
+#else
                        stmt->rowset_start += irow;
+#endif /* DRIVER_CURSOR_IMPLEMENT */
                        break;
 
                case SQL_FETCH_BOOKMARK:
-                       stmt->rowset_start = irow - 1;
+#ifdef DRIVER_CURSOR_IMPLEMENT
+                       if (bookmark_offset > 0)
+                       {
+                               if (getNthValid(res, irow - 1, SQL_FETCH_NEXT, bookmark_offset + 1, &stmt->rowset_start) <= 0)
+                               {
+                                       EXTFETCH_RETURN_EOF(stmt, res)
+                               }
+                       }
+                       else if (getNthValid(res, irow - 1, SQL_FETCH_PRIOR, 1 - bookmark_offset, &stmt->rowset_start) <= 0)
+                       {
+                               stmt->currTuple = -1;
+                               EXTFETCH_RETURN_BOF(stmt, res)
+                       }
+#else
+                       stmt->rowset_start = irow + bookmark_offset - 1;
+#endif /* DRIVER_CURSOR_IMPLEMENT */
                        break;
 
                default:
@@ -1272,8 +1448,7 @@ PGAPI_ExtendedFetch(
                /* If *new* rowset is after the result_set, return no data found */
                if (stmt->rowset_start >= num_tuples)
                {
-                       stmt->rowset_start = num_tuples;
-                       return SQL_NO_DATA_FOUND;
+                       EXTFETCH_RETURN_EOF(stmt, res)
                }
        }
 
@@ -1282,8 +1457,7 @@ PGAPI_ExtendedFetch(
        {
                if (stmt->rowset_start + opts->rowset_size <= 0)
                {
-                       stmt->rowset_start = -1;
-                       return SQL_NO_DATA_FOUND;
+                       EXTFETCH_RETURN_BOF(stmt, res)
                }
                else
                {                                               /* overlap with beginning of result set,
@@ -1298,19 +1472,30 @@ PGAPI_ExtendedFetch(
        /* increment the base row in the tuple cache */
        QR_set_rowset_size(res, opts->rowset_size);
        if (SC_is_fetchcursor(stmt))
-               QR_inc_base(res, stmt->last_fetch_count);
+               QR_inc_base(res, stmt->last_fetch_count_include_ommitted);
        else
                res->base = stmt->rowset_start;
 
+#ifdef DRIVER_CURSOR_IMPLEMENT
+       if (res->keyset)
+               SC_pos_reload_needed(stmt, SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type);
+#endif /* DRIVER_CURSOR_IMPLEMENT */
        /* Physical Row advancement occurs for each row fetched below */
 
        mylog("PGAPI_ExtendedFetch: new currTuple = %d\n", stmt->currTuple);
 
        truncated = error = FALSE;
-       for (i = 0; i < opts->rowset_size; i++)
+       for (i = 0, currp = stmt->rowset_start; i < opts->rowset_size; currp++)
        {
                stmt->bind_row = i;             /* set the binding location */
                result = SC_fetch(stmt);
+#ifdef DRIVER_CURSOR_IMPLEMENT
+               if (SQL_SUCCESS_WITH_INFO == result && 0 == stmt->last_fetch_count && res->keyset)
+               {
+                       res->keyset[stmt->currTuple].status &= ~CURS_IN_ROWSET;
+                       continue;
+               }
+#endif   /* DRIVER_CURSOR_IMPLEMENT */
 
                /* Determine Function status */
                if (result == SQL_NO_DATA_FOUND)
@@ -1328,26 +1513,28 @@ PGAPI_ExtendedFetch(
 #ifdef DRIVER_CURSOR_IMPLEMENT
                        else if (res->keyset)
                        {
-                               DWORD   currp = stmt->rowset_start + i;
-                               UWORD   pstatus = res->keyset[currp].status & KEYSET_INFO_PUBLIC;
-                               if (pstatus != 0)
+                               pstatus = (res->keyset[currp].status & KEYSET_INFO_PUBLIC);
+                               if (pstatus != 0 && pstatus != SQL_ROW_ADDED)
                                {
                                        rgfRowStatus[i] = pstatus;
-                                       /* refresh the status */
-                                       if (SQL_ROW_DELETED != pstatus)
-                                               res->keyset[currp].status &= (~KEYSET_INFO_PUBLIC);
                                }
                                else
                                        rgfRowStatus[i] = SQL_ROW_SUCCESS;
+                               res->keyset[currp].status |= CURS_IN_ROWSET;
+                               /* refresh the status */
+                               /* if (SQL_ROW_DELETED != pstatus) */
+                               res->keyset[currp].status &= (~KEYSET_INFO_PUBLIC);
                        }
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
                        else
                                *(rgfRowStatus + i) = SQL_ROW_SUCCESS;
                }
+               i++;
        }
 
        /* Save the fetch count for SQLSetPos */
        stmt->last_fetch_count = i;
+       stmt->last_fetch_count_include_ommitted = currp - stmt->rowset_start;
 
        /* Reset next binding row */
        stmt->bind_row = 0;
@@ -1393,8 +1580,11 @@ PGAPI_MoreResults(
        mylog("%s: entering...\n", func);
        if (stmt && (res = SC_get_Curres(stmt)))
                SC_set_Curres(stmt, res->next);
-       if (SC_get_Curres(stmt))
-               return SQL_SUCCESS; 
+       if (res = SC_get_Curres(stmt), res)
+       {
+               stmt->diag_row_count = res->recent_processed_row_count;
+               return SQL_SUCCESS;
+       } 
        return SQL_NO_DATA_FOUND;
 }
 
@@ -1424,6 +1614,7 @@ static void KeySetSet(const TupleField *tuple, int num_fields, KeySet *keyset)
        sscanf(tuple[num_fields - 1].value, "%u", &keyset->oid);
 }
 
+static void DiscardDeleted(QResultClass *res, int index);
 static void AddRollback(ConnectionClass *conn, QResultClass *res, int index, const KeySet *keyset)
 {
        Rollback *rollback;
@@ -1479,6 +1670,8 @@ static void DiscardRollback(QResultClass *res)
        {
                index = rollback[i].index;
                status = keyset[index].status;
+               if (0 != (status & CURS_SELF_DELETING))
+                       DiscardDeleted(res, index);
                keyset[index].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING);
                keyset[index].status |= ((status & (CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING)) << 3);
        }
@@ -1487,9 +1680,9 @@ static void DiscardRollback(QResultClass *res)
        res->rb_count = res->rb_alloc = 0;
 }
 
-static void UndoRollback(QResultClass *res)
+static void UndoRollback(StatementClass *stmt, QResultClass *res)
 {
-       int     i, index;
+       int     i, index, ridx;
        UWORD   status;
        Rollback *rollback;
        KeySet  *keyset;
@@ -1502,16 +1695,34 @@ static void UndoRollback(QResultClass *res)
        {
                index = rollback[i].index;
                status = keyset[index].status;
-               if ((status & CURS_SELF_ADDING) != 0)
+               if (0 != (status & CURS_SELF_ADDING))
                {
-                       if (index < res->fcount)
-                               res->fcount = index;
+                       ridx = index - stmt->rowset_start + res->base;
+                       if (ridx >=0 && ridx < res->num_backend_rows)
+                       {
+                               TupleField *tuple = res->backend_tuples + res->num_fields * ridx;
+                               int     j;
+
+                               for (j = 0; j < res->num_fields; j++, tuple++)
+                               {
+                                       if (tuple->len > 0 && tuple->value)
+                                       {
+                                               free(tuple->value);
+                                               tuple->value = NULL;
+                                       }
+                                       tuple->len = 0;
+                               }
+                       }
+                       if (index < res->num_total_rows)
+                               res->num_total_rows = index;
                }
                else
                {
+                       if (0 != (status & CURS_SELF_DELETING))
+                               DiscardDeleted(res, index);
+                       if (0 != (keyset[index].status & CURS_SELF_UPDATING))
+                               keyset[index].status |= CURS_NEEDS_REREAD;
                        keyset[index].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING | KEYSET_INFO_PUBLIC);
-                       keyset[index].blocknum = rollback[i].blocknum;
-                       keyset[index].offset = rollback[i].offset;
                }
        }
        free(rollback);
@@ -1532,13 +1743,66 @@ void    ProcessRollback(ConnectionClass *conn, BOOL undo)
                for (res = SC_get_Result(stmt); res; res = res->next)
                {
                        if (undo)
-                               UndoRollback(res);
+                               UndoRollback(stmt, res);
                        else
                                DiscardRollback(res);
                }
        }
 }
 
+
+static void AddDeleted(QResultClass *res, int index)
+{
+       int     i;
+       UInt4   *deleted;
+
+       if (!res->deleted)
+       {
+               res->dl_count = 0;
+               res->dl_alloc = 10;
+               deleted = res->deleted = malloc(sizeof(UInt4) * res->dl_alloc);
+       }
+       else
+       {
+               if (res->dl_count >= res->dl_alloc)
+               {
+                       res->dl_alloc *= 2; 
+                       if (deleted = realloc(res->deleted, sizeof(UInt4) * res->dl_alloc), !deleted)
+                       {
+                               res->dl_alloc = res->dl_count = 0;
+                               return;
+                       }
+                       res->deleted = deleted; 
+               }
+               for (i = 0, deleted = res->deleted; i < res->dl_count; i++, deleted++)
+               {
+                       if (index < (int) *deleted)
+                               break;
+               }
+               memmove(deleted + 1, deleted, sizeof(UInt4) * (res->dl_count - i)); 
+       }
+       *deleted = index;
+       res->dl_count++;        
+}
+static void DiscardDeleted(QResultClass *res, int index)
+{
+       int     i;
+       UInt4   *deleted;
+
+       if (!res->deleted)
+               return;
+
+       for (i = 0, deleted = res->deleted; i < res->dl_count; i++, deleted++)
+       {
+               if (index == (int) *deleted)
+                       break;
+       }
+       if (i >= res->dl_count)
+               return;
+       memmove(deleted, deleted + 1, sizeof(UInt4) * (res->dl_count - i - 1)); 
+       res->dl_count--;        
+}
+
 #define        LATEST_TUPLE_LOAD       1L
 #define        USE_INSERTED_TID        (1L << 1)
 static QResultClass *
@@ -1555,7 +1819,14 @@ positioned_load(StatementClass *stmt, UInt4 flag, UInt4 oid, const char *tidval)
                len += 100;
                selstr = malloc(len);
                if (latest)
-                       sprintf(selstr, "%s where ctid = currtid2('%s', '%s') and oid  = %u", stmt->load_statement, stmt->ti[0]->name, tidval, oid);
+               {
+                       if (stmt->ti[0]->schema[0])
+                               sprintf(selstr, "%s where ctid = currtid2('\"%s\".\"%s\"', '%s') and oid  = %u",
+                               stmt->load_statement, stmt->ti[0]->schema,
+                               stmt->ti[0]->name, tidval, oid);
+                       else
+                               sprintf(selstr, "%s where ctid = currtid2('%s', '%s') and oid  = %u", stmt->load_statement, stmt->ti[0]->name, tidval, oid);
+               }
                else 
                        sprintf(selstr, "%s where ctid = '%s' and oid = %u", stmt->load_statement, tidval, oid); 
        }
@@ -1579,11 +1850,12 @@ positioned_load(StatementClass *stmt, UInt4 flag, UInt4 oid, const char *tidval)
 }
 
 RETCODE                SQL_API
-SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count)
+SC_pos_reload(StatementClass *stmt, UDWORD global_ridx, UWORD *count, BOOL logChanges)
 {
        int                     i,
                                res_cols;
        UWORD           rcnt, offset;
+       Int4            res_ridx;
        UInt4           oid, blocknum;
        QResultClass *res,
                           *qres;
@@ -1604,7 +1876,7 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count
                stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
                return SQL_ERROR;
        }
-       global_ridx = irow + stmt->rowset_start;
+       res_ridx = global_ridx - stmt->rowset_start + res->base;
        if (!(oid = getOid(res, global_ridx)))
                return SQL_SUCCESS_WITH_INFO;
        getTid(res, global_ridx, &blocknum, &offset);
@@ -1613,9 +1885,12 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count
        if (qres = positioned_load(stmt, LATEST_TUPLE_LOAD, oid, tidval), qres)
        {
                TupleField *tupleo, *tuplen;
+               ConnectionClass *conn = SC_get_conn(stmt);
 
-               rcnt = QR_get_num_tuples(qres);
-               tupleo = res->backend_tuples + res->num_fields * global_ridx;
+               rcnt = QR_get_num_backend_tuples(qres);
+               tupleo = res->backend_tuples + res->num_fields * res_ridx;
+               if (logChanges && CC_is_in_trans(conn))
+                       AddRollback(conn, res, global_ridx, res->keyset);
                if (rcnt == 1)
                {
                        int     effective_fields = res_cols;
@@ -1647,8 +1922,6 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count
                        ret = SQL_SUCCESS_WITH_INFO;
                        if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
                        {
-                               res->keyset[global_ridx].blocknum = 0;
-                               res->keyset[global_ridx].offset = 0;
                                res->keyset[global_ridx].status |= SQL_ROW_DELETED;
                        }
                }
@@ -1661,6 +1934,162 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UDWORD global_ridx, UWORD *count
        return ret;
 }
 
+static RETCODE SQL_API
+SC_pos_reload_needed(StatementClass *stmt, UDWORD flag)
+{
+       Int4            i, limitrow;
+       UWORD           qcount;
+       QResultClass    *res;
+       IRDFields       *irdflds = SC_get_IRD(stmt);
+       RETCODE         ret = SQL_ERROR;
+       ConnectionClass *conn = SC_get_conn(stmt);
+       UInt4           oid, blocknum, lodlen;
+       char            *qval = NULL, *sval;
+       Int4            rowc;
+       UWORD           offset;
+       BOOL            create_from_scratch = (0 != flag);
+
+       mylog("SC_pos_reload_needed\n");
+       if (!(res = SC_get_Curres(stmt)))
+               return SQL_ERROR;
+       if (!stmt->ti)
+               parse_statement(stmt);  /* not preferable */
+       if (!stmt->updatable)
+       {
+               stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
+               return SQL_ERROR;
+       }
+       limitrow = stmt->rowset_start + res->rowset_size;
+       if (limitrow > res->num_total_rows)
+               limitrow = res->num_total_rows;
+       if (create_from_scratch)
+       {
+               int     flds_cnt = res->num_backend_rows * res->num_fields,
+                       brows;
+
+               for (i = 0; i < flds_cnt; i++)
+               {
+                       if (res->backend_tuples[i].value)
+                               free(res->backend_tuples[i].value);
+               }
+               brows = limitrow - stmt->rowset_start;
+               if (brows > res->count_backend_allocated)
+               {
+                       res->backend_tuples = realloc(res->backend_tuples, sizeof(TupleField) * res->num_fields * brows);
+                       res->count_backend_allocated = brows;
+               }
+               if (brows > 0)
+                       memset(res->backend_tuples, 0, sizeof(TupleField) * res->num_fields * brows);
+               res->num_backend_rows = brows;
+               res->base = 0;
+               for (i = stmt->rowset_start; i < limitrow; i++)
+               {
+                       if (0 == (res->keyset[i].status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
+                               res->keyset[i].status |= CURS_NEEDS_REREAD;
+               }
+       }
+
+       for (i = stmt->rowset_start, rowc = 0;; i++)
+       {
+               if (i >= limitrow)
+               {
+                       if (!rowc)
+                               break;
+                       rowc = -1; /* end of loop */
+               }
+               if (rowc < 0 || rowc >= 10)
+               {
+                       QResultClass    *qres;
+
+                       strcpy(sval, ")");
+                       qres = CC_send_query(conn, qval, NULL, CLEAR_RESULT_ON_ABORT | CREATE_KEYSET);
+                       if (qres)
+                       {
+                               int             j, k, l, m;
+                               TupleField      *tuple, *tuplew;
+
+                               for (j = 0; j < qres->num_total_rows; j++)
+                               {
+                                       oid = getOid(qres, j); 
+                                       getTid(qres, j, &blocknum, &offset);
+                                       for (k = stmt->rowset_start; k < limitrow; k++)
+                                       {
+                                               if (oid == getOid(res, k))
+                                               {
+                                                       l = k - stmt->rowset_start + res->base;
+                                                       tuple = res->backend_tuples + res->num_fields * l;
+                                                       tuplew = qres->backend_tuples + qres->num_fields * j;
+                                                       for (m = 0; m < res->num_fields; m++, tuple++, tuplew++)
+                                                       {
+                                                               if (tuple->len > 0 && tuple->value)
+                                                                       free(tuple->value);
+                                                               tuple->value = tuplew->value;
+                                                               tuple->len = tuplew->len;
+                                                               tuplew->value = NULL;
+                                                               tuplew->len = 0;
+                                                       }
+                                                       res->keyset[k].status &= ~CURS_NEEDS_REREAD;
+                                                       break;
+                                               }
+                                       }
+                               }
+                               QR_Destructor(qres);
+                       }
+                       if (rowc < 0)
+                               break;
+                       rowc = 0;
+               }
+               if (!rowc)
+               {
+                       if (!qval)
+                       {
+                               UInt4   allen;
+
+                               lodlen = strlen(stmt->load_statement);
+                               allen = lodlen + 20 + 23 * 10;
+                               qval = malloc(allen);
+                       }
+                       memcpy(qval, stmt->load_statement, lodlen);
+                       sval = qval + lodlen;
+                       sval[0]= '\0';
+                       strcpy(sval, " where ctid in (");
+                       sval = strchr(sval, '\0');
+               }
+               if (0 != (res->keyset[i].status & CURS_NEEDS_REREAD))
+               {
+                       getTid(res, i, &blocknum, &offset);
+                       if (rowc)
+                               sprintf(sval, ", '(%u, %u)'", blocknum, offset);
+                       else
+                               sprintf(sval, "'(%u, %u)'", blocknum, offset);
+                       sval = strchr(sval, '\0');
+                       rowc++;
+               }
+       }
+       if (qval)
+               free(qval);
+       else
+               return SQL_SUCCESS;
+
+       for (i = stmt->rowset_start; i < limitrow; i++)
+       {
+               if (0 != (res->keyset[i].status & CURS_NEEDS_REREAD))
+               {
+                       ret = SC_pos_reload(stmt, i, &qcount, FALSE);
+                       if (SQL_ERROR == ret)
+                       {
+                               break;
+                       }
+                       if (SQL_ROW_DELETED == (res->keyset[i].status & KEYSET_INFO_PUBLIC))
+                       {
+                               res->keyset[i].status |= CURS_OTHER_DELETED;
+                       }
+                       res->keyset[i].status &= ~CURS_NEEDS_REREAD;
+               }
+       }
+       return ret;
+}
+
 RETCODE                SQL_API
 SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
 {
@@ -1681,51 +2110,64 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
        if (qres = positioned_load(stmt, tidRef ? USE_INSERTED_TID : 0, oid, NULL), qres)
        {
                TupleField *tupleo, *tuplen;
-               int                     count = QR_get_num_tuples(qres);
+               int             count = QR_get_num_backend_tuples(qres);
 
                QR_set_position(qres, 0);
                if (count == 1)
                {
                        int     effective_fields = res->num_fields;
+                       int     tuple_size;
 
                        tuplen = qres->tupleField;
-                       if (res->fcount >= res->count_allocated)
+                       if (res->haskeyset &&
+                           res->num_total_rows >= res->count_keyset_allocated)
                        {
-                               int                     tuple_size;
 
-                               if (!res->count_allocated)
+                               if (!res->count_keyset_allocated)
                                        tuple_size = TUPLE_MALLOC_INC;
                                else
-                                       tuple_size = res->count_allocated * 2;
-                               res->backend_tuples = (TupleField *) realloc(
-                                                                                                        res->backend_tuples,
-                                         res->num_fields * sizeof(TupleField) * tuple_size);
-                               if (!res->backend_tuples)
-                               {
-                                       stmt->errornumber = res->status = PGRES_FATAL_ERROR;
-                                       stmt->errormsg = "Out of memory while reading tuples.";
-                                       QR_Destructor(qres);
-                                       return SQL_ERROR;
-                               }
-                               if (res->haskeyset)
-                                       res->keyset = (KeySet *) realloc(res->keyset, sizeof(KeySet) * tuple_size);     
-                               res->count_allocated = tuple_size;
+                                       tuple_size = res->count_keyset_allocated * 2;
+                               res->keyset = (KeySet *) realloc(res->keyset, sizeof(KeySet) * tuple_size);     
+                               res->count_keyset_allocated = tuple_size;
                        }
-                       tupleo = res->backend_tuples + res->num_fields * res->fcount;
-                       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;
-                       }
-                       for (; i < res->num_fields; i++)
+                       KeySetSet(tuplen, qres->num_fields, res->keyset + res->num_total_rows);
+
+                       if (res->num_total_rows == res->num_backend_rows - res->base + stmt->rowset_start)
                        {
-                               tupleo[i].len = 0;
-                               tupleo[i].value = NULL;
+                               if (res->num_backend_rows >= res->count_backend_allocated)
+                               {
+                                       if (!res->count_backend_allocated)
+                                               tuple_size = TUPLE_MALLOC_INC;
+                                       else
+                                               tuple_size = res->count_backend_allocated * 2;
+                                       res->backend_tuples = (TupleField *) realloc(
+                                               res->backend_tuples,
+                                               res->num_fields * sizeof(TupleField) * tuple_size);
+                                       if (!res->backend_tuples)
+                                       {
+                                               stmt->errornumber = res->status = PGRES_FATAL_ERROR;
+                                               stmt->errormsg = "Out of memory while reading tuples.";
+                                               QR_Destructor(qres);
+                                               return SQL_ERROR;
+                                       }
+                                       res->count_backend_allocated = tuple_size;
+                               }
+                               tupleo = res->backend_tuples + res->num_fields * res->num_backend_rows;
+                               for (i = 0; i < effective_fields; i++)
+                               {
+                                       tupleo[i].len = tuplen[i].len;
+                                       tuplen[i].len = 0;
+                                       tupleo[i].value = tuplen[i].value;
+                                       tuplen[i].value = NULL;
+                               }
+                               for (; i < res->num_fields; i++)
+                               {
+                                       tupleo[i].len = 0;
+                                       tupleo[i].value = NULL;
+                               }
+                               res->num_backend_rows++;
                        }
-                       res->fcount++;
+                       res->num_total_rows++;
                        ret = SQL_SUCCESS;
                }
                else if (0 == count)
@@ -1737,7 +2179,7 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
                        ret = SQL_ERROR;
                }
                QR_Destructor(qres);
-               /* stmt->currTuple = stmt->rowset_start + irow; */
+               /* stmt->currTuple = stmt->rowset_start + ridx; */
        }
        return ret;
 }
@@ -1754,14 +2196,14 @@ irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow
                        sscanf(cmdstr, "UPDATE %d", &updcnt) == 1)
                {
                        if (updcnt == 1)
-                               SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0);
+                               ret = SC_pos_reload(stmt, global_ridx, (UWORD *) 0, TRUE);
                        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, global_ridx, (UWORD *) 0);
+                                       SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
                        }
                        else
                                ret = SQL_ERROR;
@@ -1812,7 +2254,10 @@ SC_pos_update(StatementClass *stmt,
        }
        getTid(res, global_ridx, &blocknum, &pgoffset);
 
-       sprintf(updstr, "update \"%s\" set", stmt->ti[0]->name);
+       if (stmt->ti[0]->schema[0])
+               sprintf(updstr, "update \"%s\".\"%s\" set", stmt->ti[0]->schema, stmt->ti[0]->name);
+       else
+               sprintf(updstr, "update \"%s\" set", stmt->ti[0]->name);
        num_cols = irdflds->nfields;
        offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
        for (i = upd_cols = 0; i < num_cols; i++)
@@ -1842,8 +2287,10 @@ SC_pos_update(StatementClass *stmt,
                HSTMT           hstmt;
                int                     j;
                int                     res_cols = QR_NumResultCols(res);
+               ConnInfo        *ci = &(conn->connInfo);
                StatementClass *qstmt;
                APDFields       *apdopts;
+               Int4            fieldtype = 0;
 
                /*sprintf(updstr, "%s where ctid = '%s' and oid = %s", updstr,
                                tidval, oidval);*/
@@ -1868,10 +2315,11 @@ SC_pos_update(StatementClass *stmt,
                                mylog("%d used=%d\n", i, *used);
                                if (*used != SQL_IGNORE && fi[i]->updatable)
                                {
+                                       fieldtype = QR_get_field_type(res, i);
                                        PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++j,
                                                                 SQL_PARAM_INPUT, bindings[i].returntype,
-                                         pgtype_to_concise_type(stmt, QR_get_field_type(res, i)),
-                                                                               QR_get_fieldsize(res, i),
+                                         pgtype_to_concise_type(stmt, fieldtype),
+                                                                                                                       fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(stmt, fieldtype, i, ci->drivers.unknown_sizes),
                                                                        (SQLSMALLINT) fi[i]->decimal_digits,
                                                                                bindings[i].buffer,
                                                                                bindings[i].buflen,
@@ -1905,7 +2353,6 @@ SC_pos_update(StatementClass *stmt,
        {
                if (CC_is_in_trans(conn))
                {
-                       AddRollback(conn, res, global_ridx, res->keyset);
                        res->keyset[global_ridx].status |= (SQL_ROW_UPDATED  | CURS_SELF_UPDATING);
                }
                else
@@ -1939,7 +2386,7 @@ SC_pos_delete(StatementClass *stmt,
        BindInfoClass *bindings = opts->bindings;
        char            dltstr[4096];
        RETCODE         ret;
-       UInt4           oid, blocknum;
+       UInt4           oid, blocknum, qflag;
 
        mylog("POS DELETE ti=%x\n", stmt->ti);
        if (!(res = SC_get_Curres(stmt)))
@@ -1958,11 +2405,19 @@ SC_pos_delete(StatementClass *stmt,
        }
        getTid(res, global_ridx, &blocknum, &offset);
        /*sprintf(dltstr, "delete from \"%s\" where ctid = '%s' and oid = %s",*/
-       sprintf(dltstr, "delete from \"%s\" where ctid = '(%u, %u)' and oid = %u",
+       if (stmt->ti[0]->schema[0])
+               sprintf(dltstr, "delete from \"%s\".\"%s\" where ctid = '(%u, %u)' and oid = %u",
+               stmt->ti[0]->schema, stmt->ti[0]->name, blocknum, offset, oid);
+       else
+               sprintf(dltstr, "delete from \"%s\" where ctid = '(%u, %u)' and oid = %u",
                        stmt->ti[0]->name, blocknum, offset, oid);
 
        mylog("dltstr=%s\n", dltstr);
-       qres = CC_send_query(conn, dltstr, NULL, CLEAR_RESULT_ON_ABORT);
+       qflag = CLEAR_RESULT_ON_ABORT;
+        if (!stmt->internal && !CC_is_in_trans(conn) &&
+                 (!CC_is_in_autocommit(conn)))
+               qflag |= GO_INTO_TRANSACTION;
+       qres = CC_send_query(conn, dltstr, NULL, qflag);
        ret = SQL_SUCCESS;
        if (qres && QR_command_maybe_successful(qres))
        {
@@ -1973,14 +2428,14 @@ SC_pos_delete(StatementClass *stmt,
                        sscanf(cmdstr, "DELETE %d", &dltcnt) == 1)
                {
                        if (dltcnt == 1)
-                               SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0);
+                               SC_pos_reload(stmt, global_ridx, (UWORD *) 0, TRUE);
                        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, global_ridx, (UWORD *) 0);
+                                       SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
                        }
                        else
                                ret = SQL_ERROR;
@@ -1999,9 +2454,9 @@ SC_pos_delete(StatementClass *stmt,
                QR_Destructor(qres);
        if (SQL_SUCCESS == ret && res->keyset)
        {
+               AddDeleted(res, global_ridx);
                if (CC_is_in_trans(conn))
                {
-                       AddRollback(conn, res, global_ridx, res->keyset);
                        res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETING);
                }
                else
@@ -2085,6 +2540,7 @@ SC_pos_add(StatementClass *stmt,
        HSTMT           hstmt;
        StatementClass *qstmt;
        ConnectionClass *conn;
+       ConnInfo        *ci;
        QResultClass *res;
        ARDFields       *opts = SC_get_ARD(stmt);
        IRDFields       *irdflds = SC_get_IRD(stmt);
@@ -2095,6 +2551,7 @@ SC_pos_add(StatementClass *stmt,
        RETCODE         ret;
        UInt4           offset;
        Int4            *used, bind_size = opts->bind_size;
+       Int4            fieldtype;
 
        mylog("POS ADD fi=%x ti=%x\n", fi, stmt->ti);
        if (!(res = SC_get_Curres(stmt)))
@@ -2108,7 +2565,10 @@ SC_pos_add(StatementClass *stmt,
        }
        num_cols = irdflds->nfields;
        conn = SC_get_conn(stmt);
-       sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name);
+       if (stmt->ti[0]->schema[0])
+               sprintf(addstr, "insert into \"%s\".\"%s\" (", stmt->ti[0]->schema, stmt->ti[0]->name);
+       else
+               sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name);
        if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
                return SQL_ERROR;
        if (opts->row_offset_ptr)
@@ -2119,6 +2579,7 @@ SC_pos_add(StatementClass *stmt,
        apdopts = SC_get_APD(qstmt);
        apdopts->param_bind_type = opts->bind_size;
        apdopts->param_offset_ptr = opts->row_offset_ptr;
+       ci = &(conn->connInfo);
        for (i = add_cols = 0; i < num_cols; i++)
        {
                if (used = bindings[i].used, used != NULL)
@@ -2131,14 +2592,15 @@ SC_pos_add(StatementClass *stmt,
                        mylog("%d used=%d\n", i, *used);
                        if (*used != SQL_IGNORE && fi[i]->updatable)
                        {
+                               fieldtype = QR_get_field_type(res, i);
                                if (add_cols)
                                        sprintf(addstr, "%s, \"%s\"", addstr, fi[i]->name);
                                else
                                        sprintf(addstr, "%s\"%s\"", addstr, fi[i]->name);
                                PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++add_cols,
                                                                 SQL_PARAM_INPUT, bindings[i].returntype,
-                                         pgtype_to_concise_type(stmt, QR_get_field_type(res, i)),
-                                                                       QR_get_fieldsize(res, i),
+                                         pgtype_to_concise_type(stmt, fieldtype),
+                                                                                                                       fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(stmt, fieldtype, i, ci->drivers.unknown_sizes),
                                                                        (SQLSMALLINT) fi[i]->decimal_digits,
                                                                        bindings[i].buffer,
                                                                        bindings[i].buflen,
@@ -2178,7 +2640,7 @@ SC_pos_add(StatementClass *stmt,
                }
                brow_save = stmt->bind_row; 
                stmt->bind_row = irow; 
-               ret = irow_insert(ret, stmt, qstmt, res->fcount);
+               ret = irow_insert(ret, stmt, qstmt, res->num_total_rows);
                stmt->bind_row = brow_save; 
        }
        else
@@ -2189,7 +2651,7 @@ SC_pos_add(StatementClass *stmt,
        PGAPI_FreeStmt(hstmt, SQL_DROP);
        if (SQL_SUCCESS == ret && res->keyset)
        {
-               int     global_ridx = res->fcount - 1;
+               int     global_ridx = res->num_total_rows + stmt->rowset_start - res->base - 1;
                if (CC_is_in_trans(conn))
                {
 
@@ -2230,16 +2692,18 @@ SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx)
 #endif /* ODBCVER */
        /* save the last_fetch_count */
        int             last_fetch = stmt->last_fetch_count;
+       int             last_fetch2 = stmt->last_fetch_count_include_ommitted;
        int             bind_save = stmt->bind_row;
 
 #ifdef DRIVER_CURSOR_IMPLEMENT
        if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
-               SC_pos_reload(stmt, irow, global_ridx, (UWORD *) 0);
+               SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
        stmt->bind_row = irow;
        ret = SC_fetch(stmt);
        /* restore the last_fetch_count */
        stmt->last_fetch_count = last_fetch;
+       stmt->last_fetch_count_include_ommitted = last_fetch2;
        stmt->bind_row = bind_save;
 #if (ODBCVER >= 0x0300)
        if (irdflds->rowStatusArray)
@@ -2252,6 +2716,7 @@ SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx)
                        case SQL_SUCCESS:
                                irdflds->rowStatusArray[irow] = SQL_ROW_SUCCESS;
                                break;
+                       case SQL_SUCCESS_WITH_INFO:
                        default:
                                irdflds->rowStatusArray[irow] = ret;
                                break;
@@ -2278,10 +2743,11 @@ PGAPI_SetPos(
        StatementClass *stmt = (StatementClass *) hstmt;
        ConnectionClass *conn = SC_get_conn(stmt);
        QResultClass *res;
-       int             num_cols, i, start_row, end_row, processed;
+       int             num_cols, i, start_row, end_row, processed, ridx;
+       UWORD           nrow;
        ARDFields       *opts;
        BindInfoClass *bindings;
-       UDWORD          global_ridx, fcount;
+       UDWORD          global_ridx;
        BOOL            auto_commit_needed = FALSE;
 
        if (!stmt)
@@ -2318,8 +2784,8 @@ PGAPI_SetPos(
        {
                if (SQL_POSITION == fOption)
                {
-                       stmt->errornumber = STMT_ROW_OUT_OF_RANGE;
-                       stmt->errormsg = "Bulk Fresh operations not allowed.";
+                       stmt->errornumber = STMT_INVALID_CURSOR_POSITION;
+                       stmt->errormsg = "Bulk Position operations not allowed.";
                        SC_log_error(func, "", stmt);
                        return SQL_ERROR;
                }
@@ -2344,7 +2810,6 @@ PGAPI_SetPos(
                for (i = 0; i < num_cols; i++)
                        bindings[i].data_left = -1;
        ret = SQL_SUCCESS;
-       fcount = res->fcount;
 #ifdef DRIVER_CURSOR_IMPLEMENT
        switch (fOption)
        {
@@ -2356,28 +2821,47 @@ PGAPI_SetPos(
                        break;
        }
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
-       for (i = start_row, processed = 0; i <= end_row; i++)
+       ridx = -1;
+       for (i = nrow = 0, processed = 0; nrow <= end_row; i++)
        {
+               global_ridx = i + stmt->rowset_start;
+               if (SQL_ADD != fOption)
+               {
+                       if ((int) global_ridx >= res->num_total_rows)
+                               break;
+#ifdef DRIVER_CURSOR_IMPLEMENT
+                       if (res->keyset) /* the row may be deleted and not in the rowset */
+                       {
+                               if (0 == (res->keyset[global_ridx].status & CURS_IN_ROWSET))
+                                       continue;
+                       }
+#endif   /* DRIVER_CURSOR_IMPLEMENT */
+               }
+               if (nrow < start_row)
+               {
+                       nrow++;
+                       continue;
+               }
+               ridx = nrow;
 #if (ODBCVER >= 0x0300)
-               if (0 != irow || !opts->row_operation_ptr || opts->row_operation_ptr[i] == SQL_ROW_PROCEED)
+               if (0 != irow || !opts->row_operation_ptr || opts->row_operation_ptr[nrow] == SQL_ROW_PROCEED)
                {
 #endif /* ODBCVER */
-                       global_ridx = i + stmt->rowset_start;
                        switch (fOption)
                        {
 #ifdef DRIVER_CURSOR_IMPLEMENT
                                case SQL_UPDATE:
-                                       ret = SC_pos_update(stmt, (UWORD) i, global_ridx);
+                                       ret = SC_pos_update(stmt, nrow, global_ridx);
                                        break;
                                case SQL_DELETE:
-                                       ret = SC_pos_delete(stmt, (UWORD) i, global_ridx);
+                                       ret = SC_pos_delete(stmt, nrow, global_ridx);
                                        break;
                                case SQL_ADD:
-                                       ret = SC_pos_add(stmt, (UWORD) i);
+                                       ret = SC_pos_add(stmt, nrow);
                                        break;
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
                                case SQL_REFRESH:
-                                       ret = SC_pos_refresh(stmt, (UWORD) i, global_ridx);
+                                       ret = SC_pos_refresh(stmt, nrow, global_ridx);
                                        break;
                        }
                        processed++;
@@ -2386,21 +2870,23 @@ PGAPI_SetPos(
 #if (ODBCVER >= 0x0300)
                }
 #endif /* ODBCVER */
+               nrow++;
        }
        if (SQL_ERROR == ret)
-               res->fcount = fcount; /* restore the count */
+               CC_abort(conn);
        if (auto_commit_needed)
                PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
        if (irow > 0)
        {
-               if (SQL_ADD != fOption) /* for SQLGetData */
+               if (SQL_ADD != fOption && ridx >= 0) /* for SQLGetData */
                { 
-                       stmt->currTuple = stmt->rowset_start + irow - 1;
-                       QR_set_position(res, irow - 1);
+                       stmt->currTuple = stmt->rowset_start + ridx;
+                       QR_set_position(res, ridx);
                }
        }
        else if (SC_get_IRD(stmt)->rowsFetched)
-                       *SC_get_IRD(stmt)->rowsFetched = processed;
+               *(SC_get_IRD(stmt)->rowsFetched) = processed;
+       res->recent_processed_row_count = stmt->diag_row_count = processed;
 inolog("rowset=%d processed=%d ret=%d\n", opts->rowset_size, processed, ret);
        return ret; 
 }
@@ -2408,11 +2894,10 @@ inolog("rowset=%d processed=%d ret=%d\n", opts->rowset_size, processed, ret);
 
 /*             Sets options that control the behavior of cursors. */
 RETCODE                SQL_API
-PGAPI_SetScrollOptions(
-                                          HSTMT hstmt,
-                                          UWORD fConcurrency,
-                                          SDWORD crowKeyset,
-                                          UWORD crowRowset)
+PGAPI_SetScrollOptions( HSTMT hstmt,
+                               UWORD fConcurrency,
+                               SDWORD crowKeyset,
+                               UWORD crowRowset)
 {
        static char *func = "PGAPI_SetScrollOptions";
        StatementClass *stmt = (StatementClass *) hstmt;
index 122fcbf..551c315 100644 (file)
@@ -272,7 +272,7 @@ SC_Constructor(void)
                rv->rowset_start = -1;
                rv->current_col = -1;
                rv->bind_row = 0;
-               rv->last_fetch_count = 0;
+               rv->last_fetch_count = rv->last_fetch_count_include_ommitted = 0;
                rv->save_rowset_size = -1;
 
                rv->data_at_exec = -1;
@@ -302,6 +302,7 @@ SC_Constructor(void)
                rv->miscinfo = 0;
                rv->updatable = FALSE;
                rv->error_recsize = -1;
+               rv->diag_row_count = 0;
        }
        return rv;
 }
@@ -533,7 +534,7 @@ SC_recycle_statement(StatementClass *self)
        self->rowset_start = -1;
        self->current_col = -1;
        self->bind_row = 0;
-       self->last_fetch_count = 0;
+       self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
 
        self->errormsg = NULL;
        self->errornumber = 0;
@@ -619,6 +620,7 @@ SC_clear_error(StatementClass *self)
        self->errormsg_created = FALSE;
        self->errorpos = 0;
        self->error_recsize = -1;
+       self->diag_row_count = 0;
 }
 
 
@@ -733,21 +735,21 @@ SC_fetch(StatementClass *self)
        /* TupleField *tupleField; */
        ConnInfo   *ci = &(SC_get_conn(self)->connInfo);
 
-       self->last_fetch_count = 0;
+       self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
        coli = QR_get_fields(res);      /* the column info */
 
        mylog("manual_result = %d, use_declarefetch = %d\n", self->manual_result, ci->drivers.use_declarefetch);
 
        if (self->manual_result || !SC_is_fetchcursor(self))
        {
-               if (self->currTuple >= QR_get_num_tuples(res) - 1 ||
+               if (self->currTuple >= QR_get_num_total_tuples(res) - 1 ||
                        (self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1))
                {
                        /*
                         * if at the end of the tuples, return "no data found" and set
                         * the cursor past the end of the result set
                         */
-                       self->currTuple = QR_get_num_tuples(res);
+                       self->currTuple = QR_get_num_total_tuples(res);
                        return SQL_NO_DATA_FOUND;
                }
 
@@ -774,11 +776,23 @@ SC_fetch(StatementClass *self)
                        return SQL_ERROR;
                }
        }
+#ifdef DRIVER_CURSOR_IMPLEMENT
+       if (res->haskeyset)
+       {
+               UWORD   pstatus = res->keyset[self->currTuple].status;
+               if (0 != (pstatus & (CURS_SELF_DELETING | CURS_SELF_DELETED)))
+                       return SQL_SUCCESS_WITH_INFO;
+               if (SQL_ROW_DELETED != (pstatus & KEYSET_INFO_PUBLIC) &&
+                   0 != (pstatus & CURS_OTHER_DELETED))
+                       return SQL_SUCCESS_WITH_INFO;
+       }
+#endif   /* DRIVER_CURSOR_IMPLEMENT */
 
        num_cols = QR_NumResultCols(res);
 
        result = SQL_SUCCESS;
-       self->last_fetch_count = 1;
+       self->last_fetch_count++;
+       self->last_fetch_count_include_ommitted++;
 
        opts = SC_get_ARD(self);
        /*
@@ -830,7 +844,12 @@ SC_fetch(StatementClass *self)
                        else if (SC_is_fetchcursor(self))
                                value = QR_get_value_backend(res, lf);
                        else
-                               value = QR_get_value_backend_row(res, self->currTuple, lf);
+                       {
+                               int curt = res->base;
+                               if (self->rowset_start >= 0)
+                                       curt += (self->currTuple - self->rowset_start);
+                               value = QR_get_value_backend_row(res, curt, lf);
+                       }
 
                        mylog("value = '%s'\n", (value == NULL) ? "<NULL>" : value);
 
@@ -1152,7 +1171,7 @@ SC_log_error(const char *func, const char *desc, const StatementClass *self)
                if (res)
                {
                        qlog("                 fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn);
-                       qlog("                 fetch_count=%d, fcount=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->fcount, res->num_fields, nullcheck(res->cursor));
+                       qlog("                 fetch_count=%d, num_total_rows=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->num_total_rows, res->num_fields, nullcheck(res->cursor));
                        qlog("                 message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice));
                        qlog("                 status=%d, inTuples=%d\n", res->status, res->inTuples);
                }
index e0a01b7..f1c2ddd 100644 (file)
@@ -80,6 +80,7 @@ typedef enum
 #define STMT_ERROR_IN_ROW                                              30
 #define STMT_INVALID_DESCRIPTOR_IDENTIFIER                             31
 #define STMT_OPTION_NOT_FOR_THE_DRIVER                                 32
+#define STMT_FETCH_OUT_OF_RANGE                                                33
 
 /* statement types */
 enum
@@ -137,15 +138,6 @@ struct StatementClass_
        char       *errormsg;
        int                     errornumber;
 
-       /* information on bindings */
-       /*** BindInfoClass *bindings; ***/      /* array to store the binding information */
-       /*** BindInfoClass bookmark;
-       int                     bindings_allocated; ***/
-
-       /* information on statement parameters */
-       /*** int                        parameters_allocated;
-       ParameterInfoClass *parameters; ***/
-
        Int4            currTuple;              /* current absolute row number (GetData,
                                                                 * SetPos, SQLFetch) */
        int                     save_rowset_size;               /* saved rowset size in case of
@@ -200,9 +192,11 @@ struct StatementClass_
        char            updatable;
        SWORD           errorpos;
        SWORD           error_recsize;
+       Int4            diag_row_count;
        char            *load_statement; /* to (re)load updatable individual rows */
        Int4            from_pos;       
        Int4            where_pos;
+       Int4            last_fetch_count_include_ommitted;
 };
 
 #define SC_get_conn(a)   (a->hdbc)
index eb00cfd..c7fe46d 100644 (file)
@@ -53,6 +53,8 @@ struct Rollback_
 #define        CURS_SELF_DELETED       (1L << 7)
 #define        CURS_SELF_UPDATED       (1L << 8)
 #define        CURS_NEEDS_REREAD       (1L << 9)
+#define        CURS_IN_ROWSET          (1L << 10)
+#define        CURS_OTHER_DELETED      (1L << 11)
 
 /*     These macros are wrappers for the corresponding set_tuplefield functions
        but these handle automatic NULL determination and call set_tuplefield_null()