]> granicus.if.org Git - postgresql/commitdiff
The version is now 7.01.0010.
authorHiroshi Inoue <inoue@tpf.co.jp>
Mon, 18 Feb 2002 03:16:11 +0000 (03:16 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Mon, 18 Feb 2002 03:16:11 +0000 (03:16 +0000)
1) Handle parameter array.
2) Allow re-use of the connection handle after SQLDisconnect.
3) Reject NULL if no indicator specified.
4) Improve the handling of '_' in table name.
5) Unify internal begin/commit/abort operations.
6) Change SQLTables() to return null not "" for the
   table_owner.
7) Fix a bug about parameter handling reported by Benoit Menendez.
8) Add cast in handling ODBC date/time escape sequences.
9) Fix a bug about cache_size handing in declare/fetch mode.

[ODBC3.0 related]
10) Improve the handling of descriptor handles(ODBC3.0).
11) Improve the type handling of some types for ODBC3.0.

[Thanks to Marcelo Aceto for his useful patches]
12) Allow nested ODBC escape.
13) Allow changing autocommit on/off inside the transaction
    block.
14) Improve the handling of ODBC scalar functions.

21 files changed:
src/interfaces/odbc/bind.c
src/interfaces/odbc/connection.c
src/interfaces/odbc/connection.h
src/interfaces/odbc/convert.c
src/interfaces/odbc/convert.h
src/interfaces/odbc/environ.c
src/interfaces/odbc/execute.c
src/interfaces/odbc/info.c
src/interfaces/odbc/odbcapi.c
src/interfaces/odbc/odbcapi30.c
src/interfaces/odbc/options.c
src/interfaces/odbc/parse.c
src/interfaces/odbc/pgapifunc.h
src/interfaces/odbc/pgtypes.c
src/interfaces/odbc/pgtypes.h
src/interfaces/odbc/psqlodbc.h
src/interfaces/odbc/psqlodbc.rc
src/interfaces/odbc/qresult.c
src/interfaces/odbc/results.c
src/interfaces/odbc/statement.c
src/interfaces/odbc/statement.h

index e9f5cc34827a1f84b1bedf325cd8fd9ce684ef1e..f3fb35373578d2af34e4d6c5d43000cf56a00fd4 100644 (file)
@@ -134,6 +134,8 @@ PGAPI_BindParameter(
                stmt->parameters[ipar].EXEC_buffer = NULL;
        }
 
+       if (pcbValue && stmt->options.param_offset_ptr)
+               pcbValue += (*stmt->options.param_offset_ptr >> 2);
        /* Data at exec macro only valid for C char/binary data */
        if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC ||
                                         *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET))
index e057d7b73f9cac0606b4458812f2040827339ea3..66ef5e9ae4f033a985d56b9272088f8a4cec02c1 100644 (file)
@@ -309,12 +309,6 @@ CC_Destructor(ConnectionClass *self)
 
        mylog("after CC_Cleanup\n");
 
-#ifdef MULTIBYTE
-       if (self->client_encoding)
-               free(self->client_encoding);
-       if (self->server_encoding)
-               free(self->server_encoding);
-#endif   /* MULTIBYTE */
        /* Free up statement holders */
        if (self->stmts)
        {
@@ -323,23 +317,6 @@ CC_Destructor(ConnectionClass *self)
        }
        mylog("after free statement holders\n");
 
-       /* Free cached table info */
-       if (self->col_info)
-       {
-               int                     i;
-
-               for (i = 0; i < self->ntables; i++)
-               {
-                       if (self->col_info[i]->result)          /* Free the SQLColumns
-                                                                                                * result structure */
-                               QR_Destructor(self->col_info[i]->result);
-
-                       free(self->col_info[i]);
-               }
-               free(self->col_info);
-       }
-
-
        free(self);
 
        mylog("exit CC_Destructor\n");
@@ -380,6 +357,59 @@ CC_clear_error(ConnectionClass *self)
 }
 
 
+/*
+ *     Used to begin a transaction.
+ */
+char
+CC_begin(ConnectionClass *self)
+{
+       char    ret = TRUE;
+       if (!CC_is_in_trans(self))
+       {
+               QResultClass *res = CC_send_query(self, "BEGIN", NULL);
+               mylog("CC_begin:  sending BEGIN!\n");
+
+               if (res != NULL)
+               {
+                       ret = (!QR_aborted(res) && QR_command_successful(res));
+                       QR_Destructor(res);
+                       if (ret)
+                               CC_set_in_trans(self);
+               }
+               else
+                       ret = FALSE;
+       }
+
+       return ret;
+}
+
+/*
+ *     Used to commit a transaction.
+ *     We are almost always in the middle of a transaction.
+ */
+char
+CC_commit(ConnectionClass *self)
+{
+       char    ret = FALSE;
+       if (CC_is_in_trans(self))
+       {
+               QResultClass *res = CC_send_query(self, "COMMIT", NULL);
+               mylog("CC_commit:  sending COMMIT!\n");
+
+               CC_set_no_trans(self);
+
+               if (res != NULL)
+               {
+                       ret = QR_command_successful(res);
+                       QR_Destructor(res);
+               }
+               else
+                       ret = FALSE;
+       }
+
+       return ret;
+}
+
 /*
  *     Used to cancel a transaction.
  *     We are almost always in the middle of a transaction.
@@ -387,22 +417,17 @@ CC_clear_error(ConnectionClass *self)
 char
 CC_abort(ConnectionClass *self)
 {
-       QResultClass *res;
-
        if (CC_is_in_trans(self))
        {
-               res = NULL;
-
+               QResultClass *res = CC_send_query(self, "ROLLBACK", NULL);
                mylog("CC_abort:  sending ABORT!\n");
 
-               res = CC_send_query(self, "ABORT", NULL);
                CC_set_no_trans(self);
 
                if (res != NULL)
                        QR_Destructor(res);
                else
                        return FALSE;
-
        }
 
        return TRUE;
@@ -461,6 +486,37 @@ CC_cleanup(ConnectionClass *self)
        }
 #endif
 
+       self->status = CONN_NOT_CONNECTED;
+       self->transact_status = CONN_IN_AUTOCOMMIT;
+       memset(&self->connInfo, 0, sizeof(ConnInfo));
+#ifdef DRIVER_CURSOR_IMPLEMENT
+       self->connInfo.updatable_cursors = 1;
+#endif   /* DRIVER_CURSOR_IMPLEMENT */
+       memcpy(&(self->connInfo.drivers), &globals, sizeof(globals));
+#ifdef MULTIBYTE
+       if (self->client_encoding)
+               free(self->client_encoding);
+       self->client_encoding = NULL;
+       if (self->server_encoding)
+               free(self->server_encoding);
+       self->server_encoding = NULL;
+#endif   /* MULTIBYTE */
+       /* Free cached table info */
+       if (self->col_info)
+       {
+               int                     i;
+
+               for (i = 0; i < self->ntables; i++)
+               {
+                       if (self->col_info[i]->result)  /* Free the SQLColumns result structure */
+                               QR_Destructor(self->col_info[i]->result);
+
+                       free(self->col_info[i]);
+               }
+               free(self->col_info);
+               self->col_info = NULL;
+       }
+       self->ntables = 0;
        mylog("exit CC_Cleanup\n");
        return TRUE;
 }
@@ -516,7 +572,6 @@ md5_auth_send(ConnectionClass *self, const char *salt)
        ConnInfo   *ci = &(self->connInfo);
        SocketClass     *sock = self->sock;
 
-mylog("MD5 user=%s password=%s\n", ci->username, ci->password); 
        if (!(pwd1 = malloc(MD5_PASSWD_LEN + 1)))
                return 1;
        if (!EncryptMD5(ci->password, ci->username, strlen(ci->username), pwd1))
@@ -601,9 +656,10 @@ CC_connect(ConnectionClass *self, char do_password)
                         ci->drivers.conn_settings,
                         encoding ? encoding : "");
 #else
-               qlog("                extra_systable_prefixes='%s', conn_settings='%s'\n",
+               qlog("                extra_systable_prefixes='%s', conn_settings='%s', protocol='%s'\n",
                         ci->drivers.extra_systable_prefixes,
-                        ci->drivers.conn_settings);
+                        ci->drivers.conn_settings,
+                        ci->protocol);
 #endif
 
                if (self->status != CONN_NOT_CONNECTED)
@@ -1037,7 +1093,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
                                ReadyToReturn,
                                tuples_return = FALSE,
                                query_completed = FALSE,
-                               before_64 = PG_VERSION_LT(self, 6.4);
+                               before_64 = PG_VERSION_LT(self, 6.4),
+                               used_passed_result_object = FALSE;
 
        /* ERROR_MSG_LENGTH is suffcient */
        static char msgbuffer[ERROR_MSG_LENGTH + 1];
@@ -1289,6 +1346,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
                                else
                                {                               /* next fetch, so reuse an existing result */
 
+                                       used_passed_result_object = TRUE;
                                        /*
                                         * called from QR_next_tuple and must return
                                         * immediately.
@@ -1373,9 +1431,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
                QR_Destructor(res);
        if (result_in && retres != result_in)
        {
-               if (qi && qi->result_in)
-                       ;
-               else
+               if (!used_passed_result_object)
                        QR_Destructor(result_in);
        }
        return retres;
index a80c31b9218c042c000646fd0ac62155f94f3d23..0ef91a139f08fbcb22ee2c9f27a461bb9f60c5d9 100644 (file)
@@ -292,6 +292,8 @@ ConnectionClass *CC_Constructor(void);
 char           CC_Destructor(ConnectionClass *self);
 int                    CC_cursor_count(ConnectionClass *self);
 char           CC_cleanup(ConnectionClass *self);
+char           CC_begin(ConnectionClass *self);
+char           CC_commit(ConnectionClass *self);
 char           CC_abort(ConnectionClass *self);
 int                    CC_set_translation(ConnectionClass *self);
 char           CC_connect(ConnectionClass *self, char do_password);
index 0b609a07dbecc139852772db2c1f0603efb58908..1f3c89981ee4c4e9edb9b517e37841e04489f4ac 100644 (file)
  *     - thomas 2000-04-03
  */
 char      *mapFuncs[][2] = {
-/*     { "ASCII",               "ascii"          }, */
-       {"CHAR", "chr"},
-       {"CONCAT", "textcat"},
-/*     { "DIFFERENCE",  "difference" }, */
-/*     { "INSERT",              "insert"         }, */
-       {"LCASE", "lower"},
-       {"LEFT", "ltrunc"},
-       {"LOCATE", "strpos"},
-       {"LENGTH", "char_length"},
-/*     { "LTRIM",               "ltrim"          }, */
-       {"RIGHT", "rtrunc"},
-/*     { "REPEAT",              "repeat"         }, */
-/*     { "REPLACE",     "replace"        }, */
-/*     { "RTRIM",               "rtrim"          }, */
-/*     { "SOUNDEX",     "soundex"        }, */
-       {"SUBSTRING", "substr"},
-       {"UCASE", "upper"},
-
-/*     { "ABS",                 "abs"            }, */
-/*     { "ACOS",                "acos"           }, */
-/*     { "ASIN",                "asin"           }, */
-/*     { "ATAN",                "atan"           }, */
-/*     { "ATAN2",               "atan2"          }, */
-       {"CEILING", "ceil"},
-/*     { "COS",                 "cos"            }, */
-/*     { "COT",                 "cot"            }, */
-/*     { "DEGREES",     "degrees"        }, */
-/*     { "EXP",                 "exp"            }, */
-/*     { "FLOOR",               "floor"          }, */
-       {"LOG", "ln"},
-       {"LOG10", "log"},
-/*     { "MOD",                 "mod"            }, */
-/*     { "PI",                  "pi"             }, */
-       {"POWER", "pow"},
-/*     { "RADIANS",     "radians"        }, */
-       {"RAND", "random"},
-/*     { "ROUND",               "round"          }, */
-/*     { "SIGN",                "sign"           }, */
-/*     { "SIN",                 "sin"            }, */
-/*     { "SQRT",                "sqrt"           }, */
-/*     { "TAN",                 "tan"            }, */
-       {"TRUNCATE", "trunc"},
-
-       {"CURRENT_DATE", "curdate"},
-       {"CURRENT_TIME", "curtime"},
-       {"CURRENT_TIMESTAMP", "odbc_timestamp"},
-       {"CURRENT_USER", "odbc_current_user"},
-       {"SESSION_USER", "odbc_session_user"},
-/*     { "CURDATE",     "curdate"        }, */
-/*     { "CURTIME",     "curtime"        }, */
-/*     { "DAYNAME",     "dayname"        }, */
-/*     { "DAYOFMONTH",  "dayofmonth" }, */
-/*     { "DAYOFWEEK",   "dayofweek"  }, */
-/*     { "DAYOFYEAR",   "dayofyear"  }, */
-/*     { "HOUR",                "hour"           }, */
-/*     { "MINUTE",              "minute"         }, */
-/*     { "MONTH",               "month"          }, */
-/*     { "MONTHNAME",   "monthname"  }, */
-/*     { "NOW",                 "now"            }, */
-/*     { "QUARTER",     "quarter"        }, */
-/*     { "SECOND",              "second"         }, */
-/*     { "WEEK",                "week"           }, */
-/*     { "YEAR",                "year"           }, */
+/*     { "ASCII",               "ascii"          }, built_in */
+       {"CHAR", "chr($*)" },
+       {"CONCAT", "textcat($*)" },
+/*     { "DIFFERENCE", "difference" }, how to ? */
+       {"INSERT", "substring($1 from 1 for $2 - 1) || $4 || substring($1 from $2 + $3)" },
+       {"LCASE", "lower($*)" },
+       {"LEFT", "ltrunc($*)" },
+       {"%2LOCATE", "strpos($2,  $1)" },       /* 2 parameters */
+       {"%3LOCATE", "strpos(substring($2 from $3), $1) + $3 - 1" },    /* 3 parameters */
+       {"LENGTH", "char_length($*)"},
+/*     { "LTRIM",               "ltrim"          }, built_in */
+       {"RIGHT", "rtrunc($*)" },
+       {"SPACE", "repeat('' '', $1)" },
+/*     { "REPEAT",              "repeat"         }, built_in */
+/*     { "REPLACE", "replace" }, ??? */
+/*     { "RTRIM",               "rtrim"          }, built_in */
+/*     { "SOUNDEX", "soundex" }, how to ? */
+       {"SUBSTRING", "substr($*)" },
+       {"UCASE", "upper($*)" },
+
+/*     { "ABS",                 "abs"            }, built_in */
+/*     { "ACOS",                "acos"           }, built_in */
+/*     { "ASIN",                "asin"           }, built_in */
+/*     { "ATAN",                "atan"           }, built_in */
+/*     { "ATAN2",               "atan2"          }, bui;t_in */
+       {"CEILING", "ceil($*)" },
+/*     { "COS",                 "cos"            }, built_in */
+/*     { "COT",                 "cot"            }, built_in */
+/*     { "DEGREES",             "degrees"        }, built_in */
+/*     { "EXP",                 "exp"            }, built_in */
+/*     { "FLOOR",               "floor"          }, built_in */
+       {"LOG", "ln($*)" },
+       {"LOG10", "log($*)" },
+/*     { "MOD",                 "mod"            }, built_in */
+/*     { "PI",                  "pi"             }, built_in */
+       {"POWER", "pow($*)" },
+/*     { "RADIANS",             "radians"        }, built_in */
+       {"%0RAND", "random()" },        /* 0 parameters */
+       {"%1RAND", "(setseed($1) * .0 + random())" },   /* 1 parameters */
+/*     { "ROUND",               "round"          }, built_in */
+/*     { "SIGN",                "sign"           }, built_in */
+/*     { "SIN",                 "sin"            }, built_in */
+/*     { "SQRT",                "sqrt"           }, built_in */
+/*     { "TAN",                 "tan"            }, built_in */
+       {"TRUNCATE", "trunc($*)" },
+
+       {"CURRENT_DATE", "current_date" },
+       {"CURRENT_TIME", "current_time" },
+       {"CURRENT_TIMESTAMP", "current_timestamp" },
+       {"CURRENT_USER", "cast(current_user as text)" },
+       {"SESSION_USER", "cast(session_user as text)" },
+       {"CURDATE",      "current_date" },
+       {"CURTIME",      "current_time" },
+       {"DAYNAME",      "to_char($1, 'Day')" },
+       {"DAYOFMONTH",  "cast(extract(day from $1) as integer)" },
+       {"DAYOFWEEK",    "(cast(extract(dow from $1) as integer) + 1)" },
+       {"DAYOFYEAR",    "cast(extract(doy from $1) as integer)" }, 
+       {"HOUR",         "cast(extract(hour from $1) as integer)" },
+       {"MINUTE",      "cast(extract(minute from $1) as integer)" },
+       {"MONTH",       "cast(extract(month from $1) as integer)" },
+       {"MONTHNAME",    " to_char($1, 'Month')" },
+/*     { "NOW",                 "now"            }, built_in */
+       {"QUARTER",      "cast(extract(quarter from $1) as integer)" },
+       {"SECOND",      "cast(extract(second from $1) as integer)" },
+       {"WEEK",        "cast(extract(week from $1) as integer)" },
+       {"YEAR",        "cast(extract(year from $1) as integer)" },
 
 /*     { "DATABASE",    "database"   }, */
-       {"IFNULL", "coalesce"},
-       {"USER", "odbc_user"},
+       {"IFNULL", "coalesce($*)" },
+       {"USER", "cast(current_user as text)" },
        {0, 0}
 };
 
-static char *mapFunction(const char *func);
+static const char *mapFunction(const char *func, int param_count);
 static unsigned int conv_from_octal(const unsigned char *s);
 static unsigned int conv_from_hex(const unsigned char *s);
 static char *conv_to_octal(unsigned char val);
@@ -307,9 +310,10 @@ int
 copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col)
 {
        BindInfoClass *bic = &(stmt->bindings[col]);
+       UInt4   offset = stmt->options.row_offset_ptr ? *stmt->options.row_offset_ptr : 0;
 
-       return copy_and_convert_field(stmt, field_type, value, (Int2) bic->returntype, (PTR) bic->buffer,
-                                                        (SDWORD) bic->buflen, (SDWORD *) bic->used);
+       return copy_and_convert_field(stmt, field_type, value, (Int2) bic->returntype, (PTR) (bic->buffer + offset),
+                                                        (SDWORD) bic->buflen, (SDWORD *) (bic->used + (offset >> 2)));
 }
 
 
@@ -318,6 +322,7 @@ int
 copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType,
                                           PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue)
 {
+       static char *func = "copy_and_convert_field";
        Int4            len = 0,
                                copy_len = 0;
        SIMPLE_TIME st;
@@ -387,8 +392,17 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                 * doing nothing to the buffer.
                 */
                if (pcbValue)
+               {
                        *(SDWORD *) ((char *) pcbValue + pcbValueOffset) = SQL_NULL_DATA;
-               return COPY_OK;
+                       return COPY_OK;
+               }
+               else
+               {
+                       stmt->errornumber = STMT_RETURN_NULL_WITHOUT_INDICATOR;
+                       stmt->errormsg = "StrLen_or_IndPtr was a null pointer and NULL data was retrieved";     
+                       SC_log_error(func, "", stmt);
+                       return  SQL_ERROR;
+               }
        }
 
        if (stmt->hdbc->DataSourceToDriver != NULL)
@@ -863,6 +877,26 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                                        *((UDWORD *) rgbValue + bind_row) = atol(neut_str);
                                break;
 
+#if (ODBCVER >= 0x0300) && defined(ODBCINT64)
+#ifdef WIN32
+                       case SQL_C_SBIGINT:
+                               len = 8;
+                               if (bind_size > 0)
+                                       *(SQLBIGINT *) ((char *) rgbValue + (bind_row * bind_size)) = _atoi64(neut_str);
+                               else
+                                       *((SQLBIGINT *) rgbValue + bind_row) = _atoi64(neut_str);
+                               break;
+
+                       case SQL_C_UBIGINT:
+                               len = 8;
+                               if (bind_size > 0)
+                                       *(SQLUBIGINT *) ((char *) rgbValue + (bind_row * bind_size)) = _atoi64(neut_str);
+                               else
+                                       *((SQLUBIGINT *) rgbValue + bind_row) = _atoi64(neut_str);
+                               break;
+
+#endif /* WIN32 */
+#endif /* ODBCINT64 */
                        case SQL_C_BINARY:
 
                                /* truncate if necessary */
@@ -1146,6 +1180,11 @@ table_for_update(const char *stmt, int *endpos)
        return !wstmt[0] || isspace((unsigned char) wstmt[0]);
 }
 
+#ifdef MULTIBYTE
+#define                my_strchr(s1,c1) multibyte_strchr(s1,c1)
+#else
+#define                my_strchr(s1,c1) strchr(s1,c1)
+#endif
 /*
  *     This function inserts parameters into an SQL statements.
  *     It will also modify a SELECT statement for use with declare/fetch cursors.
@@ -1193,10 +1232,13 @@ copy_statement_with_parameters(StatementClass *stmt)
        char            token_save[64];
        int                     token_len;
        BOOL            prev_token_end;
+       UInt4   offset = stmt->options.param_offset_ptr ? *stmt->options.param_offset_ptr : 0;
+       UInt4   current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
 
 #ifdef DRIVER_CURSOR_IMPLEMENT
        BOOL            search_from_pos = FALSE;
 #endif   /* DRIVER_CURSOR_IMPLEMENT */
+
        if (ci->disallow_premature)
                prepare_dummy_cursor = stmt->pre_executing;
 
@@ -1320,25 +1362,15 @@ copy_statement_with_parameters(StatementClass *stmt)
                 */
                else if (oldchar == '{')
                {
-                       char       *esc;
-                       char       *begin = &old_statement[opos + 1];
+                       char       *begin = &old_statement[opos], *end;
 
-#ifdef MULTIBYTE
-                       char       *end = multibyte_strchr(begin, '}');
-
-#else
-                       char       *end = strchr(begin, '}');
-#endif
-
-                       if (!end)
-                               continue;
                        /* procedure calls */
                        if (stmt->statement_type == STMT_TYPE_PROCCALL)
                        {
-                               int                     lit_call_len = 4;
+                               int     lit_call_len = 4;
 
                                while (isspace((unsigned char) old_statement[++opos]));
-                               /* '=?' to accept return values exists ? */
+                               /* '?=' to accept return values exists ? */
                                if (old_statement[opos] == '?')
                                {
                                        param_number++;
@@ -1358,28 +1390,18 @@ copy_statement_with_parameters(StatementClass *stmt)
                                }
                                opos += lit_call_len;
                                CVT_APPEND_STR("SELECT ");
-#ifdef MULTIBYTE
-                               if (multibyte_strchr(&old_statement[opos], '('))
-#else
-                               if (strchr(&old_statement[opos], '('))
-#endif   /* MULTIBYTE */
+                               if (my_strchr(&old_statement[opos], '('))
                                        proc_no_param = FALSE;
                                continue;
                        }
-                       *end = '\0';
-
-                       esc = convert_escape(begin);
-                       if (esc)
-                               CVT_APPEND_STR(esc);
-                       else
-                       {                                       /* it's not a valid literal so just copy */
-                               *end = '}';
-                               CVT_APPEND_CHAR(oldchar);
-                               continue;
+                       if (convert_escape(begin, stmt, &npos, &new_stsize, &end) != CONVERT_ESCAPE_OK)
+                       {
+                               stmt->errormsg = "ODBC escape convert error";
+                               stmt->errornumber = STMT_EXEC_ERROR;
+                               return SQL_ERROR;
                        }
-
-                       opos += end - begin + 1;
-                       *end = '}';
+                       opos = end - old_statement; /* positioned at the last } */
+                       new_statement = stmt->stmt_with_params;
                        continue;
                }
                /* End of a procedure call */
@@ -1500,11 +1522,30 @@ copy_statement_with_parameters(StatementClass *stmt)
                }
                else
                {
+                       UInt4   bind_size = stmt->options.param_bind_type;
+                       UInt4   ctypelen;
 
-
-                       used = stmt->parameters[param_number].used ? *stmt->parameters[param_number].used : SQL_NTS;
-
-                       buffer = stmt->parameters[param_number].buffer;
+                       buffer = stmt->parameters[param_number].buffer + offset;
+                       if (current_row > 0)
+                       {
+                               if (bind_size > 0)
+                                       buffer += (bind_size * current_row);
+                               else if (ctypelen = ctype_length(stmt->parameters[param_number].CType), ctypelen > 0)
+                                       buffer += current_row * ctypelen;
+                               else 
+                                       buffer += current_row * stmt->parameters[param_number].buflen;
+                       }
+                       if (stmt->parameters[param_number].used)
+                       {
+                               UInt4   p_offset = offset;
+                               if (bind_size > 0)
+                                       p_offset = offset + bind_size * current_row;
+                               else
+                                       p_offset = offset + sizeof(SDWORD) * current_row;
+                               used = *(SDWORD *)((char *)stmt->parameters[param_number].used + p_offset);
+                       }
+                       else
+                               used = SQL_NTS;
                }
 
                /* Handle NULL parameter data */
@@ -1570,6 +1611,20 @@ copy_statement_with_parameters(StatementClass *stmt)
                                                *((SDWORD *) buffer));
                                break;
 
+#if (ODBCVER >= 0x0300) && defined(ODBCINT64)
+#ifdef WIN32
+                       case SQL_C_SBIGINT:
+                               sprintf(param_string, "%I64d",
+                                               *((SQLBIGINT *) buffer));
+                               break;
+
+                       case SQL_C_UBIGINT:
+                               sprintf(param_string, "%I64u",
+                                               *((SQLUBIGINT *) buffer));
+                               break;
+
+#endif /* WIN32 */
+#endif /* ODBCINT64 */
                        case SQL_C_SSHORT:
                        case SQL_C_SHORT:
                                sprintf(param_string, "%d",
@@ -1706,7 +1761,7 @@ copy_statement_with_parameters(StatementClass *stmt)
                                        parse_datetime(cbuf, &st);
                                }
 
-                               sprintf(tmp, "'%.4d-%.2d-%.2d'", st.y, st.m, st.d);
+                               sprintf(tmp, "'%.4d-%.2d-%.2d'::date", st.y, st.m, st.d);
 
                                CVT_APPEND_STR(tmp);
                                break;
@@ -1721,7 +1776,7 @@ copy_statement_with_parameters(StatementClass *stmt)
                                        parse_datetime(cbuf, &st);
                                }
 
-                               sprintf(tmp, "'%.2d:%.2d:%.2d'", st.hh, st.mm, st.ss);
+                               sprintf(tmp, "'%.2d:%.2d:%.2d'::time", st.hh, st.mm, st.ss);
 
                                CVT_APPEND_STR(tmp);
                                break;
@@ -1743,7 +1798,7 @@ copy_statement_with_parameters(StatementClass *stmt)
                                 */
                                tmp[0] = '\'';
                                /* Time zone stuff is unreliable */
-                               stime2timestamp(&st, tmp + 1, FALSE, PG_VERSION_GE(conn, 7.2));
+                               stime2timestamp(&st, tmp + 1, USE_ZONE, PG_VERSION_GE(conn, 7.2));
                                strcat(tmp, "'");
 
                                CVT_APPEND_STR(tmp);
@@ -1772,28 +1827,13 @@ copy_statement_with_parameters(StatementClass *stmt)
                                        /* begin transaction if needed */
                                        if (!CC_is_in_trans(conn))
                                        {
-                                               QResultClass *res;
-                                               char            ok;
-
-                                               res = CC_send_query(conn, "BEGIN", NULL);
-                                               if (!res)
+                                               if (!CC_begin(conn))
                                                {
                                                        stmt->errormsg = "Could not begin (in-line) a transaction";
                                                        stmt->errornumber = STMT_EXEC_ERROR;
                                                        SC_log_error(func, "", stmt);
                                                        return SQL_ERROR;
                                                }
-                                               ok = QR_command_successful(res);
-                                               QR_Destructor(res);
-                                               if (!ok)
-                                               {
-                                                       stmt->errormsg = "Could not begin (in-line) a transaction";
-                                                       stmt->errornumber = STMT_EXEC_ERROR;
-                                                       SC_log_error(func, "", stmt);
-                                                       return SQL_ERROR;
-                                               }
-
-                                               CC_set_in_trans(conn);
                                        }
 
                                        /* store the oid */
@@ -1823,28 +1863,13 @@ copy_statement_with_parameters(StatementClass *stmt)
                                        /* commit transaction if needed */
                                        if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
                                        {
-                                               QResultClass *res;
-                                               char            ok;
-
-                                               res = CC_send_query(conn, "COMMIT", NULL);
-                                               if (!res)
-                                               {
-                                                       stmt->errormsg = "Could not commit (in-line) a transaction";
-                                                       stmt->errornumber = STMT_EXEC_ERROR;
-                                                       SC_log_error(func, "", stmt);
-                                                       return SQL_ERROR;
-                                               }
-                                               ok = QR_command_successful(res);
-                                               QR_Destructor(res);
-                                               if (!ok)
+                                               if (!CC_commit(conn))
                                                {
                                                        stmt->errormsg = "Could not commit (in-line) a transaction";
                                                        stmt->errornumber = STMT_EXEC_ERROR;
                                                        SC_log_error(func, "", stmt);
                                                        return SQL_ERROR;
                                                }
-
-                                               CC_set_no_trans(conn);
                                        }
                                }
 
@@ -1951,49 +1976,95 @@ copy_statement_with_parameters(StatementClass *stmt)
 }
 
 
-static char *
-mapFunction(const char *func)
+static const char *
+mapFunction(const char *func, int param_count)
 {
        int                     i;
 
        for (i = 0; mapFuncs[i][0]; i++)
-               if (!stricmp(mapFuncs[i][0], func))
+       {
+               if (mapFuncs[i][0][0] == '%')
+               {
+                       if (mapFuncs[i][0][1] - '0' == param_count &&
+                           !stricmp(mapFuncs[i][0] + 2, func))
+                               return mapFuncs[i][1];
+               }
+               else if (!stricmp(mapFuncs[i][0], func))
                        return mapFuncs[i][1];
+       }
 
        return NULL;
 }
 
 
+static int inner_convert_escape(const ConnectionClass *conn, const char *value, char *result, UInt4 maxLen, const char **input_resume, UInt4 *count);
+static int processParameters(const ConnectionClass *conn, const char *value, char *result, UInt4 maxLen, UInt4 *input_consumed, UInt4 *count, Int4 param_pos[][2]);
+
 /*
- * convert_escape()
- *
- * This function returns a pointer to static memory!
+ * inner_convert_escape()
+ * work with embedded escapes sequences
  */
-char *
-convert_escape(char *value)
+     
+static
+int inner_convert_escape(const ConnectionClass *conn, const char *value,
+               char *result, UInt4 maxLen, const char **input_resume,
+               UInt4 *count)
 {
-       static char escape[1024];
-       char            key[33];
-
+       static const char *func = "inner_convert_escape";
+       int     subret, param_count;
+       char valnts[1024], params[1024];
+       char key[33], *end;
+       const char *valptr;
+       UInt4   vlen, prtlen, input_consumed, param_consumed;
+       Int4    param_pos[16][2];
+       valptr = value;
+       if (*valptr == '{') /* skip the first { */
+               valptr++;
        /* Separate off the key, skipping leading and trailing whitespace */
-       while ((*value != '\0') && isspace((unsigned char) *value))
-               value++;
-       sscanf(value, "%32s", key);
-       while ((*value != '\0') && (!isspace((unsigned char) *value)))
-               value++;
-       while ((*value != '\0') && isspace((unsigned char) *value))
-               value++;
-
-       mylog("convert_escape: key='%s', val='%s'\n", key, value);
-
-       if ((strcmp(key, "d") == 0) ||
-               (strcmp(key, "t") == 0) ||
-               (strcmp(key, "oj") == 0) ||             /* {oj syntax support for 7.1
-                                                                                * servers */
-               (strcmp(key, "ts") == 0))
+       while ((*valptr != '\0') && isspace((unsigned char) *valptr))
+               valptr++;
+       sscanf(valptr, "%32s", key);
+       while ((*valptr != '\0') && (!isspace((unsigned char) *valptr)))
+               valptr++;
+       while ((*valptr != '\0') && isspace((unsigned char) *valptr))
+               valptr++;
+     
+       if (end = my_strchr(valptr, '}'), NULL == end)
+       {
+               mylog("%s couldn't find the ending }\n",func);
+               return CONVERT_ESCAPE_ERROR;
+       }
+       if (vlen = (UInt4)(end - valptr), maxLen <= vlen)
+               return CONVERT_ESCAPE_OVERFLOW;
+       memcpy(valnts, valptr, vlen);
+       valnts[vlen] = '\0';
+       *input_resume = valptr + vlen; /* resume from the last } */
+       mylog("%s: key='%s', val='%s'\n", func, key, valnts);
+     
+       if (strcmp(key, "d") == 0)
+       {
+               /* Literal; return the escape part adding type cast */
+               prtlen = snprintf(result, maxLen, "%s::date", valnts);
+       }
+       else if (strcmp(key, "t") == 0)
+       {
+               /* Literal; return the escape part adding type cast */
+               prtlen = snprintf(result, maxLen, "%s::time", valnts);
+       }
+       else if (strcmp(key, "ts") == 0)
+       {
+               /* Literal; return the escape part adding type cast */
+               if (PG_VERSION_LT(conn, 7.1))
+                       prtlen = snprintf(result, maxLen, "%s::datetime", valnts);
+               else
+                       prtlen = snprintf(result, maxLen, "%s::timestamp", valnts);
+       }
+       else if (strcmp(key, "oj") == 0) /* {oj syntax support for 7.1 * servers */
        {
                /* Literal; return the escape part as-is */
-               strncpy(escape, value, sizeof(escape) - 1);
+               strncpy(result, valnts, maxLen);
+               prtlen = vlen; 
        }
        else if (strcmp(key, "fn") == 0)
        {
@@ -2001,52 +2072,286 @@ convert_escape(char *value)
                 * Function invocation Separate off the func name, skipping
                 * trailing whitespace.
                 */
-               char       *funcEnd = value;
-               char            svchar;
-               char       *mapFunc;
+               char    *funcEnd = valnts;
+               char     svchar;
+               const char      *mapExpr;
+     
+               params[sizeof(params)-1] = '\0';
 
                while ((*funcEnd != '\0') && (*funcEnd != '(') &&
-                          (!isspace((unsigned char) *funcEnd)))
+                       (!isspace((unsigned char) *funcEnd)))
                        funcEnd++;
                svchar = *funcEnd;
                *funcEnd = '\0';
-               sscanf(value, "%32s", key);
+               sscanf(valnts, "%32s", key);
                *funcEnd = svchar;
                while ((*funcEnd != '\0') && isspace((unsigned char) *funcEnd))
                        funcEnd++;
 
                /*
-                * We expect left parenthesis here, else return fn body as-is
+                * We expect left parenthesis here, else return fn body as-is
                 * since it is one of those "function constants".
                 */
                if (*funcEnd != '(')
                {
-                       strncpy(escape, value, sizeof(escape) - 1);
-                       return escape;
+                       strncpy(result, valnts, maxLen);
+                       return CONVERT_ESCAPE_OK;
                }
-               mapFunc = mapFunction(key);
 
                /*
-                * We could have mapFunction() return key if not in table... -
-                * thomas 2000-04-03
+                * Process parameter list and inner escape
+                * sequences
+                * Aceto 2002-01-29
                 */
-               if (mapFunc == NULL)
+
+               valptr += (UInt4)(funcEnd - valnts);
+               if (subret = processParameters(conn, valptr, params, sizeof(params) - 1, &input_consumed, &param_consumed, param_pos), CONVERT_ESCAPE_OK != subret) 
+                       return CONVERT_ESCAPE_ERROR;
+
+               for (param_count = 0;; param_count++)
                {
-                       /* If unrecognized function name, return fn body as-is */
-                       strncpy(escape, value, sizeof(escape) - 1);
-                       return escape;
+                       if (param_pos[param_count][0] < 0)
+                               break;
                }
-               /* copy mapped name and remaining input string */
-               strcpy(escape, mapFunc);
-               strncat(escape, funcEnd, sizeof(escape) - 1 - strlen(mapFunc));
+               if (param_count == 1 &&
+                   param_pos[0][1] < param_pos[0][0])
+                       param_count = 0;
+               
+               mapExpr = mapFunction(key, param_count);
+               if (mapExpr == NULL)
+                       prtlen = snprintf(result, maxLen, "%s%s", key, params);
+               else
+               {
+                       const char *mapptr;
+                       int     from, to, pidx, paramlen;
+
+                       for (prtlen = 0, mapptr = mapExpr; *mapptr; mapptr++)
+                       {
+                               if (prtlen + 1 >= maxLen) /* buffer overflow */
+                               {
+                                       result[prtlen] = '\0';
+                                       prtlen++;
+                                       break;
+                               }
+                               if (*mapptr != '$')
+                               {
+                                       result[prtlen++] = *mapptr;
+                                       continue;
+                               }
+                               mapptr++;
+                               if (*mapptr == '*')
+                               {
+                                       from = 1;
+                                       to = param_consumed - 2;
+                               }
+                               else if (isdigit(*mapptr))
+                               {
+                                       pidx = *mapptr - '0' - 1;
+                                       if (pidx < 0 ||
+                                           param_pos[pidx][0] <0)
+                                       {
+                                               qlog("%s %dth param not found for the expression %s\n", pidx + 1, mapExpr);
+                                               return CONVERT_ESCAPE_ERROR;
+                                       }
+                                       from = param_pos[pidx][0];
+                                       to = param_pos[pidx][1];
+                               }
+                               else
+                               {
+                                       qlog("%s internal expression error %s\n", func, mapExpr);
+                                       return CONVERT_ESCAPE_ERROR;
+                               }
+                               paramlen = to - from + 1;
+                               if (prtlen + paramlen >= maxLen) /* buffer overflow */
+                               {
+                                       prtlen = maxLen;
+                                       break;
+                               }
+                               if (paramlen > 0)
+                                       memcpy(&result[prtlen], params + from, paramlen);
+                               prtlen += paramlen;
+                       }
+                       if (prtlen < maxLen)
+                               result[prtlen] = '\0';
+                       /** prtlen = snprintf(result, maxLen, "%s%s", mapExpr, params); **/
+               }
+               valptr += input_consumed;
+               *input_resume = valptr;
        }
        else
        {
                /* Bogus key, leave untranslated */
-               return NULL;
+               return CONVERT_ESCAPE_ERROR;
+       }
+     
+       if (count)
+               *count = prtlen;
+       if (prtlen < 0 || prtlen >= maxLen) /* buffer overflow */
+       {
+               mylog("%s %d bytes buffer overflow\n", func, maxLen);
+               return CONVERT_ESCAPE_OVERFLOW;
+       }
+       return CONVERT_ESCAPE_OK;
+}
+     
+/*
+ * processParameters()
+ * Process function parameters and work with embedded escapes sequences.
+ */
+     
+static
+int processParameters(const ConnectionClass *conn, const char *value,
+               char *result, UInt4 maxLen, UInt4 *input_consumed,
+               UInt4 *output_count, Int4 param_pos[][2])
+{
+       int             innerParenthesis, subret, param_count;
+       UInt4   ipos, count, inner_count;
+       unsigned char   stop;
+       const char      *valptr;
+       char    buf[1024];
+       BOOL    in_quote, in_dquote, in_escape, leadingSpace;
+       buf[sizeof(buf)-1] = '\0';
+       innerParenthesis = 0;
+       in_quote = in_dquote = in_escape = leadingSpace = FALSE;
+       param_count = 0;
+#ifdef MULTIBYTE
+       multibyte_init();
+#endif /* MULTIBYTE */
+       /* begin with outer '(' */
+       for (stop = FALSE, valptr = value, ipos = count = 0; *valptr != '\0'; ipos++, valptr++)
+       {
+               if (leadingSpace)
+               {
+                       if (isspace(*valptr))
+                               continue;
+                       leadingSpace = FALSE;
+               }
+               if (count + 1 >= maxLen) /* buffer overflow */
+               {
+                       *input_consumed = 0;
+                       result[count++] = '\0';
+                       return CONVERT_ESCAPE_OVERFLOW;
+               }
+#ifdef MULTIBYTE
+               if (multibyte_char_check(*valptr) != 0)
+               {
+                       result[count++] = *valptr;
+                       continue;
+               }
+               /*
+                * From here we are guaranteed to handle a 1-byte character.
+                */
+#endif
+               if (in_quote)
+               {
+                       if (in_escape)
+                               in_escape = FALSE;
+                       else if (*valptr == '\\')
+                               in_escape = TRUE;
+                       else if (*valptr == '\'')
+                               in_quote = FALSE;
+                       result[count++] = *valptr;
+                       continue;
+               }
+               else if (in_dquote)
+               {
+                       if (*valptr == '\"')
+                               in_dquote = FALSE;
+                       result[count++] = *valptr;
+                       continue;
+               }
+               switch (*valptr)
+               {
+                       case '\'':
+                               in_quote = TRUE;
+                               break;
+                       case '\"':
+                               in_dquote = TRUE;
+                               break;
+                       case ',':
+                               if (1 == innerParenthesis)
+                               {
+                                       param_pos[param_count][1] = count - 1;
+                                       param_count++;
+                                       param_pos[param_count][0] = count + 1;
+                                       param_pos[param_count][1] = -1;
+                                       leadingSpace = TRUE;
+                               }
+                               break;
+                       case '(':
+                               if (0 == innerParenthesis)
+                               {
+                                       param_pos[param_count][0] = count + 1;
+                                       param_pos[param_count][1] = -1;
+                                       leadingSpace = TRUE;
+                               }
+                               innerParenthesis++;
+                               break;
+     
+                       case ')':
+                               innerParenthesis--;
+                               if (0 == innerParenthesis)
+                               {
+                                       param_pos[param_count][1] = count - 1;
+                                       param_count++;
+                                       param_pos[param_count][0] =
+                                       param_pos[param_count][1] = -1;
+                               }
+                               break;
+     
+                       case '}':
+                               stop = TRUE;
+                               break;
+     
+                       case '{':
+                               if (subret = inner_convert_escape(conn, valptr, buf, sizeof(buf) - 1, &valptr, &inner_count), CONVERT_ESCAPE_OK != subret)
+                                       return CONVERT_ESCAPE_ERROR;
+     
+                               if (inner_count + count >= maxLen)
+                                       return CONVERT_ESCAPE_OVERFLOW;
+                               memcpy(&result[count], buf, inner_count); 
+                               count += inner_count;
+                               ipos = (UInt4) (valptr - value);
+                               continue;
+               }
+               if (stop) /* returns with the last } position */
+                       break;
+               result[count++] = *valptr;
+       }
+       if (param_pos[param_count][0] >= 0)
+       {
+               mylog("processParameters closing ) not found %d\n", innerParenthesis);
+               return CONVERT_ESCAPE_ERROR;
        }
+       result[count] = '\0';
+       *input_consumed = ipos;
+       if (output_count)
+               *output_count = count;
+       return CONVERT_ESCAPE_OK;
+}
+     
+/*
+ * convert_escape()
+ * This function returns a pointer to static memory!
+ */
+     
+int
+convert_escape(const char *value, StatementClass *stmt, int *npos, int *stsize, const char **val_resume)
+{
+       int     ret, pos = *npos;
+       UInt4   count;
 
-       return escape;
+       while (ret = inner_convert_escape(SC_get_conn(stmt), value,
+               stmt->stmt_with_params + pos, *stsize - pos, val_resume, &count),
+               CONVERT_ESCAPE_OVERFLOW == ret)
+       {
+               if ((*stsize = enlarge_statement(stmt, *stsize * 2)) <= 0)
+                       return CONVERT_ESCAPE_ERROR;
+       }
+       if (CONVERT_ESCAPE_OK == ret)
+               *npos += count;
+       return ret;
 }
 
 
@@ -2218,7 +2523,7 @@ convert_special_chars(const char *si, char *dst, int used)
        multibyte_init();
 #endif
 
-       for (i = 0; i < max; i++)
+       for (i = 0; i < max && si[i]; i++)
        {
 #ifdef MULTIBYTE
                if (multibyte_char_check(si[i]) != 0)
@@ -2514,26 +2819,12 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
                /* begin transaction if needed */
                if (!CC_is_in_trans(conn))
                {
-                       QResultClass *res;
-                       char            ok;
-
-                       res = CC_send_query(conn, "BEGIN", NULL);
-                       if (!res)
-                       {
-                               stmt->errormsg = "Could not begin (in-line) a transaction";
-                               stmt->errornumber = STMT_EXEC_ERROR;
-                               return COPY_GENERAL_ERROR;
-                       }
-                       ok = QR_command_successful(res);
-                       QR_Destructor(res);
-                       if (!ok)
+                       if (!CC_begin(conn))
                        {
                                stmt->errormsg = "Could not begin (in-line) a transaction";
                                stmt->errornumber = STMT_EXEC_ERROR;
                                return COPY_GENERAL_ERROR;
                        }
-
-                       CC_set_in_trans(conn);
                }
 
                oid = atoi(value);
@@ -2577,26 +2868,12 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
                /* commit transaction if needed */
                if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
                {
-                       QResultClass *res;
-                       char            ok;
-
-                       res = CC_send_query(conn, "COMMIT", NULL);
-                       if (!res)
-                       {
-                               stmt->errormsg = "Could not commit (in-line) a transaction";
-                               stmt->errornumber = STMT_EXEC_ERROR;
-                               return COPY_GENERAL_ERROR;
-                       }
-                       ok = QR_command_successful(res);
-                       QR_Destructor(res);
-                       if (!ok)
+                       if (!CC_commit(conn))
                        {
                                stmt->errormsg = "Could not commit (in-line) a transaction";
                                stmt->errornumber = STMT_EXEC_ERROR;
                                return COPY_GENERAL_ERROR;
                        }
-
-                       CC_set_no_trans(conn);
                }
 
                stmt->lobj_fd = -1;
@@ -2626,26 +2903,12 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
                /* commit transaction if needed */
                if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
                {
-                       QResultClass *res;
-                       char            ok;
-
-                       res = CC_send_query(conn, "COMMIT", NULL);
-                       if (!res)
+                       if (!CC_commit(conn))
                        {
                                stmt->errormsg = "Could not commit (in-line) a transaction";
                                stmt->errornumber = STMT_EXEC_ERROR;
                                return COPY_GENERAL_ERROR;
                        }
-                       ok = QR_command_successful(res);
-                       QR_Destructor(res);
-                       if (!ok)
-                       {
-                               stmt->errormsg = "Could not commit (in-line) a transaction";
-                               stmt->errornumber = STMT_EXEC_ERROR;
-                               return COPY_GENERAL_ERROR;
-                       }
-
-                       CC_set_no_trans(conn);
                }
 
                stmt->lobj_fd = -1;             /* prevent further reading */
index 565ce6bf19c6b3f24e0a73370d3fe3489a3b845b..b06f72f3541e8c514b1d84471b5609b7bd95fd14 100644 (file)
 #define COPY_RESULT_TRUNCATED                                  3
 #define COPY_GENERAL_ERROR                                             4
 #define COPY_NO_DATA_FOUND                                             5
+/* convert_escape results */
+#define CONVERT_ESCAPE_OK                                      0
+#define CONVERT_ESCAPE_OVERFLOW                                        1
+#define CONVERT_ESCAPE_ERROR                                   2
 
 typedef struct
 {
@@ -35,7 +39,8 @@ int copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, I
                                           PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue);
 
 int                    copy_statement_with_parameters(StatementClass *stmt);
-char      *convert_escape(char *value);
+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);
 int                    convert_linefeeds(const char *s, char *dst, size_t max, BOOL *changed);
index 304d31d33efb74111814201617aab8a6722e5006..1113ca57ac6e18fd1efa7690954bdfedd17ec291 100644 (file)
@@ -233,6 +233,9 @@ PGAPI_Error(
                                        case STMT_INVALID_CURSOR_POSITION:
                                                strcpy(szSqlState, "S1109");
                                                break;
+                                       case STMT_RETURN_NULL_WITHOUT_INDICATOR:
+                                               strcpy(szSqlState, "22002");
+                                               break;
                                        case STMT_VALUE_OUT_OF_RANGE:
                                                strcpy(szSqlState, "22003");
                                                break;
@@ -376,6 +379,9 @@ PGAPI_Error(
                                        case STMT_NOT_IMPLEMENTED_ERROR:
                                                strcpy(szSqlState, "S1C00");
                                                break;
+                                       case STMT_RETURN_NULL_WITHOUT_INDICATOR:
+                                               strcpy(szSqlState, "22002");
+                                               break;
                                        case CONN_VALUE_OUT_OF_RANGE:
                                        case STMT_VALUE_OUT_OF_RANGE:
                                                strcpy(szSqlState, "22003");
index 5a693b7163823bda7c7d5decdea9e76380a3010d..4c6608923a47805db15c0e80f5b452601bda8fbf 100644 (file)
@@ -196,7 +196,7 @@ PGAPI_Execute(
        StatementClass *stmt = (StatementClass *) hstmt;
        ConnectionClass *conn;
        int                     i,
-                               retval;
+                               retval, start_row, end_row;
 
        mylog("%s: entering...\n", func);
 
@@ -215,7 +215,10 @@ PGAPI_Execute(
        if (stmt->prepare && stmt->status == STMT_PREMATURE)
        {
                if (stmt->inaccurate_result)
+               {
+                       stmt->exec_current_row = -1;
                        SC_recycle_statement(stmt);
+               }
                else
                {
                        stmt->status = STMT_FINISHED;
@@ -278,6 +281,35 @@ PGAPI_Execute(
                return SQL_ERROR;
        }
 
+       if (start_row = stmt->exec_start_row, start_row < 0)
+               start_row = 0; 
+       if (end_row = stmt->exec_end_row, end_row < 0)
+               end_row = stmt->options.paramset_size - 1; 
+       if (stmt->exec_current_row < 0)
+               stmt->exec_current_row = start_row;
+       if (stmt->exec_current_row == start_row)
+       {
+               if (stmt->options.param_processed_ptr)
+                       *stmt->options.param_processed_ptr = 0;
+       }
+
+next_param_row:
+#if (ODBCVER >= 0x0300)
+       if (stmt->options.param_operation_ptr)
+       {
+               while (stmt->options.param_operation_ptr[stmt->exec_current_row] == SQL_PARAM_IGNORE)
+               {
+                       if (stmt->options.param_status_ptr)
+                               stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_UNUSED;
+                       if (stmt->exec_current_row >= end_row)
+                       {
+                               stmt->exec_current_row = -1;
+                               return SQL_SUCCESS;
+                       }
+                       ++stmt->exec_current_row;
+               }
+       }
+#endif /* ODBCVER */
        /*
         * Check if statement has any data-at-execute parameters when it is
         * not in SC_pre_execute.
@@ -289,17 +321,27 @@ PGAPI_Execute(
                 * execute of this statement?  Therefore check for params and
                 * re-copy.
                 */
+               UInt4   offset = stmt->options.param_offset_ptr ? *stmt->options.param_offset_ptr : 0;
+               Int4    bind_size = stmt->options.param_bind_type;
+               Int4    current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
+
                stmt->data_at_exec = -1;
                for (i = 0; i < stmt->parameters_allocated; i++)
                {
                        Int4       *pcVal = stmt->parameters[i].used;
 
-                       if (pcVal && (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET))
-                               stmt->parameters[i].data_at_exec = TRUE;
-                       else
-                               stmt->parameters[i].data_at_exec = FALSE;
+                       stmt->parameters[i].data_at_exec = FALSE;
+                       if (pcVal)
+                       {
+                               if (bind_size > 0)
+                                       pcVal = (Int4 *)((char *)pcVal + offset + bind_size * current_row);
+                               else
+                                       pcVal = (Int4 *)((char *)pcVal + offset + sizeof(SDWORD) * current_row);
+                               if (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET)
+                                       stmt->parameters[i].data_at_exec = TRUE;
+                       }
                        /* Check for data at execution parameters */
-                       if (stmt->parameters[i].data_at_exec == TRUE)
+                       if (stmt->parameters[i].data_at_exec)
                        {
                                if (stmt->data_at_exec < 0)
                                        stmt->data_at_exec = 1;
@@ -333,68 +375,88 @@ PGAPI_Execute(
 
        mylog("   stmt_with_params = '%s'\n", stmt->stmt_with_params);
 
+       if (!stmt->inaccurate_result || !conn->connInfo.disallow_premature)
+       {
+               retval = SC_execute(stmt);
+               if (retval != SQL_ERROR)
+               {
+                       if (stmt->options.param_processed_ptr)
+                               (*stmt->options.param_processed_ptr)++;
+               }
+#if (ODBCVER >= 0x0300)
+               if (stmt->options.param_status_ptr)
+               {
+                       switch (retval)
+                       {
+                               case SQL_SUCCESS: 
+                                       stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
+                                       break;
+                               case SQL_SUCCESS_WITH_INFO: 
+                                       stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
+                                       break;
+                               default: 
+                                       stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
+                                       break;
+                       }
+               }
+#endif /* ODBCVER */
+               if (retval == SQL_ERROR ||
+                   stmt->inaccurate_result ||
+                   stmt->exec_current_row >= end_row)
+               {
+                       stmt->exec_current_row = -1;
+                       return retval;
+               }
+               stmt->exec_current_row++;
+               goto next_param_row;
+       }
        /*
         * Get the field info for the prepared query using dummy backward
         * fetch.
         */
-       if (stmt->inaccurate_result && conn->connInfo.disallow_premature)
+       if (SC_is_pre_executable(stmt))
        {
-               if (SC_is_pre_executable(stmt))
+               BOOL            in_trans = CC_is_in_trans(conn);
+               BOOL            issued_begin = FALSE,
+                                       begin_included = FALSE;
+               QResultClass *res;
+
+               if (strnicmp(stmt->stmt_with_params, "BEGIN;", 6) == 0)
+                       begin_included = TRUE;
+               else if (!in_trans)
                {
-                       BOOL            in_trans = CC_is_in_trans(conn);
-                       BOOL            issued_begin = FALSE,
-                                               begin_included = FALSE;
-                       QResultClass *res;
-
-                       if (strnicmp(stmt->stmt_with_params, "BEGIN;", 6) == 0)
-                               begin_included = TRUE;
-                       else if (!in_trans)
+                       if (issued_begin = CC_begin(conn), !issued_begin)
                        {
-                               res = CC_send_query(conn, "BEGIN", NULL);
-                               if (res && !QR_aborted(res))
-                                       issued_begin = TRUE;
-                               if (res)
-                                       QR_Destructor(res);
-                               if (!issued_begin)
-                               {
-                                       stmt->errornumber = STMT_EXEC_ERROR;
-                                       stmt->errormsg = "Handle prepare error";
-                                       return SQL_ERROR;
-                               }
-                       }
-                       /* we are now in a transaction */
-                       CC_set_in_trans(conn);
-                       stmt->result = res = CC_send_query(conn, stmt->stmt_with_params, NULL);
-                       if (!res || QR_aborted(res))
-                       {
-                               CC_abort(conn);
                                stmt->errornumber = STMT_EXEC_ERROR;
                                stmt->errormsg = "Handle prepare error";
                                return SQL_ERROR;
                        }
-                       else
-                       {
-                               if (CC_is_in_autocommit(conn))
-                               {
-                                       if (issued_begin)
-                                       {
-                                               res = CC_send_query(conn, "COMMIT", NULL);
-                                               CC_set_no_trans(conn);
-                                               if (res)
-                                                       QR_Destructor(res);
-                                       }
-                                       else if (!in_trans && begin_included)
-                                               CC_set_no_trans(conn);
-                               }
-                               stmt->status = STMT_FINISHED;
-                               return SQL_SUCCESS;
-                       }
+               }
+               /* we are now in a transaction */
+               CC_set_in_trans(conn);
+               stmt->result = res = CC_send_query(conn, stmt->stmt_with_params, NULL);
+               if (!res || QR_aborted(res))
+               {
+                       CC_abort(conn);
+                       stmt->errornumber = STMT_EXEC_ERROR;
+                       stmt->errormsg = "Handle prepare error";
+                       return SQL_ERROR;
                }
                else
+               {
+                       if (CC_is_in_autocommit(conn))
+                       {
+                               if (issued_begin)
+                                       CC_commit(conn);
+                               else if (!in_trans && begin_included)
+                                       CC_set_no_trans(conn);
+                       }
+                       stmt->status = STMT_FINISHED;
                        return SQL_SUCCESS;
+               }
        }
-
-       return SC_execute(stmt);
+       else
+               return SQL_SUCCESS;
 }
 
 
@@ -659,21 +721,7 @@ PGAPI_ParamData(
                /* commit transaction if needed */
                if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(stmt->hdbc))
                {
-                       QResultClass *res;
-                       char            ok;
-
-                       res = CC_send_query(stmt->hdbc, "COMMIT", NULL);
-                       if (!res)
-                       {
-                               stmt->errormsg = "Could not commit (in-line) a transaction";
-                               stmt->errornumber = STMT_EXEC_ERROR;
-                               SC_log_error(func, "", stmt);
-                               return SQL_ERROR;
-                       }
-                       ok = QR_command_successful(res);
-                       CC_set_no_trans(stmt->hdbc);
-                       QR_Destructor(res);
-                       if (!ok)
+                       if (!CC_commit(stmt->hdbc))
                        {
                                stmt->errormsg = "Could not commit (in-line) a transaction";
                                stmt->errornumber = STMT_EXEC_ERROR;
@@ -687,13 +735,47 @@ PGAPI_ParamData(
        /* Done, now copy the params and then execute the statement */
        if (stmt->data_at_exec == 0)
        {
+               int     end_row;
+
                retval = copy_statement_with_parameters(stmt);
                if (retval != SQL_SUCCESS)
                        return retval;
 
                stmt->current_exec_param = -1;
 
-               return SC_execute(stmt);
+               retval = SC_execute(stmt);
+               if (retval != SQL_ERROR)
+               {
+                       if (stmt->options.param_processed_ptr)
+                               (*stmt->options.param_processed_ptr)++;
+               }
+#if (ODBCVER >= 0x0300)
+               if (stmt->options.param_status_ptr)
+               {
+                       switch (retval)
+                       {
+                               case SQL_SUCCESS: 
+                                       stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
+                                       break;
+                               case SQL_SUCCESS_WITH_INFO: 
+                                       stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
+                                       break;
+                               default: 
+                                       stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
+                                       break;
+                       }
+               }
+#endif /* ODBCVER */
+               if (stmt->exec_end_row < 0)
+                       end_row = stmt->options.paramset_size - 1;
+               if (retval == SQL_ERROR ||
+                   stmt->exec_current_row >= end_row)
+               {
+                       stmt->exec_current_row = -1;
+                       return retval;
+               }
+               stmt->exec_current_row++;
+               return PGAPI_Execute(stmt);
        }
 
        /*
@@ -705,7 +787,7 @@ PGAPI_ParamData(
        /* At least 1 data at execution parameter, so Fill in the token value */
        for (; i < stmt->parameters_allocated; i++)
        {
-               if (stmt->parameters[i].data_at_exec == TRUE)
+               if (stmt->parameters[i].data_at_exec)
                {
                        stmt->data_at_exec--;
                        stmt->current_exec_param = i;
@@ -780,28 +862,13 @@ PGAPI_PutData(
                        /* begin transaction if needed */
                        if (!CC_is_in_trans(stmt->hdbc))
                        {
-                               QResultClass *res;
-                               char            ok;
-
-                               res = CC_send_query(stmt->hdbc, "BEGIN", NULL);
-                               if (!res)
-                               {
-                                       stmt->errormsg = "Could not begin (in-line) a transaction";
-                                       stmt->errornumber = STMT_EXEC_ERROR;
-                                       SC_log_error(func, "", stmt);
-                                       return SQL_ERROR;
-                               }
-                               ok = QR_command_successful(res);
-                               QR_Destructor(res);
-                               if (!ok)
+                               if (!CC_begin(stmt->hdbc))
                                {
                                        stmt->errormsg = "Could not begin (in-line) a transaction";
                                        stmt->errornumber = STMT_EXEC_ERROR;
                                        SC_log_error(func, "", stmt);
                                        return SQL_ERROR;
                                }
-
-                               CC_set_in_trans(stmt->hdbc);
                        }
 
                        /* store the oid */
index c77b3c5e8981a8d7d1a2e8a6b9426b0076858eb7..865c8ac7adfd4c97cde0bb88e15da465e8b027f3 100644 (file)
@@ -36,6 +36,9 @@
 #include "misc.h"
 #include "pgtypes.h"
 #include "pgapifunc.h"
+#ifdef MULTIBYTE
+#include "multibyte.h"
+#endif
 
 
 /*     Trigger related stuff for SQLForeign Keys */
@@ -567,7 +570,10 @@ PGAPI_GetInfo(
                        break;
 
                case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
-                       p = "";
+                       if (PG_VERSION_GE(conn, 6.5))
+                               p = "\\";
+                       else
+                               p = "";
                        break;
 
                case SQL_SERVER_NAME:   /* ODBC 1.0 */
@@ -1365,7 +1371,8 @@ PGAPI_Tables(
                {
                        row = (TupleNode *) malloc(sizeof(TupleNode) + (5 - 1) *sizeof(TupleField));
 
-                       set_tuplefield_string(&row->tuple[0], "");
+                       /*set_tuplefield_string(&row->tuple[0], "");*/
+                       set_tuplefield_null(&row->tuple[0]);
 
                        /*
                         * I have to hide the table owner from Access, otherwise it
@@ -1378,7 +1385,8 @@ PGAPI_Tables(
 
                        mylog("%s: table_name = '%s'\n", func, table_name);
 
-                       set_tuplefield_string(&row->tuple[1], "");
+                       /* set_tuplefield_string(&row->tuple[1], ""); */
+                       set_tuplefield_null(&row->tuple[1]);
                        set_tuplefield_string(&row->tuple[2], table_name);
                        set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
                        set_tuplefield_string(&row->tuple[4], "");
@@ -1413,6 +1421,66 @@ PGAPI_Tables(
 }
 
 
+/*
+ *     PostgreSQL needs 2 '\\' to escape '_' and '%'. 
+ */
+static int
+reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len)
+{
+       int     i, outlen;
+       const char *in;
+       BOOL    escape_in = FALSE;
+
+       if (srclen == SQL_NULL_DATA)
+       {
+               dest[0] = '\0';
+               return STRCPY_NULL;
+       }
+       else if (srclen == SQL_NTS)
+               srclen = strlen(src);
+       if (srclen <= 0)
+               return STRCPY_FAIL;
+#ifdef MULTIBYTE
+       multibyte_init();
+#endif
+       for (i = 0, in = src, outlen = 0; i < srclen && outlen < dst_len; i++, in++)
+       {
+#ifdef MULTIBYTE
+                if (multibyte_char_check(*in) != 0)
+                {
+                        dest[outlen++] = *in;
+                        continue;
+                }
+#endif
+               if (escape_in)
+               {
+                       switch (*in)
+                       {
+                               case '%':
+                               case '_':
+                                       dest[outlen++] = '\\'; /* needs 1 more */
+                                       break;
+                               default:
+                                       dest[outlen++] = '\\';
+                                       if (outlen < dst_len)
+                                               dest[outlen++] = '\\';
+                                       if (outlen < dst_len)
+                                               dest[outlen++] = '\\';
+                                       break;
+                       }
+               }
+               if (*in == '\\')
+                       escape_in = TRUE;
+               else
+                       escape_in = FALSE;
+               if (outlen < dst_len)
+                       dest[outlen++] = *in;
+       }
+       if (outlen < dst_len)
+               dest[outlen] = '\0';
+       return outlen;
+}
+
 RETCODE                SQL_API
 PGAPI_Columns(
                          HSTMT hstmt,
@@ -1423,7 +1491,8 @@ PGAPI_Columns(
                          UCHAR FAR * szTableName,
                          SWORD cbTableName,
                          UCHAR FAR * szColumnName,
-                         SWORD cbColumnName)
+                         SWORD cbColumnName,
+                         UWORD flag)
 {
        static char *func = "PGAPI_Columns";
        StatementClass *stmt = (StatementClass *) hstmt;
@@ -1476,9 +1545,22 @@ PGAPI_Columns(
          " and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
                        PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod");
 
-       my_strcat(columns_query, " and c.relname like '%.*s'", szTableName, cbTableName);
-       my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner);
-       my_strcat(columns_query, " and a.attname like '%.*s'", szColumnName, cbColumnName);
+       if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) 
+       {
+               my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
+               my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner);
+               my_strcat(columns_query, " and a.attname = '%.*s'", szColumnName, cbColumnName);
+       }
+       else
+       {
+               char    esc_table_name[MAX_TABLE_LEN * 2];
+               int     escTbnamelen;
+
+               escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name));
+               my_strcat(columns_query, " and c.relname like '%.*s'", esc_table_name, escTbnamelen);
+               my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner);
+               my_strcat(columns_query, " and a.attname like '%.*s'", szColumnName, cbColumnName);
+       }
 
        /*
         * give the output in the order the columns were defined when the
@@ -1730,7 +1812,7 @@ PGAPI_Columns(
                 *----------
                 */
                qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,sqltype=%d,name='%s'\n",
-                        table_name, field_name, field_type, pgtype_to_sqltype, field_type_name);
+                        table_name, field_name, field_type, pgtype_to_sqltype(stmt,field_type), field_type_name);
 
                useStaticPrecision = TRUE;
 
@@ -1892,8 +1974,10 @@ PGAPI_SpecialColumns(
                        "from pg_user u, pg_class c where "
                        "u.usesysid = c.relowner");
 
-       my_strcat(columns_query, " and c.relname like '%.*s'", szTableName, cbTableName);
-       my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner);
+       /* TableName cannot contain a string search pattern */
+       my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
+       /* SchemaName cannot contain a string search pattern */
+       my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner);
 
 
        result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
@@ -2114,8 +2198,11 @@ PGAPI_Statistics(
         * being shown. This would throw everything off.
         */
        col_stmt->internal = TRUE;
+       /* 
+        * table_name parameter cannot contain a string search pattern. 
+        */
        result = PGAPI_Columns(hcol_stmt, "", 0, "", 0,
-                                                  table_name, (SWORD) strlen(table_name), "", 0);
+                                                  table_name, (SWORD) strlen(table_name), "", 0, PODBC_NOT_SEARCH_PATTERN);
        col_stmt->internal = FALSE;
 
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
@@ -2725,9 +2812,7 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
        continueExec = (continueExec && !bError);
        if (bError && CC_is_in_trans(conn))
        {
-               if (res = CC_send_query(conn, "abort", NULL), res)
-                       QR_Destructor(res);
-               CC_set_no_trans(conn);
+               CC_abort(conn);
                bError = FALSE;
        }
        /* restore the client encoding */
@@ -2811,9 +2896,7 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
        continueExec = (continueExec && !bError);
        if (bError && CC_is_in_trans(conn))
        {
-               if (res = CC_send_query(conn, "abort", NULL), res)
-                       QR_Destructor(res);
-               CC_set_no_trans(conn);
+               CC_abort(conn);
                bError = FALSE;
        }
        /* restore the cleint encoding */
@@ -3647,7 +3730,7 @@ PGAPI_Procedures(
                " proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" ","
                   " '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
                   " '' as " "REMARKS" ","
-                  " case when prorettype =0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc");
+                  " case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc");
        my_strcat(proc_query, " where proname like '%.*s'", szProcName, cbProcName);
 
        res = CC_send_query(conn, proc_query, NULL);
index a87c35850c4a6a203d15cce6cb725ab317866f47..0527b21c38b3e34fa2a2219a017d523ccfda01a9 100644 (file)
@@ -84,8 +84,8 @@ SQLColumns(HSTMT StatementHandle,
 {
        mylog("[SQLColumns]");
        return PGAPI_Columns(StatementHandle, CatalogName, NameLength1,
-                                                SchemaName, NameLength2, TableName, NameLength3,
-                                                ColumnName, NameLength4);
+                                       SchemaName, NameLength2, TableName, NameLength3,
+                                       ColumnName, NameLength4, 0);
 }
 
 
@@ -218,7 +218,7 @@ SQLFetch(HSTMT StatementHandle)
 RETCODE                SQL_API
 SQLFreeConnect(HDBC ConnectionHandle)
 {
-       mylog("[SQLFreeStmt]");
+       mylog("[SQLFreeConnect]");
        return PGAPI_FreeConnect(ConnectionHandle);
 }
 
index 8ad1dba7e6fa3163f63c8608522bf30050810fea..1d5a623f74a82c7acc2c02f4cbd57a608946671c 100644 (file)
@@ -85,12 +85,47 @@ SQLColAttribute(HSTMT StatementHandle,
                                                           StringLength, NumericAttribute);
 }
 
+static HSTMT
+descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType) 
+{
+       switch (descType)
+       {
+               case SQL_ATTR_APP_ROW_DESC:             /* 10010 */
+                       return StatementHandle; /* this is bogus */
+               case SQL_ATTR_APP_PARAM_DESC:   /* 10011 */
+                       return (HSTMT) ((SQLUINTEGER) StatementHandle + 1) ; /* this is bogus */
+               case SQL_ATTR_IMP_ROW_DESC:             /* 10012 */
+                       return (HSTMT) ((SQLUINTEGER) StatementHandle + 2); /* this is bogus */
+               case SQL_ATTR_IMP_PARAM_DESC:   /* 10013 */
+                       return (HSTMT) ((SQLUINTEGER) StatementHandle + 3); /* this is bogus */
+       }
+       return (HSTMT) 0;
+}
+static HSTMT
+statementHandleFromDescHandle(HSTMT DescHandle, SQLINTEGER *descType) 
+{
+       SQLUINTEGER res = (SQLUINTEGER) DescHandle % 4;
+       switch (res)
+       {
+               case 0: *descType = SQL_ATTR_APP_ROW_DESC; /* 10010 */
+                       break;
+               case 1: *descType = SQL_ATTR_APP_PARAM_DESC; /* 10011 */
+                       break;
+               case 2: *descType = SQL_ATTR_IMP_ROW_DESC; /* 10012 */
+                       break;
+               case 3: *descType = SQL_ATTR_IMP_PARAM_DESC; /* 10013 */
+                       break;
+       }
+       return (HSTMT) ((SQLUINTEGER) DescHandle - res);
+}
+
 /*     new function */
 RETCODE                SQL_API
 SQLCopyDesc(SQLHDESC SourceDescHandle,
                        SQLHDESC TargetDescHandle)
 {
        mylog("[[SQLCopyDesc]]\n");
+       mylog("Error not implemented\n");
        return SQL_ERROR;
 }
 
@@ -129,7 +164,10 @@ SQLFetchScroll(HSTMT StatementHandle,
        if (FetchOrientation == SQL_FETCH_BOOKMARK)
        {
                if (stmt->options.bookmark_ptr)
+{
                        FetchOffset += *((Int4 *) stmt->options.bookmark_ptr);
+mylog("real FetchOffset = %d\n", FetchOffset);
+}
                else
                {
                        stmt->errornumber = STMT_SEQUENCE_ERROR;
@@ -172,6 +210,7 @@ SQLGetDescField(SQLHDESC DescriptorHandle,
                                SQLINTEGER *StringLength)
 {
        mylog("[[SQLGetDescField]]\n");
+       mylog("Error not implemented\n");
        return SQL_ERROR;
 }
 
@@ -185,6 +224,7 @@ SQLGetDescRec(SQLHDESC DescriptorHandle,
                          SQLSMALLINT *Scale, SQLSMALLINT *Nullable)
 {
        mylog("[[SQLGetDescRec]]\n");
+       mylog("Error not implemented\n");
        return SQL_ERROR;
 }
 
@@ -305,22 +345,51 @@ SQLGetStmtAttr(HSTMT StatementHandle,
        RETCODE         ret = SQL_SUCCESS;
        int                     len = 0;
 
-       mylog("[[%s]] %d\n", func, Attribute);
+       mylog("[[%s]] Handle=%u %d\n", func, StatementHandle, Attribute);
        switch (Attribute)
        {
                case SQL_ATTR_FETCH_BOOKMARK_PTR:               /* 16 */
                        Value = stmt->options.bookmark_ptr;
-
+                       len = 4;
+                       break;
+               case SQL_ATTR_PARAM_BIND_OFFSET_PTR:    /* 17 */
+                       Value = stmt->options.param_offset_ptr;
+                       len = 4;
+                       break;
+               case SQL_ATTR_PARAM_BIND_TYPE:  /* 18 */
+                       *((SQLUINTEGER *) Value) = stmt->options.param_bind_type;
+                       len = 4;
+                       break;
+               case SQL_ATTR_PARAM_OPERATION_PTR:              /* 19 */
+                       Value = stmt->options.param_operation_ptr;
+                       len = 4;
+                       break;
+               case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
+                       Value = stmt->options.param_status_ptr;
+                       len = 4;
+                       break;
+               case SQL_ATTR_PARAMS_PROCESSED_PTR:             /* 21 */
+                       Value = stmt->options.param_processed_ptr;
+                       len = 4;
+                       break;
+               case SQL_ATTR_PARAMSET_SIZE:    /* 22 */
+                       *((SQLUINTEGER *) Value) = stmt->options.paramset_size;
+                       len = 4;
+                       break;
+               case SQL_ATTR_ROW_BIND_OFFSET_PTR:              /* 23 */
+                       Value = stmt->options.row_offset_ptr;
+                       len = 4;
+                       break;
+               case SQL_ATTR_ROW_OPERATION_PTR:                /* 24 */
+                       Value = stmt->options.row_operation_ptr;
                        len = 4;
                        break;
                case SQL_ATTR_ROW_STATUS_PTR:   /* 25 */
                        Value = stmt->options.rowStatusArray;
-
                        len = 4;
                        break;
                case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
                        Value = stmt->options.rowsFetched;
-
                        len = 4;
                        break;
                case SQL_ATTR_ROW_ARRAY_SIZE:   /* 27 */
@@ -328,30 +397,17 @@ SQLGetStmtAttr(HSTMT StatementHandle,
                        len = 4;
                        break;
                case SQL_ATTR_APP_ROW_DESC:             /* 10010 */
-                       *((HSTMT *) Value) = StatementHandle;           /* this is useless */
-                       len = 4;
-                       break;
                case SQL_ATTR_APP_PARAM_DESC:   /* 10011 */
-                       *((HSTMT *) Value) = StatementHandle;           /* this is useless */
-                       len = 4;
-                       break;
                case SQL_ATTR_IMP_ROW_DESC:             /* 10012 */
-                       *((HSTMT *) Value) = StatementHandle;           /* this is useless */
-                       len = 4;
-                       break;
                case SQL_ATTR_IMP_PARAM_DESC:   /* 10013 */
-                       *((HSTMT *) Value) = StatementHandle;           /* this is useless */
                        len = 4;
+                       *((HSTMT *) Value) = descHandleFromStatementHandle(StatementHandle, Attribute); 
                        break;
                case SQL_ATTR_AUTO_IPD: /* 10001 */
                        /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
-               case SQL_ATTR_PARAMSET_SIZE:    /* 22 */
-               case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
-               case SQL_ATTR_PARAMS_PROCESSED_PTR:             /* 21 */
 
                case SQL_ATTR_CURSOR_SCROLLABLE:                /* -1 */
                case SQL_ATTR_CURSOR_SENSITIVITY:               /* -2 */
-
                case SQL_ATTR_ENABLE_AUTO_IPD:  /* 15 */
                case SQL_ATTR_METADATA_ID:              /* 10014 */
 
@@ -359,11 +415,6 @@ SQLGetStmtAttr(HSTMT StatementHandle,
                         * case SQL_ATTR_PREDICATE_PTR: case
                         * SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR:
                         */
-               case SQL_ATTR_PARAM_BIND_OFFSET_PTR:    /* 17 */
-               case SQL_ATTR_PARAM_BIND_TYPE:  /* 18 */
-               case SQL_ATTR_PARAM_OPERATION_PTR:              /* 19 */
-               case SQL_ATTR_ROW_BIND_OFFSET_PTR:              /* 23 */
-               case SQL_ATTR_ROW_OPERATION_PTR:                /* 24 */
                        stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
                        stmt->errormsg = "Unsupported statement option (Get)";
                        SC_log_error(func, "", stmt);
@@ -400,14 +451,127 @@ SQLSetConnectAttr(HDBC ConnectionHandle,
        return PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value);
 }
 
+static RETCODE SQL_API
+ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+               SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
+{
+       RETCODE         ret = SQL_SUCCESS;
+       switch (FieldIdentifier)
+       {
+               case SQL_DESC_ARRAY_SIZE:
+                       stmt->options.rowset_size = (SQLUINTEGER) Value;
+                       break; 
+               case SQL_DESC_ARRAY_STATUS_PTR:
+                       stmt->options.row_operation_ptr = Value;
+                       break;
+               case SQL_DESC_BIND_OFFSET_PTR:
+                       stmt->options.row_offset_ptr = Value;
+                       break;
+               case SQL_DESC_BIND_TYPE:
+                       stmt->options.bind_size = (SQLUINTEGER) Value;
+                       break;
+               default:ret = SQL_ERROR;
+                       stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+       }
+       return ret;
+}
+
+static RETCODE SQL_API
+APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+               SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
+{
+       RETCODE         ret = SQL_SUCCESS;
+       switch (FieldIdentifier)
+       {
+               case SQL_DESC_ARRAY_SIZE:
+                       stmt->options.paramset_size = (SQLUINTEGER) Value;
+                       break; 
+               case SQL_DESC_ARRAY_STATUS_PTR:
+                       stmt->options.param_operation_ptr = Value;
+                       break;
+               case SQL_DESC_BIND_OFFSET_PTR:
+                       stmt->options.param_offset_ptr = Value;
+                       break;
+               case SQL_DESC_BIND_TYPE:
+                       stmt->options.param_bind_type = (SQLUINTEGER) Value;
+                       break;
+               default:ret = SQL_ERROR;
+                       stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+       }
+       return ret;
+}
+
+static RETCODE SQL_API
+IRDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+               SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
+{
+       RETCODE         ret = SQL_SUCCESS;
+       switch (FieldIdentifier)
+       {
+               case SQL_DESC_ARRAY_STATUS_PTR:
+                       stmt->options.rowStatusArray = (SQLUSMALLINT *) Value;
+                       break;
+               case SQL_DESC_ROWS_PROCESSED_PTR:
+                       stmt->options.rowsFetched = (SQLUINTEGER *) Value;
+                       break;
+               default:ret = SQL_ERROR;
+                       stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+       }
+       return ret;
+}
+
+static RETCODE SQL_API
+IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
+               SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
+{
+       RETCODE         ret = SQL_SUCCESS;
+       switch (FieldIdentifier)
+       {
+               case SQL_DESC_ARRAY_STATUS_PTR:
+                       stmt->options.param_status_ptr = (SQLUSMALLINT *) Value;
+                       break;
+               case SQL_DESC_ROWS_PROCESSED_PTR:
+                       stmt->options.param_processed_ptr = (SQLUINTEGER *) Value;
+                       break;
+               default:ret = SQL_ERROR;
+                       stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; 
+       }
+       return ret;
+}
+
 /*     new function */
 RETCODE                SQL_API
 SQLSetDescField(SQLHDESC DescriptorHandle,
                                SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
                                PTR Value, SQLINTEGER BufferLength)
 {
-       mylog("[[SQLSetDescField]]\n");
-       return SQL_ERROR;
+       RETCODE         ret = SQL_SUCCESS;
+       HSTMT           hstmt;
+       SQLUINTEGER     descType;
+       StatementClass *stmt;
+       mylog("[[SQLSetDescField]] h=%u rec=%d field=%d val=%x\n", DescriptorHandle, RecNumber, FieldIdentifier, Value);
+       hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType);
+       mylog("stmt=%x type=%d\n", hstmt, descType);
+       stmt = (StatementClass *) hstmt;
+       switch (descType)
+       {
+               case SQL_ATTR_APP_ROW_DESC:
+                       ret = ARDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
+                       break;
+               case SQL_ATTR_APP_PARAM_DESC:
+                       ret = APDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
+                       break;
+               case SQL_ATTR_IMP_ROW_DESC:
+                       ret = IRDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
+                       break;
+               case SQL_ATTR_IMP_PARAM_DESC:
+                       ret = IPDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
+                       break;
+               default:ret = SQL_ERROR;
+                       stmt->errornumber = STMT_INTERNAL_ERROR; 
+                       mylog("Error not implemented\n");
+       }
+       return ret;
 }
 
 /*     new fucntion */
@@ -419,7 +583,8 @@ SQLSetDescRec(SQLHDESC DescriptorHandle,
                          PTR Data, SQLINTEGER *StringLength,
                          SQLINTEGER *Indicator)
 {
-       mylog("[[SQLsetDescRec]]\n");
+       mylog("[[SQLSetDescRec]]\n");
+       mylog("Error not implemented\n");
        return SQL_ERROR;
 }
 
@@ -466,16 +631,10 @@ SQLSetStmtAttr(HSTMT StatementHandle,
 {
        static char *func = "SQLSetStmtAttr";
        StatementClass *stmt = (StatementClass *) StatementHandle;
-       UDWORD          rowcount;
 
-       mylog("[[%s]] %d,%u\n", func, Attribute, Value);
+       mylog("[[%s]] Handle=%u %d,%u\n", func, StatementHandle, Attribute, Value);
        switch (Attribute)
        {
-               case SQL_ATTR_PARAMSET_SIZE:    /* 22 */
-                       return PGAPI_ParamOptions(StatementHandle, (UWORD) Value, &rowcount);
-               case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
-               case SQL_ATTR_PARAMS_PROCESSED_PTR:             /* 21 */
-
                case SQL_ATTR_CURSOR_SCROLLABLE:                /* -1 */
                case SQL_ATTR_CURSOR_SENSITIVITY:               /* -2 */
 
@@ -484,28 +643,41 @@ SQLSetStmtAttr(HSTMT StatementHandle,
                case SQL_ATTR_APP_ROW_DESC:             /* 10010 */
                case SQL_ATTR_APP_PARAM_DESC:   /* 10011 */
                case SQL_ATTR_AUTO_IPD: /* 10001 */
-                       /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
-               case SQL_ATTR_IMP_ROW_DESC:             /* 10012 */
-               case SQL_ATTR_IMP_PARAM_DESC:   /* 10013 */
+               /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
+               case SQL_ATTR_IMP_ROW_DESC:     /* 10012 (read-only) */
+               case SQL_ATTR_IMP_PARAM_DESC:   /* 10013 (read-only) */
                case SQL_ATTR_METADATA_ID:              /* 10014 */
 
                        /*
                         * case SQL_ATTR_PREDICATE_PTR: case
                         * SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR:
                         */
-               case SQL_ATTR_PARAM_BIND_OFFSET_PTR:    /* 17 */
-               case SQL_ATTR_PARAM_BIND_TYPE:  /* 18 */
                case SQL_ATTR_PARAM_OPERATION_PTR:              /* 19 */
-               case SQL_ATTR_ROW_BIND_OFFSET_PTR:              /* 23 */
+               case SQL_ATTR_PARAM_STATUS_PTR:                 /* 20 */
                case SQL_ATTR_ROW_OPERATION_PTR:                /* 24 */
                        stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
                        stmt->errormsg = "Unsupported statement option (Set)";
                        SC_log_error(func, "", stmt);
                        return SQL_ERROR;
 
+               case SQL_ATTR_PARAM_BIND_OFFSET_PTR:    /* 17 */
+                       stmt->options.param_offset_ptr = (SQLUINTEGER *) Value;
+                       break;
+               case SQL_ATTR_ROW_BIND_OFFSET_PTR:              /* 23 */
+                       stmt->options.row_offset_ptr = (SQLUINTEGER *) Value;
+                       break;
+
                case SQL_ATTR_FETCH_BOOKMARK_PTR:               /* 16 */
                        stmt->options.bookmark_ptr = Value;
-
+                       break;
+               case SQL_ATTR_PARAM_BIND_TYPE:  /* 18 */
+                       stmt->options.param_bind_type = (SQLUINTEGER) Value;
+                       break;
+               case SQL_ATTR_PARAMS_PROCESSED_PTR:             /* 21 */
+                       stmt->options.param_processed_ptr = (SQLUINTEGER *) Value;
+                       break;
+               case SQL_ATTR_PARAMSET_SIZE:    /* 22 */
+                       stmt->options.paramset_size = (SQLUINTEGER) Value;
                        break;
                case SQL_ATTR_ROW_STATUS_PTR:   /* 25 */
                        stmt->options.rowStatusArray = (SQLUSMALLINT *) Value;
@@ -642,111 +814,3 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
 
        return SQL_SUCCESS;
 }
-RETCODE                SQL_API
-PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
-                               SWORD cbInfoValueMax, SWORD FAR * pcbInfoValue)
-{
-       static char *func = "PGAPI_GetInfo30";
-       ConnectionClass *conn = (ConnectionClass *) hdbc;
-       char       *p = NULL;
-       int                     len = 0,
-                               value = 0;
-       RETCODE         result;
-
-       switch (fInfoType)
-       {
-               case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
-                       len = 4;
-                       value = 0;
-                       break;
-               case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
-                       len = 4;
-                       value = 0;
-                       break;
-
-               case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
-                       len = 4;
-                       value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
-                               SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK;
-                       break;
-               case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
-                       len = 4;
-                       value = 0;
-                       break;
-               case SQL_KEYSET_CURSOR_ATTRIBUTES1:
-                       len = 4;
-                       value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE
-                               | SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK
-                               | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION
-                               | SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
-                               | SQL_CA1_POS_REFRESH
-                               | SQL_CA1_BULK_ADD
-                               | SQL_CA1_BULK_UPDATE_BY_BOOKMARK
-                               | SQL_CA1_BULK_DELETE_BY_BOOKMARK
-                               | SQL_CA1_BULK_FETCH_BY_BOOKMARK
-                               ;
-                       break;
-               case SQL_KEYSET_CURSOR_ATTRIBUTES2:
-                       len = 4;
-                       value = SQL_CA2_OPT_ROWVER_CONCURRENCY |
-                               SQL_CA2_SENSITIVITY_ADDITIONS |
-                               SQL_CA2_SENSITIVITY_DELETIONS |
-                               SQL_CA2_SENSITIVITY_UPDATES;
-                       break;
-
-               case SQL_STATIC_CURSOR_ATTRIBUTES1:
-                       len = 4;
-                       value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
-                               SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK |
-                               SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION |
-                               SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE |
-                               SQL_CA1_POS_REFRESH;
-                       break;
-               case SQL_STATIC_CURSOR_ATTRIBUTES2:
-                       len = 4;
-                       value = SQL_CA2_OPT_ROWVER_CONCURRENCY |
-                               SQL_CA2_SENSITIVITY_ADDITIONS |
-                               SQL_CA2_SENSITIVITY_DELETIONS |
-                               SQL_CA2_SENSITIVITY_UPDATES;
-                       break;
-               default:
-                       /* unrecognized key */
-                       conn->errormsg = "Unrecognized key passed to SQLGetInfo.";
-                       conn->errornumber = CONN_NOT_IMPLEMENTED_ERROR;
-                       CC_log_error(func, "", conn);
-                       return SQL_ERROR;
-       }
-       result = SQL_SUCCESS;
-       if (p)
-       {
-               /* char/binary data */
-               len = strlen(p);
-
-               if (rgbInfoValue)
-               {
-                       strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
-
-                       if (len >= cbInfoValueMax)
-                       {
-                               result = SQL_SUCCESS_WITH_INFO;
-                               conn->errornumber = STMT_TRUNCATED;
-                               conn->errormsg = "The buffer was too small for tthe InfoValue.";
-                       }
-               }
-       }
-       else
-       {
-               /* numeric data */
-               if (rgbInfoValue)
-               {
-                       if (len == 2)
-                               *((WORD *) rgbInfoValue) = (WORD) value;
-                       else if (len == 4)
-                               *((DWORD *) rgbInfoValue) = (DWORD) value;
-               }
-       }
-
-       if (pcbInfoValue)
-               *pcbInfoValue = len;
-       return result;
-}
index bf2707f4dae33b1359414eb14df15828f184883a..80ec7dac68ecd9b1715f319cb8f84b7d5821db63 100644 (file)
@@ -342,14 +342,12 @@ PGAPI_SetConnectOption(
                        break;
 
                case SQL_AUTOCOMMIT:
+                       if (vParam == SQL_AUTOCOMMIT_ON && CC_is_in_autocommit(conn))
+                               break;
+                       else if (vParam == SQL_AUTOCOMMIT_OFF && !CC_is_in_autocommit(conn))
+                               break;
                        if (CC_is_in_trans(conn))
-                       {
-                               conn->errormsg = "Cannot switch commit mode while a transaction is in progress";
-                               conn->errornumber = CONN_TRANSACT_IN_PROGRES;
-                               CC_log_error(func, "", conn);
-                               return SQL_ERROR;
-                       }
-
+                               CC_commit(conn);
                        mylog("PGAPI_SetConnectOption: AUTOCOMMIT: transact_status=%d, vparam=%d\n", conn->transact_status, vParam);
 
                        switch (vParam)
@@ -475,7 +473,7 @@ PGAPI_GetConnectOption(
                        break;
 
                case SQL_TXN_ISOLATION: /* NOT SUPPORTED */
-                       *((UDWORD *) pvParam) = SQL_TXN_SERIALIZABLE;
+                       *((UDWORD *) pvParam) = SQL_TXN_READ_COMMITTED;
                        break;
 
                        /* These options should be handled by driver manager */
index e73cb82a32568c66cc62c46ea0b32b3b6b245699..525fb736fdf611677ee7814dfdfaa5944345abfa 100644 (file)
@@ -742,7 +742,7 @@ parse_statement(StatementClass *stmt)
                        col_stmt->internal = TRUE;
 
                        result = PGAPI_Columns(hcol_stmt, "", 0, "", 0,
-                                               ti[i]->name, (SWORD) strlen(ti[i]->name), "", 0);
+                                               ti[i]->name, (SWORD) strlen(ti[i]->name), "", 0, PODBC_NOT_SEARCH_PATTERN);
 
                        mylog("        Past PG_Columns\n");
                        if (result == SQL_SUCCESS)
index 2ebf20371ae197efb28310b48a29548fce8fd8d2..3117a6dc379a69e4ecbf3d03b05f20d6fd73994f 100644 (file)
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include <string.h>
 
+#define        PODBC_NOT_SEARCH_PATTERN        1L
 
 RETCODE SQL_API PGAPI_AllocConnect(HENV EnvironmentHandle,
                                   HDBC FAR * ConnectionHandle);
@@ -25,7 +26,8 @@ RETCODE SQL_API PGAPI_Columns(HSTMT StatementHandle,
                          SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
                          SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
                          SQLCHAR *TableName, SQLSMALLINT NameLength3,
-                         SQLCHAR *ColumnName, SQLSMALLINT NameLength4);
+                         SQLCHAR *ColumnName, SQLSMALLINT NameLength4,
+                         UWORD flag);
 RETCODE SQL_API PGAPI_Connect(HDBC ConnectionHandle,
                          SQLCHAR *ServerName, SQLSMALLINT NameLength1,
                          SQLCHAR *UserName, SQLSMALLINT NameLength2,
index 1388650a65ee6f97e6706a163743ccf585320ec6..be822a2eb4da18b1103b91930c510ebc5f8893ee 100644 (file)
@@ -51,6 +51,7 @@ Int4 pgtypes_defined[]        = {
                                PG_TYPE_BPCHAR,
                                PG_TYPE_DATE,
                                PG_TYPE_TIME,
+                               PG_TYPE_TIME_WITH_TMZONE,
                                PG_TYPE_DATETIME,
                                PG_TYPE_ABSTIME,
                                PG_TYPE_TIMESTAMP,
@@ -227,7 +228,11 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type)
 
                        /* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */
                case PG_TYPE_INT8:
+#if (ODBCVER >= 0x0300)
+                       return SQL_BIGINT;
+#else
                        return SQL_CHAR;
+#endif /* ODBCVER */
 
                case PG_TYPE_NUMERIC:
                        return SQL_NUMERIC;
@@ -273,7 +278,11 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
        switch (type)
        {
                case PG_TYPE_INT8:
+#if (ODBCVER >= 0x0300)
+                       return SQL_C_SBIGINT;
+#else
                        return SQL_C_CHAR;
+#endif
                case PG_TYPE_NUMERIC:
                        return SQL_C_CHAR;
                case PG_TYPE_INT2:
@@ -287,13 +296,25 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
                case PG_TYPE_FLOAT8:
                        return SQL_C_DOUBLE;
                case PG_TYPE_DATE:
+#if (ODBCVER >= 0x0300)
+                       return SQL_C_TYPE_DATE;
+#else
                        return SQL_C_DATE;
+#endif /* ODBCVER */
                case PG_TYPE_TIME:
+#if (ODBCVER >= 0x0300)
+                       return SQL_C_TYPE_TIME;
+#else
                        return SQL_C_TIME;
+#endif /* ODBCVER */
                case PG_TYPE_ABSTIME:
                case PG_TYPE_DATETIME:
                case PG_TYPE_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
+                       return SQL_C_TYPE_TIMESTAMP;
+#else
                        return SQL_C_TIMESTAMP;
+#endif /* ODBCVER */
                case PG_TYPE_MONEY:
                        return SQL_C_FLOAT;
                case PG_TYPE_BOOL:
@@ -386,7 +407,7 @@ pgtype_to_name(StatementClass *stmt, Int4 type)
 static Int2
 getNumericScale(StatementClass *stmt, Int4 type, int col)
 {
-       Int4            atttypmod;
+       Int4            atttypmod = -1;
        QResultClass *result;
        ColumnInfoClass *flds;
 
@@ -405,12 +426,16 @@ getNumericScale(StatementClass *stmt, Int4 type, int col)
        {
                flds = result->fields;
                if (flds)
-                       return flds->adtsize[col];
-               else
+               {
+                       atttypmod = flds->atttypmod[col];
+                       if (atttypmod < 0 && flds->adtsize[col] > 0)
+                               return flds->adtsize[col];
+               }
+               if (atttypmod < 0)
                        return PG_NUMERIC_MAX_SCALE;
        }
-
-       atttypmod = QR_get_atttypmod(result, col);
+       else 
+               atttypmod = QR_get_atttypmod(result, col);
        if (atttypmod > -1)
                return (atttypmod & 0xffff);
        else
@@ -423,7 +448,7 @@ getNumericScale(StatementClass *stmt, Int4 type, int col)
 static Int4
 getNumericPrecision(StatementClass *stmt, Int4 type, int col)
 {
-       Int4            atttypmod;
+       Int4            atttypmod = -1;
        QResultClass *result;
        ColumnInfoClass *flds;
 
@@ -442,16 +467,20 @@ getNumericPrecision(StatementClass *stmt, Int4 type, int col)
        {
                flds = result->fields;
                if (flds)
-                       return flds->adtsize[col];
-               else
+               {
+                       atttypmod = flds->atttypmod[col];
+                       if (atttypmod < 0 && flds->adtsize[col] > 0)
+                               return flds->adtsize[col];
+               }
+               if (atttypmod < 0)
                        return PG_NUMERIC_MAX_PRECISION;
        }
-
-       atttypmod = QR_get_atttypmod(result, col);
+       else
+               atttypmod = QR_get_atttypmod(result, col);
        if (atttypmod > -1)
                return (atttypmod >> 16) & 0xffff;
        else
-               return (QR_get_display_size(result, col) >= 0 ?
+               return (QR_get_display_size(result, col) > 0 ?
                                QR_get_display_size(result, col) :
                                PG_NUMERIC_MAX_PRECISION);
 }
@@ -586,13 +615,19 @@ getTimestampPrecision(StatementClass *stmt, Int4 type, int col)
                        fixed = 8;
                        break;
                case PG_TYPE_TIME_WITH_TMZONE:
-                       fixed = 11;
+                       if (USE_ZONE)
+                               fixed = 11;
+                       else
+                               fixed = 8;
                        break;
                case PG_TYPE_TIMESTAMP_NO_TMZONE:
                        fixed = 19;
                        break;
                default:
-                       fixed = 22;
+                       if (USE_ZONE)
+                               fixed = 22;
+                       else
+                               fixed = 19;
                        break;
        }
        scale = getTimestampScale(stmt, type, col);
@@ -677,6 +712,8 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
 Int4
 pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
 {
+       int     dsize;
+
        switch (type)
        {
                case PG_TYPE_INT2:
@@ -693,7 +730,8 @@ pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown
                        return 20;                      /* signed: 19 digits + sign */
 
                case PG_TYPE_NUMERIC:
-                       return getNumericPrecision(stmt, type, col) + 2;
+                       dsize = getNumericPrecision(stmt, type, col);
+                       return dsize < 0 ? dsize : dsize + 2;
 
                case PG_TYPE_MONEY:
                        return 15;                      /* ($9,999,999.99) */
@@ -848,6 +886,7 @@ pgtype_auto_increment(StatementClass *stmt, Int4 type)
 
                case PG_TYPE_DATE:
                case PG_TYPE_TIME:
+               case PG_TYPE_TIME_WITH_TMZONE:
                case PG_TYPE_ABSTIME:
                case PG_TYPE_DATETIME:
                case PG_TYPE_TIMESTAMP:
@@ -1013,8 +1052,14 @@ sqltype_to_default_ctype(Int2 sqltype)
                case SQL_LONGVARCHAR:
                case SQL_DECIMAL:
                case SQL_NUMERIC:
+#if (ODBCVER < 0x0300)
                case SQL_BIGINT:
                        return SQL_C_CHAR;
+#else
+                       return SQL_C_CHAR;
+               case SQL_BIGINT:
+                       return SQL_C_SBIGINT;
+#endif
 
                case SQL_BIT:
                        return SQL_C_BIT;
@@ -1041,13 +1086,25 @@ sqltype_to_default_ctype(Int2 sqltype)
                        return SQL_C_BINARY;
 
                case SQL_DATE:
+#if (ODBCVER >= 0x0300)
+                       return SQL_C_TYPE_DATE;
+#else
                        return SQL_C_DATE;
+#endif /* ODBCVER */
 
                case SQL_TIME:
+#if (ODBCVER >= 0x0300)
+                       return SQL_C_TYPE_TIME;
+#else
                        return SQL_C_TIME;
+#endif /* ODBCVER */
 
                case SQL_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
+                       return SQL_C_TYPE_TIMESTAMP;
+#else
                        return SQL_C_TIMESTAMP;
+#endif /* ODBCVER */
 
                default:
                        /* should never happen */
@@ -1091,12 +1148,21 @@ ctype_length(Int2 ctype)
                        return sizeof(UCHAR);
 
                case SQL_C_DATE:
+#if (ODBCVER >= 0x0300)
+               case SQL_C_TYPE_DATE:
+#endif /* ODBCVER */
                        return sizeof(DATE_STRUCT);
 
                case SQL_C_TIME:
+#if (ODBCVER >= 0x0300)
+               case SQL_C_TYPE_TIME:
+#endif /* ODBCVER */
                        return sizeof(TIME_STRUCT);
 
                case SQL_C_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
+               case SQL_C_TYPE_TIMESTAMP:
+#endif /* ODBCVER */
                        return sizeof(TIMESTAMP_STRUCT);
 
                case SQL_C_BINARY:
index 1d276432ce52be7cb41da55e1331f38d603ef7fd..651817921fe34ebea5b8e40b2bbd706a9544017a 100644 (file)
@@ -58,7 +58,7 @@
 #define PG_TYPE_VARCHAR                        1043
 #define PG_TYPE_DATE                   1082
 #define PG_TYPE_TIME                   1083
-#define PG_TYPE_TIMESTAMP_NO_TMZONE 1114               /* since 7.2 */
+#define PG_TYPE_TIMESTAMP_NO_TMZONE    1114            /* since 7.2 */
 #define PG_TYPE_DATETIME               1184
 #define PG_TYPE_TIME_WITH_TMZONE       1266            /* since 7.1 */
 #define PG_TYPE_TIMESTAMP              1296    /* deprecated since 7.0 */
@@ -96,4 +96,5 @@ char     *pgtype_create_params(StatementClass *stmt, Int4 type);
 Int2           sqltype_to_default_ctype(Int2 sqltype);
 Int4           ctype_length(Int2 ctype);
 
+#define        USE_ZONE        FALSE
 #endif
index 5317be324374faeb62689a632c612321bb874576..fc246b8b77ebf4f14f1ac8e92385c29f0513e9ca 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:           See "notice.txt" for copyright and license information.
  *
- * $Id: psqlodbc.h,v 1.56 2001/11/05 17:46:38 momjian Exp $
+ * $Id: psqlodbc.h,v 1.57 2002/02/18 03:16:11 inoue Exp $
  *
  */
 
@@ -72,6 +72,8 @@ typedef UInt4 Oid;
 #ifndef WIN32
 #define stricmp strcasecmp
 #define strnicmp strncasecmp
+#else
+#define snprintf _snprintf
 #endif
 
 /* Driver stuff */
@@ -85,7 +87,7 @@ typedef UInt4 Oid;
 #define DBMS_NAME                                      "PostgreSQL"
 #endif   /* ODBCVER */
 
-#define POSTGRESDRIVERVERSION          "07.01.0009"
+#define POSTGRESDRIVERVERSION          "07.01.0010"
 
 #ifdef WIN32
 #if (ODBCVER >= 0x0300)
index 30a7ff7203d48b05e6ad0ca357bdc85e90c1cf83..5b7b53583ebd17aee3fbaeefdc79b851005cbe01 100644 (file)
@@ -354,8 +354,8 @@ END
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 7,1,0,9
- PRODUCTVERSION 7,1,0,9
+ FILEVERSION 7,1,0,10
+ PRODUCTVERSION 7,1,0,10
  FILEFLAGSMASK 0x3L
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -377,14 +377,14 @@ BEGIN
             VALUE "CompanyName", "Insight Distribution Systems\0"
 #endif
             VALUE "FileDescription", "PostgreSQL Driver\0"
-            VALUE "FileVersion", " 07.01.0009\0"
+            VALUE "FileVersion", " 07.01.0010\0"
             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.01.0009\0"
+            VALUE "ProductVersion", " 07.01.0010\0"
             VALUE "SpecialBuild", "\0"
         END
     END
index ca7a6dee9ea32d0fda3353b154ae7109b35eb239..2cbe64f0b4c4af4b8f7528ad205f54397392dee1 100644 (file)
@@ -279,7 +279,11 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
                mylog("QR_fetch_tuples: past CI_read_fields: num_fields = %d\n", self->num_fields);
 
                if (fetch_cursor)
+               {
+                       if (self->cache_size <= 0)
+                               self->cache_size = ci->drivers.fetch_max;
                        tuple_size = self->cache_size;
+               }
                else
                        tuple_size = TUPLE_MALLOC_INC;
 
@@ -359,17 +363,12 @@ QR_close(QResultClass *self)
                {
                        mylog("QResult: END transaction on conn=%u\n", self->conn);
 
-                       res = CC_send_query(self->conn, "END", NULL);
-
-                       CC_set_no_trans(self->conn);
-
-                       if (res == NULL)
+                       if (!CC_commit(self->conn))
                        {
                                self->status = PGRES_FATAL_ERROR;
                                QR_set_message(self, "Error ending transaction.");
                                return FALSE;
                        }
-                       QR_Destructor(res);
                }
        }
 
index 3bc5a5c0e1accc02794da11a90dfadfe5d21604c..4d221cacc63a253dc9989427792c4423b7db7081 100644 (file)
@@ -1296,7 +1296,7 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
                if (rcnt == 1)
                {
                        QR_set_position(qres, 0);
-                       tuplen = res->tupleField;
+                       tuplen = qres->tupleField;
                        for (i = 0; i < res->num_fields; i++)
                        {
                                if (tupleo[i].value)
@@ -1416,6 +1416,8 @@ SC_pos_update(StatementClass *stmt,
        RETCODE         ret;
        char       *tidval,
                           *oidval;
+       UInt4   offset;
+       Int4    *used;
 
        mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, stmt->result->base, stmt->fi, stmt->ti);
        if (!(res = stmt->result))
@@ -1438,12 +1440,17 @@ SC_pos_update(StatementClass *stmt,
 
        sprintf(updstr, "update \"%s\" set", stmt->ti[0]->name);
        num_cols = stmt->nfld;
+       if (stmt->options.row_offset_ptr)
+               offset = *stmt->options.row_offset_ptr;
+       else
+               offset = 0;
        for (i = upd_cols = 0; i < num_cols; i++)
        {
-               if (bindings[i].used)
+               if (used = bindings[i].used, used != NULL)
                {
-                       mylog("%d used=%d\n", i, *bindings[i].used);
-                       if (*bindings[i].used != SQL_IGNORE)
+                       used += (offset >> 2);
+                       mylog("%d used=%d\n", i, *used);
+                       if (*used != SQL_IGNORE)
                        {
                                if (upd_cols)
                                        sprintf(updstr, "%s, \"%s\" = ?", updstr, stmt->fi[i]->name);
@@ -1468,12 +1475,15 @@ SC_pos_update(StatementClass *stmt,
                if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS)
                        return SQL_ERROR;
                qstmt = (StatementClass *) hstmt;
+               qstmt->options.param_bind_type = stmt->options.bind_size;
+               qstmt->options.param_offset_ptr = stmt->options.row_offset_ptr;
                for (i = j = 0; i < num_cols; i++)
                {
-                       if (bindings[i].used)
+                       if (used = bindings[i].used, used != NULL)
                        {
-                               mylog("%d used=%d\n", i, *bindings[i].used);
-                               if (*bindings[i].used != SQL_IGNORE)
+                               used += (offset >> 2);
+                               mylog("%d used=%d\n", i, *used);
+                               if (*used != SQL_IGNORE)
                                {
                                        PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++j,
                                                                 SQL_PARAM_INPUT, bindings[i].returntype,
@@ -1486,6 +1496,7 @@ SC_pos_update(StatementClass *stmt,
                                }
                        }
                }
+               qstmt->exec_start_row = qstmt->exec_end_row = irow; 
                ret = PGAPI_ExecDirect(hstmt, updstr, strlen(updstr));
                if (ret == SQL_ERROR)
                {
@@ -1533,6 +1544,19 @@ SC_pos_update(StatementClass *stmt,
        }
        else
                ret = SQL_SUCCESS_WITH_INFO;
+       if (stmt->options.rowStatusArray)
+       {
+               switch (ret)
+               {
+                       case SQL_SUCCESS:
+                               stmt->options.rowStatusArray[irow] = SQL_ROW_UPDATED;
+                               break;
+                       case SQL_SUCCESS_WITH_INFO:
+                               stmt->options.rowStatusArray[irow] = SQL_ROW_SUCCESS_WITH_INFO;
+                               break;
+               }
+       }
+
        return ret;
 }
 RETCODE                SQL_API
@@ -1606,6 +1630,18 @@ SC_pos_delete(StatementClass *stmt,
        }
        if (qres)
                QR_Destructor(qres);
+       if (stmt->options.rowStatusArray)
+       {
+               switch (ret)
+               {
+                       case SQL_SUCCESS:
+                               stmt->options.rowStatusArray[irow] = SQL_ROW_DELETED;
+                               break;
+                       case SQL_SUCCESS_WITH_INFO:
+                               stmt->options.rowStatusArray[irow] = SQL_ROW_SUCCESS_WITH_INFO;
+                               break;
+               }
+       }
        return ret;
 }
 RETCODE                SQL_API
@@ -1616,10 +1652,13 @@ SC_pos_add(StatementClass *stmt,
                                add_cols,
                                i;
        HSTMT           hstmt;
+       StatementClass *qstmt;
        QResultClass *res;
        BindInfoClass *bindings = stmt->bindings;
        char            addstr[4096];
        RETCODE         ret;
+       UInt4           offset;
+       Int4            *used;
 
        mylog("POS ADD fi=%x ti=%x\n", stmt->fi, stmt->ti);
        if (!(res = stmt->result))
@@ -1635,12 +1674,20 @@ SC_pos_add(StatementClass *stmt,
        sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name);
        if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS)
                return SQL_ERROR;
+       if (stmt->options.row_offset_ptr)
+               offset = *stmt->options.row_offset_ptr;
+       else
+               offset = 0;
+       qstmt = (StatementClass *) hstmt;
+       qstmt->options.param_bind_type = stmt->options.bind_size;
+       qstmt->options.param_offset_ptr = stmt->options.row_offset_ptr;
        for (i = add_cols = 0; i < num_cols; i++)
        {
-               if (bindings[i].used)
+               if (used = bindings[i].used, used != NULL)
                {
-                       mylog("%d used=%d\n", i, *bindings[i].used);
-                       if (*bindings[i].used != SQL_IGNORE)
+                       used += (offset >> 2);
+                       mylog("%d used=%d\n", i, *used);
+                       if (*used != SQL_IGNORE)
                        {
                                if (add_cols)
                                        sprintf(addstr, "%s, \"%s\"", addstr, stmt->fi[i]->name);
@@ -1661,7 +1708,6 @@ SC_pos_add(StatementClass *stmt,
        }
        if (add_cols > 0)
        {
-               StatementClass *qstmt = (StatementClass *) hstmt;
 
                sprintf(addstr, "%s) values (", addstr);
                for (i = 0; i < add_cols; i++)
@@ -1673,6 +1719,7 @@ SC_pos_add(StatementClass *stmt,
                }
                strcat(addstr, ")");
                mylog("addstr=%s\n", addstr);
+               qstmt->exec_start_row = qstmt->exec_end_row = irow; 
                ret = PGAPI_ExecDirect(hstmt, addstr, strlen(addstr));
                if (ret == SQL_NEED_DATA)               /* must be fixed */
                {
@@ -1718,6 +1765,18 @@ SC_pos_add(StatementClass *stmt,
        else
                ret = SQL_SUCCESS_WITH_INFO;
        PGAPI_FreeStmt(hstmt, SQL_DROP);
+       if (stmt->options.rowStatusArray)
+       {
+               switch (ret)
+               {
+                       case SQL_SUCCESS:
+                               stmt->options.rowStatusArray[irow] = SQL_ROW_ADDED;
+                               break;
+                       case SQL_SUCCESS_WITH_INFO:
+                               stmt->options.rowStatusArray[irow] = SQL_ROW_SUCCESS_WITH_INFO;
+                               break;
+               }
+       }
        return ret;
 }
 
index bfdb8a2fc0185a70d70e24996dafb3cb63abff20..2b2e5f0634e1cc1a8cb931caaa33462e8504f820 100644 (file)
@@ -263,6 +263,9 @@ SC_Constructor(void)
 
                rv->data_at_exec = -1;
                rv->current_exec_param = -1;
+               rv->exec_start_row = -1;
+               rv->exec_end_row = -1;
+               rv->exec_current_row = -1;
                rv->put_data = FALSE;
 
                rv->lobj_fd = -1;
@@ -404,6 +407,9 @@ SC_free_params(StatementClass *self, char option)
                free(self->parameters);
                self->parameters = NULL;
                self->parameters_allocated = 0;
+               self->exec_start_row = -1;
+               self->exec_end_row = -1;
+               self->exec_current_row = -1;
        }
 
        mylog("SC_free_params:  EXIT\n");
@@ -778,10 +784,12 @@ SC_fetch(StatementClass *self)
        if (self->bookmark.buffer)
        {
                char            buf[32];
+               UInt4   offset = self->options.row_offset_ptr ? *self->options.row_offset_ptr : 0;
 
                sprintf(buf, "%ld", SC_get_bookmark(self));
                result = copy_and_convert_field(self, 0, buf,
-                        SQL_C_ULONG, self->bookmark.buffer, 0, self->bookmark.used);
+                        SQL_C_ULONG, self->bookmark.buffer + offset, 0,
+                       self->bookmark.used ? self->bookmark.used + (offset >> 2) : NULL);
        }
 
 #ifdef DRIVER_CURSOR_IMPLEMENT
@@ -892,10 +900,7 @@ SC_execute(StatementClass *self)
 {
        static char *func = "SC_execute";
        ConnectionClass *conn;
-       QResultClass *res;
-       char            ok,
-                               was_ok,
-                               was_nonfatal;
+       char            was_ok, was_nonfatal;
        Int2            oldstatus,
                                numcols;
        QueryInfo       qi;
@@ -920,30 +925,13 @@ SC_execute(StatementClass *self)
                 (!CC_is_in_autocommit(conn) && self->statement_type != STMT_TYPE_OTHER)))
        {
                mylog("   about to begin a transaction on statement = %u\n", self);
-               res = CC_send_query(conn, "BEGIN", NULL);
-               if (QR_aborted(res))
+               if (!CC_begin(conn))
                {
                        self->errormsg = "Could not begin a transaction";
                        self->errornumber = STMT_EXEC_ERROR;
                        SC_log_error(func, "", self);
                        return SQL_ERROR;
                }
-
-               ok = QR_command_successful(res);
-
-               mylog("SC_exec: begin ok = %d, status = %d\n", ok, QR_get_status(res));
-
-               QR_Destructor(res);
-
-               if (!ok)
-               {
-                       self->errormsg = "Could not begin a transaction";
-                       self->errornumber = STMT_EXEC_ERROR;
-                       SC_log_error(func, "", self);
-                       return SQL_ERROR;
-               }
-               else
-                       CC_set_in_trans(conn);
        }
 
        oldstatus = conn->status;
@@ -1008,11 +996,7 @@ SC_execute(StatementClass *self)
                 * transactions must be committed. (Hiroshi, 02/11/2001)
                 */
                if (!self->internal && CC_is_in_autocommit(conn) && CC_is_in_trans(conn))
-               {
-                       res = CC_send_query(conn, "COMMIT", NULL);
-                       QR_Destructor(res);
-                       CC_set_no_trans(conn);
-               }
+                       CC_commit(conn);
        }
 
        conn->status = oldstatus;
index 6cb0f6ccd39fda3a198c5afa7c4801254f23e1aa..534c8db4d8aa4982fa023ae97f342257024e5347 100644 (file)
@@ -75,6 +75,7 @@ typedef enum
 #define STMT_PROGRAM_TYPE_OUT_OF_RANGE                 26
 #define STMT_BAD_ERROR                                                 27
 #define STMT_INVALID_OPTION_IDENTIFIER                                 28
+#define STMT_RETURN_NULL_WITHOUT_INDICATOR                             29
 
 /* statement types */
 enum
@@ -207,6 +208,9 @@ struct StatementClass_
        char       *stmt_with_params;           /* statement after parameter
                                                                                 * substitution */
        int                     stmt_size_limit;
+       int                     exec_start_row;
+       int                     exec_end_row;
+       int                     exec_current_row;
 
        char            pre_executing;  /* This statement is prematurely executing */
        char            inaccurate_result;              /* Current status is PREMATURE but