1) Add rollback functionality to updatable cursors.
authorHiroshi Inoue <inoue@tpf.co.jp>
Mon, 1 Apr 2002 03:01:15 +0000 (03:01 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Mon, 1 Apr 2002 03:01:15 +0000 (03:01 +0000)
2) Implement some options for SQLGetDescField().
3) Handle *Inifinity* timestamp for SQL_C_CHAR type output.
4) Separate Unicode conversions from common implementations.
5) Improve internal parse_statement() function.

17 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/convert.h
src/interfaces/odbc/descriptor.h
src/interfaces/odbc/odbcapi30.c
src/interfaces/odbc/odbcapi30w.c
src/interfaces/odbc/parse.c
src/interfaces/odbc/pgapi30.c
src/interfaces/odbc/pgapifunc.h
src/interfaces/odbc/psqlodbc.h
src/interfaces/odbc/qresult.c
src/interfaces/odbc/qresult.h
src/interfaces/odbc/results.c
src/interfaces/odbc/statement.c

index 397d984ec6c6bea046295fc1f36e27abe445d8e1..e931b8b8d51766aaf5332b2c5d8501cfe2916071 100644 (file)
@@ -67,8 +67,8 @@ PGAPI_BindParameter(
    opts->parameters[ipar].paramType = fParamType;
    opts->parameters[ipar].CType = fCType;
    opts->parameters[ipar].SQLType = fSqlType;
-   opts->parameters[ipar].precision = cbColDef;
-   opts->parameters[ipar].scale = ibScale;
+   opts->parameters[ipar].column_size = cbColDef;
+   opts->parameters[ipar].decimal_digits = ibScale;
 
    /*
     * If rebinding a parameter that had data-at-exec stuff in it, then
@@ -276,10 +276,10 @@ PGAPI_DescribeParam(
        *pfSqlType = opts->parameters[ipar].SQLType;
 
    if (pcbColDef)
-       *pcbColDef = opts->parameters[ipar].precision;
+       *pcbColDef = opts->parameters[ipar].column_size;
 
    if (pibScale)
-       *pibScale = opts->parameters[ipar].scale;
+       *pibScale = opts->parameters[ipar].decimal_digits;
 
    if (pfNullable)
        *pfNullable = pgtype_nullable(stmt, opts->parameters[ipar].paramType);
@@ -458,8 +458,8 @@ reset_a_parameter_binding(APDFields *self, int ipar)
        self->parameters[ipar].EXEC_buffer = NULL;
    }
    self->parameters[ipar].SQLType = 0;
-   self->parameters[ipar].precision = 0;
-   self->parameters[ipar].scale = 0;
+   self->parameters[ipar].column_size = 0;
+   self->parameters[ipar].decimal_digits = 0;
    self->parameters[ipar].data_at_exec = FALSE;
    self->parameters[ipar].lobj_oid = 0;
 }
index 16d9f84b6e62817acef49146a8e4c543c22129cb..7eadea92e44c41a42b2bb4440ef7741b720c8258 100644 (file)
@@ -40,8 +40,8 @@ struct ParameterInfoClass_
    Int2        paramType;
    Int2        CType;
    Int2        SQLType;
-   UInt4       precision;
-   Int2        scale;
+   UInt4       column_size;
+   Int2        decimal_digits;
    Oid         lobj_oid;
    Int4       *EXEC_used;      /* amount of data OR the oid of the large
                                 * object */
index db237b3f952866b79caedca309648bc374bacde4..d6b622a16d736df112b019bad220bcd78d9e9bdd 100644 (file)
@@ -288,6 +288,7 @@ CC_Constructor()
        rv->pg_version_minor = 0;
        rv->ms_jet = 0;
        rv->unicode = 0;
+       rv->result_uncommitted = 0;
 #ifdef MULTIBYTE
        rv->client_encoding = NULL;
        rv->server_encoding = NULL;
@@ -1110,21 +1111,30 @@ CC_get_error(ConnectionClass *self, int *number, char **message)
 }
 
 
-void   CC_on_commit(ConnectionClass *conn, BOOL set_no_trans)
+void   CC_on_commit(ConnectionClass *conn)
 {
    if (CC_is_in_trans(conn))
    {
-       if (set_no_trans)
-           CC_set_no_trans(conn);
+#ifdef DRIVER_CURSOR_IMPLEMENT
+       if (conn->result_uncommitted)
+           ProcessRollback(conn, FALSE);
+#endif /* DRIVER_CURSOR_IMPLEMENT */
+       CC_set_no_trans(conn);
    }
+   conn->result_uncommitted = 0;
 }
 void   CC_on_abort(ConnectionClass *conn, BOOL set_no_trans)
 {
    if (CC_is_in_trans(conn))
    {
+#ifdef DRIVER_CURSOR_IMPLEMENT
+       if (conn->result_uncommitted)
+           ProcessRollback(conn, TRUE);
+#endif /* DRIVER_CURSOR_IMPLEMENT */
        if (set_no_trans)
            CC_set_no_trans(conn);
    }
+   conn->result_uncommitted = 0;
 }
 
 /*
@@ -1293,11 +1303,11 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
                        }
                    }
                    else if (strnicmp(cmdbuffer, "COMMIT", 6) == 0)
-                       CC_on_commit(self, TRUE);
+                       CC_on_commit(self);
                    else if (strnicmp(cmdbuffer, "ROLLBACK", 8) == 0)
                        CC_on_abort(self, TRUE);
                    else if (strnicmp(cmdbuffer, "END", 3) == 0)
-                       CC_on_commit(self, TRUE);
+                       CC_on_commit(self);
                    else if (strnicmp(cmdbuffer, "ABORT", 5) == 0)
                        CC_on_abort(self, TRUE);
 
index 67411edd67a9dc6d4fdadb3abfba3a38c9d8e367..5d01dacd2148f368f40fc60c734d14e6a2fb7da0 100644 (file)
@@ -272,6 +272,7 @@ struct ConnectionClass_
    Int2        pg_version_minor;
    char        ms_jet;
    char        unicode;
+   char        result_uncommitted;
 #ifdef MULTIBYTE
    char       *client_encoding;
    char       *server_encoding;
@@ -318,8 +319,9 @@ void        CC_lookup_pg_version(ConnectionClass *conn);
 void       CC_initialize_pg_version(ConnectionClass *conn);
 void       CC_log_error(const char *func, const char *desc, const ConnectionClass *self);
 int            CC_get_max_query_len(const ConnectionClass *self);
-void       CC_on_commit(ConnectionClass *conn, BOOL set_no_trans);
+void       CC_on_commit(ConnectionClass *conn);
 void       CC_on_abort(ConnectionClass *conn, BOOL set_no_trans);
+void       ProcessRollback(ConnectionClass *conn, BOOL undo);
 
 /* CC_send_query_options */
 #define    CLEAR_RESULT_ON_ABORT   1L
index c0a2706ef6116763577986c40d5d0dc3d02e8ebb..e4232137fef7dd292c2cdee3ec182b7f92abe69b 100644 (file)
@@ -265,6 +265,16 @@ stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, BOOL precision)
    int         i;
 
    precstr[0] = '\0';
+   if (st->infinity > 0)
+   {
+       strcpy(str, "Infinity");
+       return TRUE;
+   }
+   else if (st->infinity < 0)
+   {
+       strcpy(str, "-Infinity");
+       return TRUE;
+   }
    if (precision && st->fr)
    {
        sprintf(precstr, ".%09d", st->fr);
@@ -447,6 +457,27 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
        case PG_TYPE_DATETIME:
        case PG_TYPE_TIMESTAMP:
            st.fr = 0;
+           st.infinity = 0;
+           if (strnicmp(value, "infinity", 8) == 0)
+           {
+               st.infinity = 1;
+               st.m = 12;
+               st.d = 31;
+               st.y = 9999;
+               st.hh = 24;
+               st.mm = 0;
+               st.ss = 0;
+           }
+           if (strnicmp(value, "-infinity", 9) == 0)
+           {
+               st.infinity = -1;
+               st.m = 0;
+               st.d = 0;
+               st.y = 0;
+               st.hh = 0;
+               st.mm = 0;
+               st.ss = 0;
+           }
            if (strnicmp(value, "invalid", 7) != 0)
            {
                BOOL        bZone = (field_type != PG_TYPE_TIMESTAMP_NO_TMZONE && PG_VERSION_GE(SC_get_conn(stmt), 7.2));
@@ -2495,7 +2526,7 @@ convert_money(const char *s, char *sout, size_t soutmax)
  * It does not zero out SIMPLE_TIME in case it is desired to initialize it with a value
  */
 char
-parse_datetime(char *buf, SIMPLE_TIME *st)
+parse_datetime(const char *buf, SIMPLE_TIME *st)
 {
    int         y,
                m,
index 2d5f01859f04dd87f253549a7a4f77f371d28151..1ca0b1bb0c94e251271eaccf2b4554b0ffc4ebf2 100644 (file)
@@ -25,6 +25,7 @@
 
 typedef struct
 {
+   int     infinity;
    int         m;
    int         d;
    int         y;
@@ -42,7 +43,7 @@ int           copy_statement_with_parameters(StatementClass *stmt);
 int        convert_escape(const char *value, StatementClass *stmt,
            int *npos, int *stsize, const char **val_resume);
 BOOL       convert_money(const char *s, char *sout, size_t soutmax);
-char       parse_datetime(char *buf, SIMPLE_TIME *st);
+char       parse_datetime(const char *buf, SIMPLE_TIME *st);
 int            convert_linefeeds(const char *s, char *dst, size_t max, BOOL convlf, BOOL *changed);
 int            convert_special_chars(const char *si, char *dst, int used, BOOL convlf,int ccsc);
 
index 58036914ada6f94cf119f099a5b8e7a77eb072c6..5186810b21799e3b97c63e0a44b04b79cbb6d08c 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * $Id: descriptor.h,v 1.1 2002/03/28 08:08:02 inoue Exp $
+ * $Id: descriptor.h,v 1.2 2002/04/01 03:01:14 inoue Exp $
  *
  */
 
@@ -92,5 +92,8 @@ void  IRDFields_free(IRDFields *self);
 void   IPDFields_free(IPDFields *self);
 void   ARD_unbind_cols(ARDFields *self, BOOL freeall);
 void   APD_free_params(APDFields *self, char option);
+#if (ODBCVER >= 0x0300)
+void   Desc_set_error(SQLHDESC hdesc, int errornumber, const char * errormsg);
+#endif /* ODBCVER */
 
 #endif
index 0e9b63a304961eb27c78b9aadb522fa931a30040..8bcb1cab146bfd49929c38cb56a3b191e9d5edaf 100644 (file)
@@ -235,7 +235,8 @@ SQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
                SQLSMALLINT *StringLength)
 {
    mylog("[[SQLGetDiagField]] Handle=(%u,%x) Rec=%d Id=%d\n", HandleType, Handle, RecNumber, DiagIdentifier);
-   return SQL_ERROR;
+   return PGAPI_GetDiagField(HandleType, Handle, RecNumber, DiagIdentifier,
+               DiagInfo, BufferLength, StringLength);
 }
 
 /* SQLError -> SQLDiagRec */
index 0273f97b6b95376917d9ad1bbb7088c3e7f93604..ac0f1d9931fe361332929a3c06290a9e5b69ca7a 100644 (file)
@@ -89,10 +89,25 @@ SQLSetDescFieldW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber,
    mylog("[SQLSetDescFieldW]");
    if (BufferLength > 0)
    {
-       uval = ucs2_to_utf8(Value, BufferLength / 2, &vallen);
-       val_alloced = TRUE;
+       switch (FieldIdentifier)
+       {
+           case SQL_DESC_BASE_COLUMN_NAME:
+           case SQL_DESC_BASE_TABLE_NAME:
+           case SQL_DESC_CATALOG_NAME:
+           case SQL_DESC_LABEL:
+           case SQL_DESC_LITERAL_PREFIX:
+           case SQL_DESC_LITERAL_SUFFIX:
+           case SQL_DESC_LOCAL_TYPE_NAME:
+           case SQL_DESC_NAME:
+           case SQL_DESC_SCHEMA_NAME:
+           case SQL_DESC_TABLE_NAME:
+           case SQL_DESC_TYPE_NAME:
+               uval = ucs2_to_utf8(Value, BufferLength / 2, &vallen);
+               val_alloced = TRUE;
+           break;
+       }
    }
-   else
+   if (!val_alloced)
    {
        uval = Value;
        vallen = BufferLength;
@@ -109,11 +124,49 @@ SQLGetDescFieldW(SQLHDESC hdesc, SQLSMALLINT iRecord, SQLSMALLINT iField,
                    SQLINTEGER *pcbValue)
 {
    RETCODE ret;
-        char    *qstr = NULL, *mtxt = NULL;
+   BOOL    alloced = FALSE;
+   SQLINTEGER  blen, bMax, *pcbV;
+        char    *rgbV = NULL;
 
    mylog("[SQLGetDescFieldW]");
-   ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbValue,
-               cbValueMax, pcbValue);
+   switch (iField)
+   {
+       case SQL_DESC_BASE_COLUMN_NAME:
+       case SQL_DESC_BASE_TABLE_NAME:
+       case SQL_DESC_CATALOG_NAME:
+       case SQL_DESC_LABEL:
+       case SQL_DESC_LITERAL_PREFIX:
+       case SQL_DESC_LITERAL_SUFFIX:
+       case SQL_DESC_LOCAL_TYPE_NAME:
+       case SQL_DESC_NAME:
+       case SQL_DESC_SCHEMA_NAME:
+       case SQL_DESC_TABLE_NAME:
+       case SQL_DESC_TYPE_NAME:
+           alloced = TRUE;
+           bMax = cbValueMax * 3 / 2;
+           rgbV = malloc(bMax + 1);
+           pcbV = &blen;
+                   break;
+       default:
+           rgbV = rgbValue;
+           bMax = cbValueMax;
+           pcbV = pcbValue;
+           break;
+   }
+   ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbV, bMax, pcbV);
+   if (alloced)
+   {
+       blen = utf8_to_ucs2(rgbV, blen, (SQLWCHAR *) rgbValue, cbValueMax / 2);
+       if (SQL_SUCCESS == ret && blen * 2 > cbValueMax)
+       {
+           ret = SQL_SUCCESS_WITH_INFO;
+           Desc_set_error(hdesc, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.");
+       }
+       if (pcbValue)
+           *pcbValue = blen * 2;
+       free(rgbV);
+   }
+
    return ret;
 }
 
@@ -171,6 +224,9 @@ RETCODE SQL_API SQLColAttributeW(
     SQLINTEGER           *pfDesc)
 {
    RETCODE ret;
+   BOOL    alloced = FALSE;
+   SQLSMALLINT *rgbL, blen, bMax;
+        char    *rgbD = NULL;
 
    mylog("[SQLColAttributeW]");
    switch (fDescType)
@@ -187,11 +243,35 @@ RETCODE SQL_API SQLColAttributeW(
        case SQL_DESC_TABLE_NAME:
        case SQL_DESC_TYPE_NAME:
        case SQL_COLUMN_NAME:
+           alloced = TRUE;
+           bMax = cbDescMax * 3 / 2;
+           rgbD = malloc(bMax + 1);
+           rgbL = &blen;
                    break;
+       default:
+           rgbD = rgbDesc;
+           bMax = cbDescMax;
+           rgbL = pcbDesc;
+           break;
    }
 
-   ret = PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc,
-       cbDescMax, pcbDesc, pfDesc);
+   ret = PGAPI_ColAttributes(hstmt, icol, fDescType, rgbD,
+       bMax, rgbL, pfDesc);
+   if (alloced)
+   {
+       blen = utf8_to_ucs2(rgbD, blen, (SQLWCHAR *) rgbDesc, cbDescMax / 2);
+       if (SQL_SUCCESS == ret && blen * 2 > cbDescMax)
+       {
+           StatementClass  *stmt = (StatementClass *) hstmt;
+
+           ret = SQL_SUCCESS_WITH_INFO;
+           stmt->errornumber = STMT_TRUNCATED;
+           stmt->errormsg = "The buffer was too small for the rgbDesc.";
+       }
+       if (pcbDesc)
+           *pcbDesc = blen * 2;
+       free(rgbD);
+   }
 
    return ret;
 }
index 3549ff2ef7a0beae70b79b0c8fd9b28e70799c09..d86e62f85bb0af7cdc40320683638b4d998746ef 100644 (file)
@@ -304,7 +304,8 @@ parse_statement(StatementClass *stmt)
                in_on = FALSE,
                in_from = FALSE,
                in_where = FALSE,
-               in_table = FALSE;
+               in_table = FALSE,
+               out_table = TRUE;
    char        in_field = FALSE,
                in_expr = FALSE,
                in_func = FALSE,
@@ -610,12 +611,21 @@ parse_statement(StatementClass *stmt)
 
        if (in_from)
        {
-           if (!in_table)
+           if (token[0] == ';')
            {
-               if (!token[0])
+               in_from = FALSE;
+               break;
+           }
+           switch (token[0])
+           {
+               case '\0':
                    continue;
-               if (token[0] == ';')
-                   break;
+               case ',':
+                   out_table = TRUE; 
+                   continue;
+           }
+           if (out_table && !in_table) /* new table */
+           {
 
                if (!(stmt->ntab % TAB_INCR))
                {
@@ -660,22 +670,47 @@ parse_statement(StatementClass *stmt)
                mylog("got table = '%s'\n", ti[stmt->ntab]->name);
 
                if (delim == ',')
+               {
+                   out_table = TRUE;
                    mylog("more than 1 tables\n");
+               }
                else
+               {
+                   out_table = FALSE;
                    in_table = TRUE;
+               }
                stmt->ntab++;
                continue;
            }
 
-           if (token[0] == ';')
-               break;
-           if (stricmp(token, "as"))
+           if (!dquote && stricmp(token, "JOIN") == 0)
+           {
+               in_table = FALSE;
+               out_table = TRUE;
+               continue;
+           }
+           if (in_table && stricmp(token, "as"))
            {
+               if (!dquote)
+               {
+                   if (stricmp(token, "LEFT") == 0 ||
+                       stricmp(token, "RIGHT") == 0 ||
+                       stricmp(token, "OUTER") == 0 ||
+                       stricmp(token, "FULL") == 0 ||
+                       stricmp(token, "ON") == 0)
+                   {
+                       in_table = FALSE;
+                       continue;
+                   }
+               }
                strcpy(ti[stmt->ntab - 1]->alias, token);
                mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab - 1]->name, ti[stmt->ntab - 1]->alias);
                in_table = FALSE;
                if (delim == ',')
+               {
+                   out_table = TRUE;
                    mylog("more than 1 tables\n");
+               }
            }
        } /* in_from */
    }
index a67cc434fab5c1dca776dbbbed57540429ee4929..e73773931565aa784db8702d240c5d10c7c65536 100644 (file)
@@ -27,7 +27,7 @@
 #include "descriptor.h"
 #include "pgapifunc.h"
 
-static HSTMT statementHandleFromDescHandle(HSTMT, SQLINTEGER *descType); 
+static HSTMT statementHandleFromDescHandle(SQLHDESC, SQLINTEGER *descType); 
 /* SQLError -> SQLDiagRec */
 RETCODE        SQL_API
 PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
@@ -75,7 +75,7 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
        PTR DiagInfoPtr, SQLSMALLINT BufferLength,
        SQLSMALLINT *StringLengthPtr)
 {
-   RETCODE     ret = SQL_SUCCESS;
+   RETCODE     ret = SQL_ERROR;
    static const char *func = "PGAPI_GetDiagField";
 
    mylog("%s entering rec=%d", func, RecNumber);
@@ -122,6 +122,7 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
                case SQL_DIAG_NUMBER:
                case SQL_DIAG_RETURNCODE:
                case SQL_DIAG_SERVER_NAME:
+                   break;
                case SQL_DIAG_SQLSTATE:
                    break;
            }
@@ -154,7 +155,12 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
            *((SQLUINTEGER *) Value) = SQL_FALSE;
            break;
        case SQL_ATTR_CONNECTION_DEAD:
-           *((SQLUINTEGER *) Value) = SQL_CD_FALSE;
+           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;
            break;
        case SQL_ATTR_CONNECTION_TIMEOUT:
            *((SQLUINTEGER *) Value) = 0;
@@ -172,7 +178,7 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
    return ret;
 }
 
-static HSTMT
+static SQLHDESC
 descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType) 
 {
    switch (descType)
@@ -189,7 +195,7 @@ descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType)
    return (HSTMT) 0;
 }
 static HSTMT
-statementHandleFromDescHandle(HSTMT DescHandle, SQLINTEGER *descType) 
+statementHandleFromDescHandle(SQLHDESC DescHandle, SQLINTEGER *descType) 
 {
    SQLUINTEGER res = (SQLUINTEGER) DescHandle % 4;
    if (descType)
@@ -209,6 +215,19 @@ statementHandleFromDescHandle(HSTMT DescHandle, SQLINTEGER *descType)
    return (HSTMT) ((SQLUINTEGER) DescHandle - res);
 }
 
+void   Desc_set_error(SQLHDESC hdesc, int errornumber, const char *errormsg)
+{
+   SQLINTEGER  descType;
+   HSTMT   hstmt = statementHandleFromDescHandle(hdesc, &descType);
+   StatementClass  *stmt;
+
+   if (!hstmt)
+       return;
+   stmt = (StatementClass *) hstmt;
+   stmt->errornumber = errornumber;
+   stmt->errormsg = errormsg; /* should be static */
+}
+
 static  void column_bindings_set(ARDFields *opts, int cols, BOOL maxset)
 {
    int i;
@@ -568,7 +587,7 @@ IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
            apdopts->parameters[RecNumber - 1].paramType = (Int2) Value;
            break;
        case SQL_DESC_SCALE:
-           apdopts->parameters[RecNumber - 1].scale = (Int2) Value;
+           apdopts->parameters[RecNumber - 1].decimal_digits = (Int2) Value;
            break;
        case SQL_DESC_ALLOC_TYPE: /* read-only */ 
        case SQL_DESC_CASE_SENSITIVE: /* read-only */
@@ -599,7 +618,7 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
        SQLINTEGER *StringLength)
 {
    RETCODE     ret = SQL_SUCCESS;
-   SQLINTEGER  len, ival;
+   SQLINTEGER  len, ival, rettype = 0;
    PTR     ptr = NULL;
    const ARDFields *opts = SC_get_ARD(stmt);
 
@@ -610,9 +629,11 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
            ival = opts->rowset_size;
            break; 
        case SQL_DESC_ARRAY_STATUS_PTR:
+           rettype = SQL_IS_POINTER;
            ptr = opts->row_operation_ptr;
            break;
        case SQL_DESC_BIND_OFFSET_PTR:
+           rettype = SQL_IS_POINTER;
            ptr = opts->row_offset_ptr;
            break;
        case SQL_DESC_BIND_TYPE:
@@ -651,6 +672,7 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
            ival = opts->bindings[RecNumber - 1].returntype;
            break;
        case SQL_DESC_DATA_PTR:
+           rettype = SQL_IS_POINTER;
            if (!RecNumber)
                ptr = opts->bookmark->buffer;
            else
@@ -659,6 +681,7 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
            }
            break;
        case SQL_DESC_INDICATOR_PTR:
+           rettype = SQL_IS_POINTER;
            if (!RecNumber)
                ptr = opts->bookmark->used;
            else
@@ -667,6 +690,7 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
            }
            break;
        case SQL_DESC_OCTET_LENGTH_PTR:
+           rettype = SQL_IS_POINTER;
            if (!RecNumber)
                ptr = opts->bookmark->used;
            else
@@ -694,25 +718,13 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
        default:ret = SQL_ERROR;
            stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
    }
-   switch (BufferLength)
+   switch (rettype)
    {
        case 0:
        case SQL_IS_INTEGER:
            len = 4;
            *((SQLINTEGER *) Value) = ival;
            break;
-       case SQL_IS_UINTEGER:
-           len = 4;
-           *((UInt4 *) Value) = ival;
-           break;
-       case SQL_IS_SMALLINT:
-           len = 2;
-           *((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
-           break;
-       case SQL_IS_USMALLINT:
-           len = 2;
-           *((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
-           break;
        case SQL_IS_POINTER:
            len = 4;
            *((void **) Value) = ptr;
@@ -730,7 +742,7 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
        SQLINTEGER *StringLength)
 {
    RETCODE     ret = SQL_SUCCESS;
-   SQLINTEGER  ival = 0, len;
+   SQLINTEGER  ival = 0, len, rettype = 0;
    PTR     ptr = NULL;
    const APDFields *opts = SC_get_APD(stmt);
 
@@ -738,12 +750,15 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
    switch (FieldIdentifier)
    {
        case SQL_DESC_ARRAY_SIZE:
+           rettype = SQL_IS_POINTER;
            ival = opts->paramset_size;
            break; 
        case SQL_DESC_ARRAY_STATUS_PTR:
+           rettype = SQL_IS_POINTER;
            ptr = opts->param_operation_ptr;
            break;
        case SQL_DESC_BIND_OFFSET_PTR:
+           rettype = SQL_IS_POINTER;
            ptr = opts->param_offset_ptr;
            break;
        case SQL_DESC_BIND_TYPE:
@@ -783,15 +798,18 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
            ival = opts->parameters[RecNumber - 1].CType;
            break;
        case SQL_DESC_DATA_PTR:
+           rettype = SQL_IS_POINTER;
            ptr = opts->parameters[RecNumber - 1].buffer;
            break;
        case SQL_DESC_INDICATOR_PTR:
+           rettype = SQL_IS_POINTER;
            ptr = opts->parameters[RecNumber - 1].used;
            break;
        case SQL_DESC_OCTET_LENGTH:
            ival = opts->parameters[RecNumber - 1].buflen;
            break;
        case SQL_DESC_OCTET_LENGTH_PTR:
+           rettype = SQL_IS_POINTER;
            ptr = opts->parameters[RecNumber - 1].used;
            break;
        case SQL_DESC_COUNT:
@@ -800,33 +818,21 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
        case SQL_DESC_ALLOC_TYPE: /* read-only */
            ival = SQL_DESC_ALLOC_AUTO;
            break;
+       case SQL_DESC_PRECISION:
+       case SQL_DESC_SCALE:
        case SQL_DESC_DATETIME_INTERVAL_PRECISION:
        case SQL_DESC_LENGTH:
        case SQL_DESC_NUM_PREC_RADIX:
-       case SQL_DESC_PRECISION:
-       case SQL_DESC_SCALE:
        default:ret = SQL_ERROR;
            stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
    }
-   switch (BufferLength)
+   switch (rettype)
    {
        case 0:
        case SQL_IS_INTEGER:
            len = 4;
            *((Int4 *) Value) = ival;
            break;
-       case SQL_IS_UINTEGER:
-           len = 4;
-           *((UInt4 *) Value) = ival;
-           break;
-       case SQL_IS_SMALLINT:
-           len = 2;
-           *((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
-           break;
-       case SQL_IS_USMALLINT:
-           len = 2;
-           *((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
-           break;
        case SQL_IS_POINTER:
            len = 4;
            *((void **) Value) = ptr;
@@ -844,36 +850,33 @@ IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
        SQLINTEGER *StringLength)
 {
    RETCODE     ret = SQL_SUCCESS;
-   SQLINTEGER  ival = 0, len;
+   SQLINTEGER  ival = 0, len, rettype = 0;
    PTR     ptr = NULL;
+   BOOL        bCallColAtt = FALSE;
    const IRDFields *opts = SC_get_IRD(stmt);
 
    switch (FieldIdentifier)
    {
        case SQL_DESC_ARRAY_STATUS_PTR:
+           rettype = SQL_IS_POINTER;
            ptr = opts->rowStatusArray;
            break;
        case SQL_DESC_ROWS_PROCESSED_PTR:
+           rettype = SQL_IS_POINTER;
            ptr = opts->rowsFetched;
            break;
        case SQL_DESC_ALLOC_TYPE: /* read-only */
+           ival = SQL_DESC_ALLOC_AUTO;
+           break;
        case SQL_DESC_COUNT: /* read-only */
        case SQL_DESC_AUTO_UNIQUE_VALUE: /* read-only */
-       case SQL_DESC_BASE_COLUMN_NAME: /* read-only */
-       case SQL_DESC_BASE_TABLE_NAME: /* read-only */
        case SQL_DESC_CASE_SENSITIVE: /* read-only */
-       case SQL_DESC_CATALOG_NAME: /* read-only */
        case SQL_DESC_CONCISE_TYPE: /* read-only */
        case SQL_DESC_DATETIME_INTERVAL_CODE: /* read-only */
        case SQL_DESC_DATETIME_INTERVAL_PRECISION: /* read-only */
        case SQL_DESC_DISPLAY_SIZE: /* read-only */
        case SQL_DESC_FIXED_PREC_SCALE: /* read-only */
-       case SQL_DESC_LABEL: /* read-only */
        case SQL_DESC_LENGTH: /* read-only */
-       case SQL_DESC_LITERAL_PREFIX: /* read-only */
-       case SQL_DESC_LITERAL_SUFFIX: /* read-only */
-       case SQL_DESC_LOCAL_TYPE_NAME: /* read-only */
-       case SQL_DESC_NAME: /* read-only */
        case SQL_DESC_NULLABLE: /* read-only */
        case SQL_DESC_NUM_PREC_RADIX: /* read-only */
        case SQL_DESC_OCTET_LENGTH: /* read-only */
@@ -882,18 +885,40 @@ IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
        case SQL_DESC_ROWVER: /* read-only */
 #endif /* ODBCVER */
        case SQL_DESC_SCALE: /* read-only */
-       case SQL_DESC_SCHEMA_NAME: /* read-only */
        case SQL_DESC_SEARCHABLE: /* read-only */
-       case SQL_DESC_TABLE_NAME: /* read-only */
        case SQL_DESC_TYPE: /* read-only */
-       case SQL_DESC_TYPE_NAME: /* read-only */
        case SQL_DESC_UNNAMED: /* read-only */
        case SQL_DESC_UNSIGNED: /* read-only */
        case SQL_DESC_UPDATABLE: /* read-only */
+           bCallColAtt = TRUE;
+           break;
+       case SQL_DESC_BASE_COLUMN_NAME: /* read-only */
+       case SQL_DESC_BASE_TABLE_NAME: /* read-only */
+       case SQL_DESC_CATALOG_NAME: /* read-only */
+       case SQL_DESC_LABEL: /* read-only */
+       case SQL_DESC_LITERAL_PREFIX: /* read-only */
+       case SQL_DESC_LITERAL_SUFFIX: /* read-only */
+       case SQL_DESC_LOCAL_TYPE_NAME: /* read-only */
+       case SQL_DESC_NAME: /* read-only */
+       case SQL_DESC_SCHEMA_NAME: /* read-only */
+       case SQL_DESC_TABLE_NAME: /* read-only */
+       case SQL_DESC_TYPE_NAME: /* read-only */
+           rettype = SQL_NTS;
+           bCallColAtt = TRUE;
+           break; 
        default:ret = SQL_ERROR;
            stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
    }
-   switch (BufferLength)
+   if (bCallColAtt)
+   {
+       SQLSMALLINT pcbL;
+
+       ret = PGAPI_ColAttributes(stmt, RecNumber,
+           FieldIdentifier, Value, (SQLSMALLINT) BufferLength,
+               &pcbL, &ival);
+       len = pcbL;
+   } 
+   switch (rettype)
    {
        case 0:
        case SQL_IS_INTEGER:
@@ -904,14 +929,6 @@ IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
            len = 4;
            *((UInt4 *) Value) = ival;
            break;
-       case SQL_IS_SMALLINT:
-           len = 2;
-           *((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
-           break;
-       case SQL_IS_USMALLINT:
-           len = 2;
-           *((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
-           break;
        case SQL_IS_POINTER:
            len = 4;
            *((void **) Value) = ptr;
@@ -929,7 +946,7 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
        SQLINTEGER *StringLength)
 {
    RETCODE     ret = SQL_SUCCESS;
-   SQLINTEGER  ival = 0, len;
+   SQLINTEGER  ival = 0, len, rettype = 0;
    PTR     ptr = NULL;
    const IPDFields *ipdopts = SC_get_IPD(stmt);
    const APDFields *apdopts = SC_get_APD(stmt);
@@ -937,9 +954,11 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
    switch (FieldIdentifier)
    {
        case SQL_DESC_ARRAY_STATUS_PTR:
+           rettype = SQL_IS_POINTER;
            ptr = ipdopts->param_status_ptr;
            break;
        case SQL_DESC_ROWS_PROCESSED_PTR:
+           rettype = SQL_IS_POINTER;
            ptr = ipdopts->param_processed_ptr;
            break;
        case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */
@@ -981,8 +1000,24 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
        case SQL_DESC_PARAMETER_TYPE:
            ival = apdopts->parameters[RecNumber - 1].paramType;
            break;
+       case SQL_DESC_PRECISION:
+           switch (apdopts->parameters[RecNumber - 1].CType)
+           {
+               case SQL_C_TYPE_DATE:
+               case SQL_C_TYPE_TIME:
+               case SQL_C_TYPE_TIMESTAMP:
+               case SQL_DATETIME:
+                   ival = apdopts->parameters[RecNumber - 1].decimal_digits;
+                   break;
+           }
+           break;
        case SQL_DESC_SCALE:
-           ival = apdopts->parameters[RecNumber - 1].scale ;
+           switch (apdopts->parameters[RecNumber - 1].CType)
+           {
+               case SQL_C_NUMERIC:
+                   ival = apdopts->parameters[RecNumber - 1].decimal_digits;
+                   break;
+           }
            break;
        case SQL_DESC_ALLOC_TYPE: /* read-only */
            ival = SQL_DESC_ALLOC_AUTO;
@@ -996,7 +1031,6 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
        case SQL_DESC_NULLABLE: /* read-only */
        case SQL_DESC_NUM_PREC_RADIX:
        case SQL_DESC_OCTET_LENGTH:
-       case SQL_DESC_PRECISION:
 #if (ODBCVER >= 0x0350)
        case SQL_DESC_ROWVER: /* read-only */
 #endif /* ODBCVER */
@@ -1005,25 +1039,13 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
        default:ret = SQL_ERROR;
            stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER; 
    }
-   switch (BufferLength)
+   switch (rettype)
    {
        case 0:
        case SQL_IS_INTEGER:
            len = 4;
            *((Int4 *) Value) = ival;
            break;
-       case SQL_IS_UINTEGER:
-           len = 4;
-           *((UInt4 *) Value) = ival;
-           break;
-       case SQL_IS_SMALLINT:
-           len = 2;
-           *((SQLSMALLINT *) Value) = (SQLSMALLINT) ival;
-           break;
-       case SQL_IS_USMALLINT:
-           len = 2;
-           *((SQLUSMALLINT *) Value) = (SQLUSMALLINT) ival;
-           break;
        case SQL_IS_POINTER:
            len = 4;
            *((void **)Value) = ptr;
index a906a311debce5020c3f0b5117e3cd1942a6596c..f4c740bca84c60748434c3077776de63543c36e6 100644 (file)
@@ -265,6 +265,10 @@ RETCODE SQL_API PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
        SQLSMALLINT RecNumber, SQLCHAR *Sqlstate,
        SQLINTEGER *NativeError, SQLCHAR *MessageText,
        SQLSMALLINT BufferLength, SQLSMALLINT *TextLength);
+RETCODE SQL_API PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
+       SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier,
+       PTR DiagInfoPtr, SQLSMALLINT BufferLength,
+       SQLSMALLINT *StringLengthPtr);
 RETCODE SQL_API PGAPI_GetConnectAttr(HDBC ConnectionHandle,
            SQLINTEGER Attribute, PTR Value,
            SQLINTEGER BufferLength, SQLINTEGER *StringLength);
index a0d4be134b1435d411d2564690f8c316f6d9d1a6..839c6e4876cde49792d2592304e12c8a4e5c0ef5 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * $Id: psqlodbc.h,v 1.61 2002/03/28 08:08:06 inoue Exp $
+ * $Id: psqlodbc.h,v 1.62 2002/04/01 03:01:15 inoue Exp $
  *
  */
 
index 923448abeba844a9dea9140fff1817f69c559dcc..2817a7f316a3e2fc10e0dc746c0afa205207cff9 100644 (file)
@@ -123,6 +123,7 @@ QR_Constructor()
        rv->rowset_size = 1;
        rv->haskeyset = 0;
        rv->keyset = NULL;
+       rv->rb_alloc = 0;
        rv->rb_count = 0;
        rv->rollback = NULL;
    }
@@ -233,6 +234,7 @@ QR_free_memory(QResultClass *self)
    if (self->rollback)
    {
        free(self->rollback);
+       self->rb_alloc = 0;
        self->rb_count = 0;
        self->rollback = NULL;
    }
index a7291c43a6f325a6f0e9440fd91b48e63b7236ec..1bf1ce93b742f24d03f4b92fa6c791ee63948bf7 100644 (file)
@@ -74,7 +74,8 @@ struct QResultClass_
    char        aborted;        /* was aborted? */
    char        haskeyset;      /* this result contains keyset ? */
    KeySet      *keyset;
-   UInt4       rb_count;   /* count of rollback info */    
+   UInt2       rb_alloc;   /* count of allocated rollback info */  
+   UInt2       rb_count;   /* count of rollback info */    
    Rollback    *rollback;  
 };
 
index 6d20bbaad593b483f523ae133f7fc75019f880dd..517d5a234d1c99b8b9c91eadbd96e7087fdcb77e 100644 (file)
@@ -491,7 +491,7 @@ PGAPI_ColAttributes(
            return SQL_SUCCESS;
        }
 
-       if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[col_idx])
+       if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi)
        {
            if (col_idx >= cols)
            {
@@ -500,9 +500,12 @@ PGAPI_ColAttributes(
                SC_log_error(func, "", stmt);
                return SQL_ERROR;
            }
-           field_type = irdflds->fi[col_idx]->type;
-           if (field_type > 0)
-               parse_ok = TRUE;
+           if (irdflds->fi[col_idx])
+           {
+               field_type = irdflds->fi[col_idx]->type;
+               if (field_type > 0)
+                   parse_ok = TRUE;
+           }
        }
    }
 
@@ -756,14 +759,6 @@ inolog("COLUMN_TYPE=%d\n", value);
 
        if (rgbDesc)
        {
-#ifdef UNICODE_SUPPORT
-           if (conn->unicode)
-           {
-               len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbDesc, cbDescMax / 2);
-               len *= 2;
-           }
-           else
-#endif /* UNICODE_SUPPORT */
            strncpy_null((char *) rgbDesc, p, (size_t) cbDescMax);
 
            if (len >= cbDescMax)
@@ -1343,8 +1338,6 @@ PGAPI_ExtendedFetch(
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
            else
                *(rgfRowStatus + i) = SQL_ROW_SUCCESS;
-if (rgfRowStatus[i] != SQL_ROW_SUCCESS)
-inolog("rgfRowStatus[%d]=%d\n", i, rgfRowStatus[i]);
        }
    }
 
@@ -1426,6 +1419,121 @@ static void KeySetSet(const TupleField *tuple, int num_fields, KeySet *keyset)
    sscanf(tuple[num_fields - 1].value, "%u", &keyset->oid);
 }
 
+static void AddRollback(ConnectionClass *conn, QResultClass *res, int index, const KeySet *keyset)
+{
+   Rollback *rollback;
+
+   if (!res->rollback)
+   {
+       res->rb_count = 0;
+       res->rb_alloc = 10;
+       rollback = res->rollback = malloc(sizeof(Rollback) * res->rb_alloc);
+   }
+   else
+   {
+       if (res->rb_count >= res->rb_alloc)
+       {
+           res->rb_alloc *= 2; 
+           if (rollback = realloc(res->rollback, sizeof(Rollback) * res->rb_alloc), !rollback)
+           {
+               res->rb_alloc = res->rb_count = 0;
+               return;
+           }
+           res->rollback = rollback; 
+       }
+       rollback = res->rollback + res->rb_count;
+   }
+   rollback->index = index;
+   if (keyset)
+   {
+       rollback->blocknum = keyset[index].blocknum;
+       rollback->offset = keyset[index].offset;
+   }
+   else
+   {
+       rollback->offset = 0;
+       rollback->blocknum = 0;
+   }
+
+   conn->result_uncommitted = 1;
+   res->rb_count++;    
+}
+
+static void DiscardRollback(QResultClass *res)
+{
+   int i, index;
+   UWORD   status;
+   Rollback *rollback;
+   KeySet  *keyset;
+
+   if (0 == res->rb_count || NULL == res->rollback)
+       return;
+   rollback = res->rollback;
+   keyset = res->keyset;
+   for (i = 0; i < res->rb_count; i++)
+   {
+       index = rollback[i].index;
+       status = keyset[index].status;
+       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);
+   }
+   free(rollback);
+   res->rollback = NULL;
+   res->rb_count = res->rb_alloc = 0;
+}
+
+static void UndoRollback(QResultClass *res)
+{
+   int i, index;
+   UWORD   status;
+   Rollback *rollback;
+   KeySet  *keyset;
+
+   if (0 == res->rb_count || NULL == res->rollback)
+       return;
+   rollback = res->rollback;
+   keyset = res->keyset;
+   for (i = res->rb_count - 1; i >= 0; i--)
+   {
+       index = rollback[i].index;
+       status = keyset[index].status;
+       if ((status & CURS_SELF_ADDING) != 0)
+       {
+           if (index < res->fcount)
+               res->fcount = index;
+       }
+       else
+       {
+           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);
+   res->rollback = NULL;
+   res->rb_count = res->rb_alloc = 0;
+}
+
+void   ProcessRollback(ConnectionClass *conn, BOOL undo) 
+{
+   int i;
+   StatementClass  *stmt;
+   QResultClass    *res;
+
+   for (i = 0; i < conn->num_stmts; i++)
+   {
+       if (stmt = conn->stmts[i], !stmt)
+           continue;
+       for (res = SC_get_Result(stmt); res; res = res->next)
+       {
+           if (undo)
+               UndoRollback(res);
+           else
+               DiscardRollback(res);
+       }
+   }
+}
+
 #define    LATEST_TUPLE_LOAD   1L
 #define    USE_INSERTED_TID    (1L << 1)
 static QResultClass *
@@ -1534,7 +1642,8 @@ 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].oid = 0;
+               res->keyset[global_ridx].blocknum = 0;
+               res->keyset[global_ridx].offset = 0;
                res->keyset[global_ridx].status |= SQL_ROW_DELETED;
            }
        }
@@ -1670,6 +1779,7 @@ SC_pos_update(StatementClass *stmt,
                num_cols,
                upd_cols;
    QResultClass *res;
+   ConnectionClass *conn = SC_get_conn(stmt);
    ARDFields   *opts = SC_get_ARD(stmt);
    IRDFields   *irdflds = SC_get_IRD(stmt);
    BindInfoClass *bindings = opts->bindings;
@@ -1735,7 +1845,7 @@ SC_pos_update(StatementClass *stmt,
        sprintf(updstr, "%s where ctid = '(%u, %u)' and oid = %u", updstr,
                blocknum, pgoffset, oid);
        mylog("updstr=%s\n", updstr);
-       if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS)
+       if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
            return SQL_ERROR;
        qstmt = (StatementClass *) hstmt;
        apdopts = SC_get_APD(qstmt);
@@ -1788,8 +1898,11 @@ SC_pos_update(StatementClass *stmt,
    }
    if (SQL_SUCCESS == ret && res->keyset)
    {
-       if (CC_is_in_trans(SC_get_conn(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
            res->keyset[global_ridx].status |= (SQL_ROW_UPDATED  | CURS_SELF_UPDATED);
    }
@@ -1815,12 +1928,12 @@ SC_pos_delete(StatementClass *stmt,
 {
    UWORD       offset;
    QResultClass *res, *qres;
+   ConnectionClass *conn = SC_get_conn(stmt);
    ARDFields   *opts = SC_get_ARD(stmt);
    IRDFields   *irdflds = SC_get_IRD(stmt);
    BindInfoClass *bindings = opts->bindings;
    char        dltstr[4096];
    RETCODE     ret;
-   /*const char       *oidval;*/
    UInt4       oid, blocknum;
 
    mylog("POS DELETE ti=%x\n", stmt->ti);
@@ -1844,7 +1957,7 @@ SC_pos_delete(StatementClass *stmt,
            stmt->ti[0]->name, blocknum, offset, oid);
 
    mylog("dltstr=%s\n", dltstr);
-   qres = CC_send_query(SC_get_conn(stmt), dltstr, NULL, CLEAR_RESULT_ON_ABORT);
+   qres = CC_send_query(conn, dltstr, NULL, CLEAR_RESULT_ON_ABORT);
    ret = SQL_SUCCESS;
    if (qres && QR_command_successful(qres))
    {
@@ -1881,8 +1994,11 @@ SC_pos_delete(StatementClass *stmt,
        QR_Destructor(qres);
    if (SQL_SUCCESS == ret && res->keyset)
    {
-       if (CC_is_in_trans(SC_get_conn(stmt)))
+       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
            res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED);
    }
@@ -1988,7 +2104,7 @@ SC_pos_add(StatementClass *stmt,
    num_cols = irdflds->nfields;
    conn = SC_get_conn(stmt);
    sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name);
-   if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS)
+   if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
        return SQL_ERROR;
    if (opts->row_offset_ptr)
        offset = *opts->row_offset_ptr;
@@ -2068,10 +2184,15 @@ SC_pos_add(StatementClass *stmt,
    PGAPI_FreeStmt(hstmt, SQL_DROP);
    if (SQL_SUCCESS == ret && res->keyset)
    {
+       int global_ridx = res->fcount - 1;
        if (CC_is_in_trans(conn))
-           res->keyset[res->fcount - 1].status |= (SQL_ROW_ADDED | CURS_SELF_ADDING);
+       {
+
+           AddRollback(conn, res, global_ridx, NULL);
+           res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDING);
+       }
        else
-           res->keyset[res->fcount - 1].status |= (SQL_ROW_ADDED | CURS_SELF_ADDED);
+           res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDED);
    }
 #if (ODBCVER >= 0x0300)
    if (irdflds->rowStatusArray)
index f48a1724219da2edac54a16ebe8d69618966e154..6bdac480872929beb87e9c2185d4b06c43415187 100644 (file)
@@ -503,8 +503,8 @@ SC_recycle_statement(StatementClass *self)
        int i;
 
        for (i = 0; i < self->ntab; i++)
-           if (self->ti)
-               free(self->ti);
+           if (self->ti[i])
+               free(self->ti[i]);
        self->ti = NULL;
        self->ntab = 0;
    }