1) Support Keyset Driven driver cursors.
authorHiroshi Inoue
Wed, 22 May 2002 05:51:03 +0000 (05:51 +0000)
committerHiroshi Inoue
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 e931b8b8d51766aaf5332b2c5d8501cfe2916071..e6deedaa8b6b8107ce20d9c8d01b7bfac9ec0a58 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 7eadea92e44c41a42b2bb4440ef7741b720c8258..f2467c7713a9b2e3762bfda4115ac031bd838d9a 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 2b0d67a648d8ff000c5994b6f319b572dad8b18c..81ed7d5ba7ad36fd7292dafb92c8fbad68892ae7 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 849350d14d1e0456d286dd662965c61a6d8b22d0..3bd86328453a6a85c69c329d3da98d78f84d1833 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 433f4b3fe17a4820771f7941260bddd4f31efe45..d33f390e485a10508a840335581f9b1039d097c7 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 59e4212ed63b04147991777e6ff06faa9b84334f..182142bf2ea541fe727f3d10815675e67ed45cdc 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 a4423e43b41cedb432c8b62427a5b18f5ca5a7e2..259c7b3692a6b0e051fe08ddde8d4b5d1ae47368 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 7c8f80dd8f22ea96017d5ad460e0cae6e60b8445..9ac8f8eb6cf2a1b898b37ce8e1f0f2d9dafff443 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 f82a327f9958d62b32695550364f8b43ee6ec7b9..164debbf4d0e94e21c0cc504a9af500925247c26 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 75deea4c7bd649bd2a628378bcad1b38c365ae1c..9b9844e396c0c3d87d1e3048f19f23db430f95d2 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 f92c2ab6ff787658eb4b69e64e80a1145b43a80c..50245343078e952e9fc2a5ff52ebbcca8d5fb95e 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 df99994175999588196f47f3bbf7baf9215ddcfe..e4828455f511e3a3f6511685edbbea3e2bb6aa3a 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 fe946eebfa12ce020b2a4dd45ee3e1ac8de71395..161920f9b2b017d3a8caa89d263c5c765ec8fedc 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 d116d00006c666da35ce0806f719ff9ed7c5fa47..6a4a618b38a233ec86f22144d0b1b2e022899146 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 0c03007701bc6c9c807224db6551b6e73360b867..cf73924065e3237b60c1392f84c72c867f2929e8 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 ac0f1d9931fe361332929a3c06290a9e5b69ca7a..8992353b315afb7e0e0ac8c280272d652cb9a815 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 ab974c3cd0047f34ae2979604e08ad4fdfb09e6a..f4a510a58731d3d840b6ee998d1f372e79b08608 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 cb77fddd83658f5d76dd595c3a5af0565e24710d..2ca0ef00f99a437594f2cbc94876da9b12d5d02f 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 e73773931565aa784db8702d240c5d10c7c65536..7fd6c9ac1c5c55f0d78c63f117a10325a31b3c13 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 f4c740bca84c60748434c3077776de63543c36e6..756a49d94588dff283065ed71250858128842fce 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 74df2a79e93f9c70f14ed9d358a9bd4bc03a52df..fe0d5b86deac8622e33566e9cf6bd7350c378ca7 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 3a2d8c9cb0bec0fe0d003d58abf0aca8be514f02..6d39e63737f63924ccbf2b36d0c7877822547fd7 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              /* 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 050b45d94139acf15783b8f4cc2088dcc4e9066d..9cbb44b6082cd76fcaf77bb4d7f888b896f4316a 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 2817a7f316a3e2fc10e0dc746c0afa205207cff9..b10408207ffa48eac4bdacde8d6aaca74b3d7e5d 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 b313cbc467cb6058283ad61ad79fd535716e93b8..03c4ed35fb746b239d2538591c4dd9655bd0f177 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 937e275e058d082cbaa20545d9f28bff2fad773b..0739167fdfdf69dd5b01d4792200d43861870724 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 122fcbff9bb371b07d692edb09a1c64ab7c24b72..551c315879de656c8f64bfeb595bc25c5e9d1ec7 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) ? "" : 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 e0a01b7eab4d61fd6b9ff409ef4f3a4927ec01ba..f1c2ddd4c1ffe552a2d9235e2723d223bfd94584 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 eb00cfd5094276cf32019396da2003227b992fda..c7fe46def45f028079105d2647e044ba18bbff5e 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()