The version is now 8.2.0204.
authorHiroshi Inoue <inoue@tpf.co.jp>
Sun, 4 Mar 2007 10:41:49 +0000 (10:41 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Sun, 4 Mar 2007 10:41:49 +0000 (10:41 +0000)
. Configure the combination of time.h and sys/time.h.
. Treat the tables in information_schema as system tables.
. Correct the precision of SQL_NUMERIC_STRUCT.
. Change the default max varchar size from 254 to 255.
. Reset the fields information properly in case of SQLMoreResults.
. Implement SQLDescribeParam() also in case of multi-command queries.
. Handle dollar-quotes more properly.
. Provide a make option to link dynamic multithread library.
. Set the default nullablity to TRUE.
. Parse command delimiters(;) more correctly.
. Use QR_get_value_backend_text() or QR_get_value_backend_int()
   instead of QR_get_value_backend_row().
. Apply Parse statement or disallow premature properly.
. Reset current_schema cache in case 'set search_path ..' command
   is issued.

20 files changed:
bind.c
configure.ac
connection.c
convert.c
convert.h
descriptor.c
dlg_specific.c
execute.c
info.c
mylog.c
parse.c
psqlodbc.h
qresult.h
results.c
socket.c
socket.h
statement.c
statement.h
version.h
win32.mak

diff --git a/bind.c b/bind.c
index c2819de5efcbaee5b28fedccca0e39e031d5873a..0ad1fc1e5f1c80c1274c05cc1d3f79c8ee48f15d 100644 (file)
--- a/bind.c
+++ b/bind.c
@@ -370,6 +370,12 @@ ipdopts->parameters[ipar].PGType);
            *pfSqlType = ipdopts->parameters[ipar].SQLType;
        else if (ipdopts->parameters[ipar].PGType)
            *pfSqlType = pgtype_to_concise_type(stmt, ipdopts->parameters[ipar].PGType, PG_STATIC);
+       else
+       {
+           ret = SQL_ERROR;
+           SC_set_error(stmt, STMT_EXEC_ERROR, "Unfortunatley couldn't get this paramater's info", func);
+           goto cleanup;
+       }
    }
 
    if (pcbParamDef)
@@ -468,101 +474,15 @@ inolog("num_params=%d,%d\n", stmt->num_params, stmt->proc_return);
    }
    else
    {
-       const   char *sptr, *tag = NULL;
-       ConnectionClass *conn = SC_get_conn(stmt);
-       size_t  taglen = 0;
-       char    tchar, bchar, escape_in_literal = '\0';
-       char    in_literal = FALSE, in_identifier = FALSE,
-           in_dollar_quote = FALSE, in_escape = FALSE,
-           multi = FALSE, del_found = FALSE;
-       encoded_str encstr;
+       char    multi = FALSE, proc_return = 0;
 
        stmt->proc_return = 0;
-       make_encoded_str(&encstr, conn, stmt->statement);
-       for (sptr = stmt->statement, bchar = '\0'; *sptr; sptr++)
-       {
-           tchar = encoded_nextchar(&encstr);
-           if (ENCODE_STATUS(encstr) != 0) /* multibyte char */
-           {
-               if ((UCHAR) tchar >= 0x80)
-                   bchar = tchar;
-               continue;
-           }
-           if (!multi && del_found)
-           {
-               if (!isspace(tchar))
-                   multi = TRUE;
-           }
-           if (in_dollar_quote)
-           {
-               if (tchar == dollar_quote)
-               {
-                   if (strncmp(sptr, tag, taglen) == 0)
-                   {
-                       in_dollar_quote = FALSE;
-                       tag = NULL;
-                       sptr += taglen;
-                       sptr--;
-                       encoded_position_shift(&encstr, taglen - 1);
-                   }
-               }
-           }
-           else if (in_literal)
-           {
-               if (in_escape)
-                   in_escape = FALSE;
-               else if (tchar == escape_in_literal)
-                   in_escape = TRUE;
-               else if (tchar == literal_quote)
-                   in_literal = FALSE;
-           }
-           else if (in_identifier)
-           {
-               if (tchar == identifier_quote)
-                   in_identifier = FALSE;
-           }
-           else
-           {
-               if (tchar == '?')
-               {
-                   if (0 == *pcpar && bchar == '{')
-                       stmt->proc_return = 1;
-                   (*pcpar)++;
-               }
-               else if (tchar == ';')
-                   del_found = TRUE;
-               else if (tchar == dollar_quote)
-               {
-                   char    *dollar_next;
-
-                   in_dollar_quote = TRUE;
-                   tag = sptr;
-                   taglen = 0; 
-                   if (dollar_next = strchr(sptr + 1, dollar_quote), NULL != dollar_next)
-                   {
-                       taglen = dollar_next - sptr + 1;
-                       sptr = dollar_next;
-                       encoded_position_shift(&encstr, taglen - 1);
-                   }
-               }
-               else if (tchar == literal_quote)
-               {
-                   in_literal = TRUE;
-                   escape_in_literal = CC_get_escape(conn);
-                   if (!escape_in_literal)
-                   {
-                       if (LITERAL_EXT == sptr[-1])
-                           escape_in_literal = ESCAPE_IN_LITERAL;
-                   }
-               }
-               else if (tchar == identifier_quote)
-                   in_identifier = TRUE;
-               if (!isspace(tchar))
-                   bchar = tchar;
-           }
-       }
+       SC_scanQueryAndCountParams(stmt->statement, SC_get_conn(stmt), NULL, pcpar, &multi, &proc_return);
        stmt->num_params = *pcpar;
+       stmt->proc_return = proc_return;
        stmt->multi_statement = multi;
+       if (multi)
+           SC_no_parse_tricky(stmt);
    }
 inolog("num_params=%d,%d\n", stmt->num_params, stmt->proc_return);
    return SQL_SUCCESS;
@@ -1076,7 +996,7 @@ extend_putdata_info(PutDataInfo *self, int num_params, BOOL shrink)
        new_pdata = (PutDataClass *) realloc(self->pdata, sizeof(PutDataClass) * num_params);
        if (!new_pdata)
        {
-           mylog("%s: unable to create %d new pdata from %d old pdata\n", func, num_params, self->allocated);
+           mylog("%s: unable to create new pdata of %d params(%d old pdata)\n", func, num_params, self->allocated);
 
            self->pdata = NULL;
            self->allocated = 0;
index 827691ec235fd2f908dfe47dc544daa00966ede0..7b08422442df817808cc108f18191d25fe1447c3 100644 (file)
@@ -92,8 +92,8 @@ AC_DISABLE_STATIC
 AC_LIBTOOL_DLOPEN
 AC_PROG_LIBTOOL
 
-AC_CHECK_HEADERS([locale.h])
-AC_CHECK_HEADERS([sys/un.h])
+AC_CHECK_HEADERS(locale.h sys/un.h sys/time.h)
+AC_HEADER_TIME
 AC_CHECK_TYPES(ssize_t)
 PGAC_VAR_INT_TIMEZONE
 
index c41309f78861c7e146cc62097279317f27dcb356..d26f7e8a5eab4400179e2c8b1ddad2ec9763d28e 100644 (file)
@@ -295,9 +295,21 @@ CC_conninfo_init(ConnInfo *conninfo)
 #ifdef WIN32
 extern int platformId;
 #endif /* WIN32 */
+
 /*
  *     IMPLEMENTATION CONNECTION CLASS
  */
+
+static void
+reset_current_schema(ConnectionClass *self)
+{
+   if (self->current_schema)
+   {
+       free(self->current_schema);
+       self->current_schema = NULL;
+   }
+}
+
 ConnectionClass *
 CC_Constructor()
 {
@@ -621,11 +633,7 @@ CC_cleanup(ConnectionClass *self)
        free(self->server_encoding);
        self->server_encoding = NULL;
    }
-   if (self->current_schema)
-   {
-       free(self->current_schema);
-       self->current_schema = NULL;
-   }
+   reset_current_schema(self);
    /* Free cached table info */
    if (self->col_info)
    {
@@ -1201,10 +1209,34 @@ inolog("return conninfo=%s(%d)\n", conninfo, strlen(conninfo));
 static char CC_initial_log(ConnectionClass *self, const char *func)
 {
    const ConnInfo  *ci = &self->connInfo;
-   char    *encoding;
+   char    *encoding, vermsg[128];
 
-   qlog("Global Options: Version='%s', fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
-        POSTGRESDRIVERVERSION,
+   snprintf(vermsg, sizeof(vermsg), "Driver Version='%s,%s'"
+#ifdef WIN32
+       " linking"
+#ifdef _MT
+#ifdef _DLL
+       " dynamic"
+#else
+       " static"
+#endif /* _DLL */
+       " Multithread"
+#else
+       " Singlethread"
+#endif /* _MT */
+#ifdef NOT_USED
+#ifdef _DEBUG
+       " Debug"
+#else
+       " Release"
+#endif /* DEBUG */
+#endif /* NOT_USED */
+       " library"
+#endif /* WIN32 */
+       "\n", POSTGRESDRIVERVERSION, PG_BUILD_VERSION);
+   qlog(vermsg);
+   mylog(vermsg);
+   qlog("Global Options: fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
         ci->drivers.fetch_max,
         ci->drivers.socket_buffersize,
         ci->drivers.unknown_sizes,
@@ -2052,6 +2084,23 @@ mylog("CC_on_abort_partial in\n");
    CONNLOCK_RELEASE(conn);
 }
 
+static BOOL
+is_setting_search_path(const UCHAR* query)
+{
+   for (query += 4; *query; query++)
+   {
+       if (!isspace(*query))
+       {
+           if (strnicmp(query, "search_path", 11) == 0)
+               return TRUE;
+           query++;
+           while (*query && !isspace(*query))
+               query++;
+       }
+   }
+   return FALSE;
+}
+
 /*
  * The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
  * the same existing QResultClass (this occurs when the tuple cache is depleted and
@@ -2298,7 +2347,16 @@ inolog("Discarded the first SAVEPOINT\n");
                            res->recent_processed_row_count = atoi(ptr + 1);
                        else
                            res->recent_processed_row_count = -1;
-                        if (!PROTOCOL_74(&(self->connInfo)))
+                       if (PROTOCOL_74(&(self->connInfo)))
+                       {
+                           if (NULL != self->current_schema &&
+                               strnicmp(cmdbuffer, "SET", 3) == 0)
+                           {
+                               if (is_setting_search_path(query))
+                                   reset_current_schema(self);
+                           }
+                       }
+                       else
                        {
                            if (strnicmp(cmdbuffer, "COMMIT", 6) == 0)
                                CC_on_commit(self);
index e73d73197619e2c24a1f755ac06c8f1f7bb37175..4a6755f00a37af8725b145d07bed5ad8b481594d 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -1312,8 +1312,7 @@ inolog("2stime fr=%d\n", std_time.fr);
                {
                    if (dot_exist)
                        ns->scale++;
-                   else
-                       ns->precision++;
+                   ns->precision++;
                    calv[nlen++] = *wv;
                }
            }
@@ -2252,8 +2251,11 @@ RETCODE  prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
    BOOL        ret;
    ConnectionClass *conn = SC_get_conn(stmt);
    QResultClass    *res;
-   char        plan_name[32];
+   char        plan_name[32], multi;
    int     func_cs_count = 0;
+   const char  *orgquery, *srvquery;
+   Int4        endp1, endp2;
+   SQLSMALLINT num_pa = 0, num_p1, num_p2;
 
 inolog("prep_params\n");
    qb->flags |= FLGB_BUILDING_PREPARE_STATEMENT;
@@ -2277,8 +2279,19 @@ inolog("prep_params\n");
    else
        strcpy(plan_name, NULL_STRING);
 
-   ret = SendParseRequest(stmt, plan_name, qb->query_statement);
-   QB_Destructor(qb);
+   stmt->current_exec_param = 0;
+   multi = stmt->multi_statement;
+   if (multi > 0)
+   {
+       orgquery = stmt->statement;
+       SC_scanQueryAndCountParams(orgquery, conn, &endp1, &num_p1, NULL, NULL);
+       srvquery = qb->query_statement;
+       SC_scanQueryAndCountParams(srvquery, conn, &endp2, NULL, NULL, NULL);
+       mylog("%s:SendParseRequest for the first command length=%d(%d) num_p=%d\n", func, endp2, endp1, num_p1);
+       ret = SendParseRequest(stmt, plan_name, srvquery, endp2, num_p1);
+   }
+   else
+       ret = SendParseRequest(stmt, plan_name, qb->query_statement, SQL_NTS, -1);
    if (!ret)
        goto cleanup;
    if (!SendDescribeRequest(stmt, plan_name))
@@ -2291,13 +2304,46 @@ inolog("prep_params\n");
        goto cleanup;
    }
    SC_set_Result(stmt, res);
-   if (QR_command_maybe_successful(res))
+   if (!QR_command_maybe_successful(res))
+   {
+       SC_set_error(stmt, STMT_EXEC_ERROR, "Error while preparing parameters", func);
+       goto cleanup;
+   } 
+   if (stmt->multi_statement <= 0)
+   {
        retval = SQL_SUCCESS;
-   else
-       SC_set_error(stmt, STMT_EXEC_ERROR, "Error while preparing parameters", func); 
+       goto cleanup;
+   }
+   while (multi > 0)
+   {
+       orgquery += (endp1 + 1);
+       srvquery += (endp2 + 1);
+       num_pa += num_p1;
+       SC_scanQueryAndCountParams(orgquery, conn, &endp1, &num_p1, &multi, NULL);
+       SC_scanQueryAndCountParams(srvquery, conn, &endp2, &num_p2, NULL, NULL);
+       mylog("%s:SendParseRequest for the subsequent command length=%d(%d) num_p=%d\n", func, endp2, endp1, num_p1);
+       if (num_p2 > 0)
+       {
+           stmt->current_exec_param = num_pa;
+           ret = SendParseRequest(stmt, plan_name, srvquery, endp2 < 0 ? SQL_NTS : endp2, num_p1);
+           if (!ret)   goto cleanup;
+           if (!SendDescribeRequest(stmt, plan_name))
+               goto cleanup;
+           if (!(res = SendSyncAndReceive(stmt, NULL, "prepare_and_describe")))
+           {
+               SC_set_error(stmt, STMT_EXEC_ERROR, "commnication error while preapreand_describe", func);
+               CC_on_abort(conn, CONN_DEAD);
+               goto cleanup;
+           }
+           QR_Destructor(res);
+       }
+   }
+   retval = SQL_SUCCESS;
 cleanup:
 #undef return
    CLEANUP_FUNC_CONN_CS(func_cs_count, conn);
+   stmt->current_exec_param = -1;
+   QB_Destructor(qb);
    return retval;
 }
 
@@ -2571,6 +2617,30 @@ remove_declare_cursor(QueryBuild *qb, QueryParse *qp)
    qp->declare_pos = 0;
 }
 
+Int4 findTag(const char *tag, char dollar_quote, int ccsc)
+{
+   Int4    taglen = 0;
+   encoded_str encstr;
+   char        tchar;
+   const char  *sptr;
+
+   encoded_str_constr(&encstr, ccsc, tag + 1);
+   for (sptr = tag + 1; *sptr; sptr++)
+   {
+       tchar = encoded_nextchar(&encstr);
+       if (ENCODE_STATUS(encstr) != 0)
+           continue;
+       if (dollar_quote == tchar)
+       {
+           taglen = sptr - tag + 1;
+           break;
+       }
+       if (isspace(tchar))
+           break;
+   }
+   return taglen;
+}
+
 static int
 inner_process_tokens(QueryParse *qp, QueryBuild *qb)
 {
@@ -2753,15 +2823,12 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
    {
        if (oldchar == dollar_quote)
        {
-           char    *next_dollar;
-
-           qp->in_literal = TRUE;
-           qp->in_dollar_quote = TRUE;
-           qp->dollar_tag = F_OldPtr(qp);
-           qp->taglen = 1;
-           if (next_dollar = strchr(F_OldPtr(qp) + 1, dollar_quote), NULL != next_dollar)
+           qp->taglen = findTag(F_OldPtr(qp), dollar_quote, qp->encstr.ccsc);
+           if (qp->taglen > 0)
            {
-               qp->taglen = next_dollar - F_OldPtr(qp) + 1;
+               qp->in_literal = TRUE;
+               qp->in_dollar_quote = TRUE;
+               qp->dollar_tag = F_OldPtr(qp);
                CVT_APPEND_DATA(qb, F_OldPtr(qp), qp->taglen);
                qp->opos += (qp->taglen - 1);
                return SQL_SUCCESS;
@@ -2787,6 +2854,12 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
        }
        else if (oldchar == ';')
        {
+           /*
+            * can't parse multiple statement using protocol V3.
+            * reset the dollar number here in case it is divided
+            * to parse.
+            */
+           qb->dollar_number = 0;
            if (0 != (qp->flags & FLGP_CURSOR_CHECK_OK))
            {
                const char *vp = &(qp->statement[qp->opos + 1]);
@@ -3024,7 +3097,7 @@ cleanup:
 static BOOL
 ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
 {
-   static const int prec[] = {1, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 29, 32, 34, 37, 39};
+   static const int prec[] = {1, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37, 39};
    Int4    i, j, k, ival, vlen, len, newlen;
    UCHAR       calv[40];
    const UCHAR *val = (const UCHAR *) ns->val;
index 685d3653bf468d7d251316e4bfaa11fb41e6e25f..6e2685a8a732d8a6dca811675e083325ea50d086 100644 (file)
--- a/convert.h
+++ b/convert.h
@@ -54,6 +54,7 @@ size_t        convert_from_pgbinary(const UCHAR *value, UCHAR *rgbValue, SQLLEN cbValu
 SQLLEN     pg_hex2bin(const UCHAR *in, UCHAR *out, SQLLEN len);
 int convert_lo(StatementClass *stmt, const void *value, SQLSMALLINT fCType,
     PTR rgbValue, SQLLEN cbValueMax, SQLLEN *pcbValue);
+Int4       findTag(const char *str, char dollar_quote, int ccsc);
 
 #ifdef __cplusplus
 }
index b70d2a3ffb59b1ad02c494d1a723d5771d920804..f51fd9cdc89ff7ab81044ae83ab7db636f8b48a5 100644 (file)
@@ -66,6 +66,7 @@ inolog("FI_Constructor reuse=%d\n", reuse);
    if (reuse)
        FI_Destructor(&self, 1, FALSE);
    memset(self, 0, sizeof(FIELD_INFO));
+   self->nullable = TRUE;
 }
 void   FI_Destructor(FIELD_INFO **fi, int count, BOOL freeFI)
 {
index 94d4f989ae890d3a1a56d960c98af6a4d52945f2..a75b8c9970f92aff76009d1857da9f97d3ccfe3a 100644 (file)
@@ -899,10 +899,6 @@ writeDriverCommoninfo(const char *fileName, const char *sectionName,
    if (ODBCINST_INI == fileName && NULL == sectionName)
        sectionName = DBMS_NAME;
  
-   sprintf(tmp, "%d", comval->fetch_max);
-   SQLWritePrivateProfileString(sectionName,
-                                INI_FETCH, tmp, fileName);
-
    sprintf(tmp, "%d", comval->commlog);
    SQLWritePrivateProfileString(sectionName,
                                 INI_COMMLOG, tmp, fileName);
@@ -911,6 +907,17 @@ writeDriverCommoninfo(const char *fileName, const char *sectionName,
    SQLWritePrivateProfileString(sectionName,
                                 INI_DEBUG, tmp, fileName);
 
+   sprintf(tmp, "%d", comval->fetch_max);
+   SQLWritePrivateProfileString(sectionName,
+                                INI_FETCH, tmp, fileName);
+
+   if (stricmp(ODBCINST_INI, fileName) == 0)
+       return;
+
+   sprintf(tmp, "%d", comval->fetch_max);
+   SQLWritePrivateProfileString(sectionName,
+                                INI_FETCH, tmp, fileName);
+
    sprintf(tmp, "%d", comval->disable_optimizer);
    SQLWritePrivateProfileString(sectionName,
                                 INI_OPTIMIZER, tmp, fileName);
index b99b8fccd949984f6ea9f2dc02c4a29e559eabf5..e12861b807b31b89c9b344ab83f8957d651d3f26 100644 (file)
--- a/execute.c
+++ b/execute.c
@@ -227,14 +227,13 @@ inquireHowToPrepare(const StatementClass *stmt)
        }
        if (stmt->multi_statement < 0)
            PGAPI_NumParams((StatementClass *) stmt, &num_params);
-       if (stmt->multi_statement > 0) /* server-side prepare mechanism coundn' handle multi statement */
-           return PREPARE_BY_THE_DRIVER;
+       if (stmt->multi_statement > 0) /* would divide the query into multiple commands and apply V3 parse requests for each of them */
+           ret = PARSE_REQ_FOR_INFO;
        else if (PROTOCOL_74(ci))
        {
            if (STMT_TYPE_SELECT == stmt->statement_type)
            {
                if (ci->drivers.use_declarefetch)
-                   /* ret = PREPARE_BY_THE_DRIVER; */
                    return PARSE_REQ_FOR_INFO;
                else if (SQL_CURSOR_FORWARD_ONLY != stmt->options.cursor_type)
                    ret = PARSE_REQ_FOR_INFO;
@@ -335,7 +334,7 @@ inolog("prepare_before_exec=%d srv=%d\n", prepare_before_exec, conn->connInfo.us
    /*
     *  Dummy exection to get the column info.
     */ 
-   if (stmt->inaccurate_result && conn->connInfo.disallow_premature)
+   if (stmt->inaccurate_result && SC_is_parse_tricky(stmt))
    {
        BOOL        in_trans = CC_is_in_trans(conn);
        BOOL        issued_begin = FALSE,
@@ -1378,6 +1377,7 @@ inolog("ipdopts=%p\n", ipdopts);
    if (estmt->data_at_exec == 0)
    {
        BOOL    exec_end;
+       UWORD   flag = SC_is_with_hold(stmt) ? PODBC_WITH_HOLD : 0;
 
        retval = Exec_with_parameters_resolved(estmt, &exec_end);
        if (exec_end)
@@ -1386,7 +1386,7 @@ inolog("ipdopts=%p\n", ipdopts);
            retval = dequeueNeedDataCallback(retval, stmt);
            goto cleanup;
        }
-       if (retval = PGAPI_Execute(estmt, 0), SQL_NEED_DATA != retval)
+       if (retval = PGAPI_Execute(estmt, flag), SQL_NEED_DATA != retval)
        {
            goto cleanup;
        }
diff --git a/info.c b/info.c
index 5ac1ec4958a89942bad0be9d9c5e7ccf9fb84518..0c9b7debcbeeb11ff345c84b5fb74ef76bb7a770 100644 (file)
--- a/info.c
+++ b/info.c
@@ -1819,7 +1819,15 @@ retry_public_schema:
        systable = FALSE;
        if (!atoi(ci->show_system_tables))
        {
-           if (strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0)
+           if (conn->schema_support)
+           {
+               if (stricmp(table_owner, "pg_catalog") == 0 ||
+                   stricmp(table_owner, "pg_toast") == 0 ||
+                   strnicmp(table_owner, "pg_temp_", 8) == 0 ||
+                   stricmp(table_owner, "information_schema") == 0)
+                   systable = TRUE;
+           }
+           else if (strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0)
                systable = TRUE;
 
            else
@@ -3263,7 +3271,7 @@ PGAPI_Statistics(
                    snprintf(cmd, sizeof(cmd), "select pg_get_indexdef(%u, %d, true)", ioid, i);
                    res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN, stmt);
                    if (QR_command_maybe_successful(res))
-                       set_tuplefield_string(&tuple[STATS_COLUMN_NAME], QR_get_value_backend_row(res, 0, 0));
+                       set_tuplefield_string(&tuple[STATS_COLUMN_NAME], QR_get_value_backend_text(res, 0, 0));
                    QR_Destructor(res);
                }
                else
@@ -3784,7 +3792,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName,
        if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, flag, NULL), QR_command_maybe_successful(res))
        {
            if (QR_get_num_cached_tuples(res) > 0)
-               conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
+               conn->server_encoding = strdup(QR_get_value_backend_text(res, 0, 0));
        }
        QR_Destructor(res);
        res = NULL;
@@ -3803,7 +3811,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName,
        {
            if (QR_get_num_cached_tuples(res) > 0)
            {
-               strcpy(saveattnum, QR_get_value_backend_row(res, 0, 0));
+               strcpy(saveattnum, QR_get_value_backend_text(res, 0, 0));
            }
            else
                continueExec = FALSE;
@@ -3824,7 +3832,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName,
    {
        if (QR_get_num_cached_tuples(res) > 0)
        {
-           ret = strdup(QR_get_value_backend_row(res, 0, 0));
+           ret = strdup(QR_get_value_backend_text(res, 0, 0));
            *nameAlloced = TRUE;
        }
    }
@@ -4879,21 +4887,21 @@ PGAPI_ProcedureColumns(
    for (i = 0, poid = 0; i < tcount; i++)
    {
        if (conn->schema_support)
-           schema_name = GET_SCHEMA_NAME(QR_get_value_backend_row(tres, i, 5));
+           schema_name = GET_SCHEMA_NAME(QR_get_value_backend_text(tres, i, 5));
        else
            schema_name = NULL;
-       procname = QR_get_value_backend_row(tres, i, 0);
-       retset = QR_get_value_backend_row(tres, i, 1);
-       pgtype = atoi(QR_get_value_backend_row(tres, i, 2));
+       procname = QR_get_value_backend_text(tres, i, 0);
+       retset = QR_get_value_backend_text(tres, i, 1);
+       pgtype = QR_get_value_backend_int(tres, i, 2, NULL);
        bRetset = retset && (retset[0] == 't' || retset[0] == 'y');
        newpoid = 0;
        if (poid_pos >= 0)
-           newpoid = atoi(QR_get_value_backend_row(tres, i, poid_pos));
+           newpoid = QR_get_value_backend_int(tres, i, poid_pos, NULL);
 mylog("newpoid=%d\n", newpoid);
        atttypid = NULL;
        if (attid_pos >= 0)
        {
-           atttypid = QR_get_value_backend_row(tres, i, attid_pos);
+           atttypid = QR_get_value_backend_text(tres, i, attid_pos);
 mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
        }
        if (poid == 0 || newpoid != poid)
@@ -4905,10 +4913,10 @@ mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
            {
 #ifdef DISPLAY_ARGNAME /* !! named parameter is unavailable !! */
                if (PG_VERSION_GE(conn, 8.0))
-                   proargnames = QR_get_value_backend_row(tres, i, ext_pos);
+                   proargnames = QR_get_value_backend_text(tres, i, ext_pos);
 #endif /* DISPLAY_ARGNAME */
                if (PG_VERSION_GE(conn, 8.1))
-                   proargmodes = QR_get_value_backend_row(tres, i, ext_pos + 1);
+                   proargmodes = QR_get_value_backend_text(tres, i, ext_pos + 1);
            }
            /* RETURN_VALUE info */ 
            if (0 != pgtype && PG_TYPE_VOID != pgtype && !bRetset && !atttypid && !proargmodes)
@@ -4947,7 +4955,7 @@ mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
                        paramcount++;
                }
                paramcount++;
-               params = QR_get_value_backend_row(tres, i, ext_pos + 2);
+               params = QR_get_value_backend_text(tres, i, ext_pos + 2);
                if ('{' == *proargmodes)
                    proargmodes++;
                if ('{' == *params)
@@ -4955,8 +4963,8 @@ mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
            }
            else
            {
-               paramcount = atoi(QR_get_value_backend_row(tres, i, 3));
-               params = QR_get_value_backend_row(tres, i, 4);
+               paramcount = QR_get_value_backend_int(tres, i, 3, NULL);
+               params = QR_get_value_backend_text(tres, i, 4);
            }
            if (proargnames)
            {
@@ -5075,7 +5083,7 @@ mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
            else
            {
                typid = atoi(atttypid);
-               attname = QR_get_value_backend_row(tres, i, attname_pos);
+               attname = QR_get_value_backend_text(tres, i, attname_pos);
            }
            tuple = QR_AddNew(res);
            set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT], CurrCat(conn));
@@ -5249,7 +5257,7 @@ mylog("user=%s auth=%s\n", user, auth);
    if (user[0])
        for (i = 0; i < usercount; i++)
        {
-           if (strcmp(QR_get_value_backend_row(allures, i, 0), user) == 0)
+           if (strcmp(QR_get_value_backend_text(allures, i, 0), user) == 0)
            {
                addcnt += usracl_auth(useracl[i], auth);
                break;
@@ -5414,7 +5422,7 @@ retry_public_schema:
    for (i = 0; i < tablecount; i++)
    { 
        memset(useracl, 0, usercount * sizeof(char[ACLMAX]));
-       acl = (char *) QR_get_value_backend_row(wres, i, 2);
+       acl = (char *) QR_get_value_backend_text(wres, i, 2);
        if (acl && acl[0] == '{')
            user = acl + 1;
        else
@@ -5452,7 +5460,7 @@ retry_public_schema:
                snprintf(proc_query, sizeof(proc_query) - 1, "select grolist from pg_group where groname = '%s'", user);
                if (gres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(gres))
                {
-                   grolist = QR_get_value_backend_row(gres, 0, 0);
+                   grolist = QR_get_value_backend_text(gres, 0, 0);
                    if (grolist && grolist[0] == '{')
                    {
                        for (uid = grolist + 1; *uid;)
@@ -5464,8 +5472,8 @@ retry_public_schema:
 mylog("guid=%s\n", uid);
                            for (i = 0; i < usercount; i++)
                            {
-                               if (strcmp(QR_get_value_backend_row(allures, i, 1), uid) == 0)
-                                   useracl_upd(useracl, allures, QR_get_value_backend_row(allures, i, 0), auth);
+                               if (strcmp(QR_get_value_backend_text(allures, i, 1), uid) == 0)
+                                   useracl_upd(useracl, allures, QR_get_value_backend_text(allures, i, 0), auth);
                            }
                            uid = delm + 1;
                        }
@@ -5479,16 +5487,16 @@ mylog("guid=%s\n", uid);
                break;
            user = delim + 1;
        }
-       reln = QR_get_value_backend_row(wres, i, 0);
-       owner = QR_get_value_backend_row(wres, i, 1);
+       reln = QR_get_value_backend_text(wres, i, 0);
+       owner = QR_get_value_backend_text(wres, i, 1);
        if (conn->schema_support)
-           schnm = QR_get_value_backend_row(wres, i, 3);
+           schnm = QR_get_value_backend_text(wres, i, 3);
        /* The owner has all privileges */
        useracl_upd(useracl, allures, owner, ALL_PRIVILIGES);
        for (j = 0; j < usercount; j++)
        {
-           user = QR_get_value_backend_row(allures, j, 0);
-           su = (strcmp(QR_get_value_backend_row(allures, j, 2), "t") == 0);
+           user = QR_get_value_backend_text(allures, j, 0);
+           su = (strcmp(QR_get_value_backend_text(allures, j, 2), "t") == 0);
            sys = (strcmp(user, owner) == 0);
            /* Super user has all privileges */
            if (su)
diff --git a/mylog.c b/mylog.c
index ab1fa85fdfe9b031e3592e475a75c08e62ca0764..e4068095c3699da22b4798e36bec3514e44e4dad 100644 (file)
--- a/mylog.c
+++ b/mylog.c
@@ -248,6 +248,10 @@ qlog(char *fmt,...)
    if (!qlog_on)   return;
 
    ENTER_QLOG_CS;
+#ifdef LOGGING_PROCESS_TIME
+   if (!start_time)
+       start_time = timeGetTime();
+#endif /* LOGGING_PROCESS_TIME */
    va_start(args, fmt);
 
    if (!QLOGFP)
@@ -259,7 +263,13 @@ qlog(char *fmt,...)
    }
 
    if (QLOGFP)
+   {
+#ifdef LOGGING_PROCESS_TIME
+       DWORD   proc_time = timeGetTime() - start_time;
+       fprintf(QLOGFP, "[%d.%03d]", proc_time / 1000, proc_time % 1000);
+#endif /* LOGGING_PROCESS_TIME */
        vfprintf(QLOGFP, fmt, args);
+   }
 
    va_end(args);
    LEAVE_QLOG_CS;
diff --git a/parse.c b/parse.c
index 5c4c7d58a4f7d4c7054056041d61b77a23180cc7..9d7d87fc140ce38c9be7eb1f5f27f57d880f0670 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -275,18 +275,18 @@ getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
 
 inolog("getColInfo non-manual result\n");
    fi->dquote = TRUE;
-   STR_TO_NAME(fi->column_name, QR_get_value_backend_row(col_info->result, k, COLUMNS_COLUMN_NAME));
+   STR_TO_NAME(fi->column_name, QR_get_value_backend_text(col_info->result, k, COLUMNS_COLUMN_NAME));
 
-   fi->columntype = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_FIELD_TYPE));
-   fi->column_size = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_PRECISION));
-   fi->length = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_LENGTH));
-   if (str = QR_get_value_backend_row(col_info->result, k, COLUMNS_SCALE), str)
+   fi->columntype = (OID) QR_get_value_backend_int(col_info->result, k, COLUMNS_FIELD_TYPE, NULL);
+   fi->column_size = QR_get_value_backend_int(col_info->result, k, COLUMNS_PRECISION, NULL);
+   fi->length = QR_get_value_backend_int(col_info->result, k, COLUMNS_LENGTH, NULL);
+   if (str = QR_get_value_backend_text(col_info->result, k, COLUMNS_SCALE), str)
        fi->decimal_digits = atoi(str);
    else
        fi->decimal_digits = -1;
-   fi->nullable = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_NULLABLE));
-   fi->display_size = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_DISPLAY_SIZE));
-   fi->auto_increment = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_AUTO_INCREMENT));
+   fi->nullable = QR_get_value_backend_int(col_info->result, k, COLUMNS_NULLABLE, NULL);
+   fi->display_size = QR_get_value_backend_int(col_info->result, k, COLUMNS_DISPLAY_SIZE, NULL);
+   fi->auto_increment = QR_get_value_backend_int(col_info->result, k, COLUMNS_AUTO_INCREMENT, NULL);
 }
 
 
@@ -295,7 +295,7 @@ searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
 {
    int         k,
                cmp, attnum;
-   char       *col;
+   const char     *col;
 
 inolog("searchColInfo num_cols=%d col=%s\n", QR_get_num_cached_tuples(col_info->result), PRINT_NAME(fi->column_name));
    if (fi->attnum < 0)
@@ -304,7 +304,7 @@ inolog("searchColInfo num_cols=%d col=%s\n", QR_get_num_cached_tuples(col_info->
    {
        if (fi->attnum > 0)
        {
-           attnum = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_PHYSICAL_NUMBER));
+           attnum = QR_get_value_backend_int(col_info->result, k, COLUMNS_PHYSICAL_NUMBER, NULL);
 inolog("searchColInfo %d attnum=%d\n", k, attnum);
            if (attnum == fi->attnum)
            {
@@ -315,7 +315,7 @@ inolog("searchColInfo %d attnum=%d\n", k, attnum);
        }
        else if (NAME_IS_VALID(fi->column_name))
        {
-           col = QR_get_value_backend_row(col_info->result, k, COLUMNS_COLUMN_NAME);
+           col = QR_get_value_backend_text(col_info->result, k, COLUMNS_COLUMN_NAME);
 inolog("searchColInfo %d col=%s\n", k, col);
            if (fi->dquote)
                cmp = strcmp(col, GET_NAME(fi->column_name));
@@ -378,7 +378,7 @@ static BOOL CheckHasOids(StatementClass * stmt)
        stmt->num_key_fields = PG_NUM_NORMAL_KEYS;
        if (1 == QR_get_num_total_tuples(res))
        {
-           char *value = QR_get_value_backend_row(res, 0, 0);
+           const char *value = QR_get_value_backend_text(res, 0, 0);
            if (value && ('f' == *value || '0' == *value))
            {
                hasoids = FALSE;
@@ -394,7 +394,7 @@ static BOOL CheckHasOids(StatementClass * stmt)
                STR_TO_NAME(ti->bestqual, query);
            }
            TI_set_hasoids_checked(ti);
-           ti->table_oid = strtoul(QR_get_value_backend_row(res, 0, 1), NULL, 10);
+           ti->table_oid = (OID) strtoul(QR_get_value_backend_text(res, 0, 1), NULL, 10);
        }
        QR_Destructor(res);
        res = NULL;
@@ -405,9 +405,9 @@ static BOOL CheckHasOids(StatementClass * stmt)
            if (QR_command_maybe_successful(res) && QR_get_num_total_tuples(res) > 0)
            {
                foundKey = TRUE;
-               STR_TO_NAME(ti->bestitem, QR_get_value_backend_row(res, 0, 0));
+               STR_TO_NAME(ti->bestitem, QR_get_value_backend_text(res, 0, 0));
                sprintf(query, "\"%s\" = %%", SAFE_NAME(ti->bestitem));
-               if (PG_TYPE_INT4 == atoi(QR_get_value_backend_row(res, 0, 1)))
+               if (PG_TYPE_INT4 == (OID) QR_get_value_backend_int(res, 0, 1, NULL))
                    strcat(query, "d");
                else
                    strcat(query, "u");
@@ -470,6 +470,29 @@ static void setNumFields(IRDFields *irdflds, size_t numFields)
    irdflds->nfields = (UInt4) numFields;
 }
 
+void SC_initialize_cols_info(StatementClass *stmt, BOOL DCdestroy, BOOL parseReset)
+{
+   IRDFields   *irdflds = SC_get_IRDF(stmt);
+
+   /* Free the parsed table information */
+   if (stmt->ti)
+   {
+       TI_Destructor(stmt->ti, stmt->ntab);
+       free(stmt->ti);
+       stmt->ti = NULL;
+   }
+   stmt->ntab = 0;
+   if (DCdestroy) /* Free the parsed field information */
+       DC_Destructor((DescriptorClass *) SC_get_IRD(stmt));
+   else
+       setNumFields(irdflds, 0);
+   if (parseReset)
+   {
+       stmt->parse_status = STMT_PARSE_NONE;
+       stmt->updatable = FALSE;
+   }
+}
+
 static BOOL allocateFields(IRDFields *irdflds, size_t sizeRequested)
 {
    FIELD_INFO  **fi = irdflds->fi;
@@ -670,7 +693,7 @@ COL_INFO **coli)
                    if (QR_get_num_total_tuples(res) == 1)
                    {
                        tblFound = TRUE;
-                       STR_TO_NAME(*schema_name, QR_get_value_backend_row(res, 0, 0));
+                       STR_TO_NAME(*schema_name, QR_get_value_backend_text(res, 0, 0));
                    }
                }
                QR_Destructor(res);
@@ -854,15 +877,15 @@ inolog("fi=%p greloid=%d col_info=%p\n", wti, greloid, wti->col_info);
            if (res && QR_get_num_cached_tuples(res) > 0)
            {
                if (!greloid)
-                   greloid = strtoul(QR_get_value_backend_row(res, 0, COLUMNS_TABLE_OID), NULL, 10);
+                   greloid = (OID) strtoul(QR_get_value_backend_text(res, 0, COLUMNS_TABLE_OID), NULL, 10);
                if (!wti->table_oid)
                    wti->table_oid = greloid;
                if (NAME_IS_NULL(wti->schema_name))
                    STR_TO_NAME(wti->schema_name, 
-                       QR_get_value_backend_row(res, 0, COLUMNS_SCHEMA_NAME));
+                       QR_get_value_backend_text(res, 0, COLUMNS_SCHEMA_NAME));
                if (NAME_IS_NULL(wti->table_name))
                    STR_TO_NAME(wti->table_name, 
-                       QR_get_value_backend_row(res, 0, COLUMNS_TABLE_NAME));
+                       QR_get_value_backend_text(res, 0, COLUMNS_TABLE_NAME));
            }
 inolog("#2 %p->table_name=%s(%u)\n", wti, PRINT_NAME(wti->table_name), wti->table_oid);
            /*
@@ -887,7 +910,7 @@ inolog("#2 %p->table_name=%s(%u)\n", wti, PRINT_NAME(wti->table_name), wti->tabl
            conn->ntables++;
 
 if (res && QR_get_num_cached_tuples(res) > 0)
-inolog("oid item == %s\n", QR_get_value_backend_row(res, 0, 3));
+inolog("oid item == %s\n", QR_get_value_backend_text(res, 0, 3));
 
            mylog("Created col_info table='%s', ntables=%d\n", PRINT_NAME(wti->table_name), conn->ntables);
            /* Associate a table from the statement with a SQLColumn info */
@@ -905,15 +928,15 @@ cleanup:
        if (res && QR_get_num_cached_tuples(res) > 0)
        {
            if (!greloid)
-               greloid = strtoul(QR_get_value_backend_row(res, 0, COLUMNS_TABLE_OID), NULL, 10);
+               greloid = (OID) strtoul(QR_get_value_backend_text(res, 0, COLUMNS_TABLE_OID), NULL, 10);
            if (!wti->table_oid)
                wti->table_oid = greloid;
            if (NAME_IS_NULL(wti->schema_name))
                STR_TO_NAME(wti->schema_name, 
-                   QR_get_value_backend_row(res, 0, COLUMNS_SCHEMA_NAME));
+                   QR_get_value_backend_text(res, 0, COLUMNS_SCHEMA_NAME));
            if (NAME_IS_NULL(wti->table_name))
                STR_TO_NAME(wti->table_name, 
-                   QR_get_value_backend_row(res, 0, COLUMNS_TABLE_NAME));
+                   QR_get_value_backend_text(res, 0, COLUMNS_TABLE_NAME));
        }
 inolog("#1 %p->table_name=%s(%u)\n", wti, PRINT_NAME(wti->table_name), wti->table_oid);
        if (colatt /* SQLColAttribute case */
@@ -980,14 +1003,7 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids)
    ti = stmt->ti;
 
    allocated_size = irdflds->allocated;
-   setNumFields(irdflds, 0);
-   if (stmt->ntab > 0)
-   {
-       TI_Destructor(stmt->ti, stmt->ntab);
-       free(stmt->ti);
-       stmt->ti = NULL;
-       stmt->ntab = 0;
-   }
+   SC_initialize_cols_info(stmt, FALSE, TRUE);
    stmt->from_pos = -1;
    stmt->where_pos = -1;
 #define    return  DONT_CALL_RETURN_FROM_HERE???
@@ -1299,13 +1315,16 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids)
            mylog("*** setting expression\n");
        } /* in_select end */
 
-       if (in_from)
+       if (in_from || in_where)
        {
-           if (token[0] == ';')
+           if (token[0] == ';') /* end of the first command */
            {
-               in_from = FALSE;
+               in_select = in_from = in_where = in_table = FALSE;
                break;
            }
+       }
+       if (in_from)
+       {
            switch (token[0])
            {
                case '\0':
@@ -1744,11 +1763,7 @@ cleanup:
 #undef return
    if (STMT_PARSE_FATAL == SC_parsed_status(stmt))
    {
-       setNumFields(irdflds, 0);
-       TI_Destructor(stmt->ti, stmt->ntab);
-       free(stmt->ti);
-       stmt->ti = NULL;
-       stmt->ntab = 0;
+       SC_initialize_cols_info(stmt, FALSE, FALSE);
        parse = FALSE;
    }
 
index 7da2c69405d14c0b8103313dbb4c4ac9b2bfe4d8..a6d0af2929ed6c356fdffa670f451a6469def132 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * $Id: psqlodbc.h,v 1.115 2006/11/14 15:29:26 hinoue Exp $
+ * $Id: psqlodbc.h,v 1.116 2007/03/04 10:41:49 hinoue Exp $
  *
  */
 
@@ -423,7 +423,7 @@ void        logs_on_off(int cnopen, int, int);
 #define TEXT_FIELD_SIZE                8190        /* size of text fields
                                                 * (not including null
                                                 * term) */
-#define MAX_VARCHAR_SIZE           254 /* maximum size of a varchar (not
+#define MAX_VARCHAR_SIZE           255 /* maximum size of a varchar (not
                                         * including null term) */
 
 #define PG_NUMERIC_MAX_PRECISION   1000
index 95d0f1309f30fbea7020e31b15ba515dfca39a2f..26308e140abec06148484bab6fbb5e9898342c9d 100644 (file)
--- a/qresult.h
+++ b/qresult.h
@@ -127,6 +127,8 @@ enum {
 /* These functions are for retrieving data from the qresult */
 #define QR_get_value_backend(self, fieldno)    (self->tupleField[fieldno].value)
 #define QR_get_value_backend_row(self, tupleno, fieldno) ((self->backend_tuples + (tupleno * self->num_fields))[fieldno].value)
+#define QR_get_value_backend_text(self, tupleno, fieldno) QR_get_value_backend_row(self, tupleno, fieldno)
+#define QR_get_value_backend_int(self, tupleno, fieldno, isNull) atoi(QR_get_value_backend_row(self, tupleno, fieldno))
 
 /* These functions are used by both manual and backend results */
 #define QR_NumResultCols(self)     (CI_get_num_fields(self->fields))
index 4ba6780afb31f0c7eebd192c4258fe5e80f4ba32..1e4ab29015611a7663401df59be669120d94f7e6 100644 (file)
--- a/results.c
+++ b/results.c
@@ -170,7 +170,7 @@ PGAPI_NumResultCols(
        goto cleanup;
    }
    parse_ok = FALSE;
-   if (!stmt->catalog_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
+   if (!stmt->catalog_result && SC_is_parse_forced(stmt) && stmt->statement_type == STMT_TYPE_SELECT)
    {
        if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
        {
@@ -286,7 +286,7 @@ inolog("answering bookmark info\n");
    fi = NULL;
    if (icol < irdflds->nfields && irdflds->fi)
        fi = irdflds->fi[icol];
-   if (!FI_is_applicable(fi) && !stmt->catalog_result && ci->drivers.parse && STMT_TYPE_SELECT == stmt->statement_type)
+   if (!FI_is_applicable(fi) && !stmt->catalog_result && SC_is_parse_forced(stmt) && STMT_TYPE_SELECT == stmt->statement_type)
    {
        if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
        {
@@ -516,7 +516,7 @@ inolog("answering bookmark info\n");
    if (unknown_sizes == UNKNOWNS_AS_DONTKNOW)
        unknown_sizes = UNKNOWNS_AS_MAX;
 
-   if (!stmt->catalog_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
+   if (!stmt->catalog_result && SC_is_parse_forced(stmt) && stmt->statement_type == STMT_TYPE_SELECT)
    {
        if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
        {
@@ -1894,6 +1894,21 @@ PGAPI_MoreResults(
        SC_set_Curres(stmt, res->next);
    if (res = SC_get_Curres(stmt), res)
    {
+       SQLSMALLINT num_p;
+
+       if (stmt->multi_statement < 0)
+           PGAPI_NumParams(stmt, &num_p);
+       if (stmt->multi_statement > 0)
+       { 
+           const char *cmdstr;
+
+           SC_initialize_cols_info(stmt, FALSE, TRUE);
+           stmt->statement_type = STMT_TYPE_UNKNOWN;
+           if (cmdstr = QR_get_command(res), NULL != cmdstr)
+               stmt->statement_type = statement_type(cmdstr);
+           stmt->join_info = 0;
+           SC_clear_parse_method(stmt);
+       }
        stmt->diag_row_count = res->recent_processed_row_count;
        SC_set_rowset_start(stmt, -1, FALSE);
        stmt->currTuple = -1;
@@ -3054,6 +3069,18 @@ inolog("%s bestitem=%s bestqual=%s\n", func, SAFE_NAME(ti->bestitem), SAFE_NAME(
 
    mylog("selstr=%s\n", selstr);
    qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, 0, stmt);
+#ifdef NOT_USED
+if (qres)
+{
+int    i, j;
+TupleField *tuple = qres->backend_tuples;
+mylog("%s qres=%p backend_tuples=%p\n", func, qres, tuple);
+for (i = 0; i < QR_get_num_cached_tuples(qres); i++)
+for (j = 0; j < qres->num_fields; j++, tuple++)
+mylog("tuple[%d,%d]=(%d,%p)\n", i, j, tuple->len, tuple->value);
+QR_free_memory(qres);
+}
+#endif /* NOT_USED */
 cleanup:
    free(selstr);
    return qres;
@@ -3575,6 +3602,9 @@ QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt), stmt->options.cursor_t
        }
        /* stmt->currTuple = SC_get_rowset_start(stmt) + ridx; */
    }
+#ifdef NOT_USED
+mylog("about to QR_Destructor %p\n", qres);
+#endif /* NOT_USED */
    QR_Destructor(qres);
    return ret;
 }
index f5933b7f642183832fb9ed4b5f135e131ff871ae..1975d53453da27b1c9ed13831c8dbb6655426146 100644 (file)
--- a/socket.c
+++ b/socket.c
 #ifndef WIN32
 #include <stdlib.h>
 #include <string.h>                /* for memset */
-#if defined(TM_IN_SYS_TIME)
+#ifdef TIME_WITH_SYS_TIME
 #include <sys/time.h>
-#else
 #include <time.h>
-#endif /* defined(TM_IN_SYS_TIME) */
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
 #else
 #include <time.h>
+#endif /* HAVE_SYS_TIME_H */
+#endif /* TIME_WITH__SYS_TIME */
 #endif /* WIN32 */
 
 extern GLOBAL_VALUES globals;
@@ -590,7 +593,7 @@ SOCK_get_n_char(SocketClass *self, char *buffer, Int4 len)
 
 
 void
-SOCK_put_n_char(SocketClass *self, char *buffer, Int4 len)
+SOCK_put_n_char(SocketClass *self, const char *buffer, Int4 len)
 {
    int         lf;
 
index 69dbac0e5f09465fcc2b4de8d797ee26e94b9897..b53c4ea93c22bcf65b3eea5fc85b4c00e4cdad47 100644 (file)
--- a/socket.h
+++ b/socket.h
@@ -189,7 +189,7 @@ void        SOCK_Destructor(SocketClass *self);
 char       SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname, long timeout);
 int        SOCK_get_id(SocketClass *self);
 void       SOCK_get_n_char(SocketClass *self, char *buffer, Int4 len);
-void       SOCK_put_n_char(SocketClass *self, char *buffer, Int4 len);
+void       SOCK_put_n_char(SocketClass *self, const char *buffer, Int4 len);
 BOOL       SOCK_get_string(SocketClass *self, char *buffer, Int4 bufsize);
 void       SOCK_put_string(SocketClass *self, const char *string);
 int        SOCK_get_int(SocketClass *self, short len);
index ac7e04eb5aea6fe4c5dd8ee7e60346a9b30a4756..7116a9f43f917d6991482d0b15697cd8487e6cbb 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "bind.h"
 #include "connection.h"
+#include "multibyte.h"
 #include "qresult.h"
 #include "convert.h"
 #include "environ.h"
@@ -325,6 +326,20 @@ static void SC_init_discard_output_params(StatementClass *self)
    if (!conn->connInfo.use_server_side_prepare)
        self->discard_output_params = 1;
 }
+
+static void SC_init_parse_method(StatementClass *self)
+{
+   ConnectionClass *conn = SC_get_conn(self);
+
+   self->parse_method = 0;
+   if (!conn)  return;
+   if (self->catalog_result) return;
+   if (conn->connInfo.drivers.parse)
+       SC_set_parse_forced(self);
+   if (self->multi_statement <= 0 && conn->connInfo.disallow_premature)
+       SC_set_parse_tricky(self);
+}
+
 StatementClass *
 SC_Constructor(ConnectionClass *conn)
 {
@@ -374,6 +389,7 @@ SC_Constructor(ConnectionClass *conn)
        rv->ref_CC_error = FALSE;
        rv->lock_CC_for_rb = 0;
        rv->join_info = 0;
+       SC_init_parse_method(rv);
 
        rv->lobj_fd = -1;
        INIT_NAME(rv->cursor_name);
@@ -443,13 +459,7 @@ SC_Destructor(StatementClass *self)
    SC_initialize_stmts(self, TRUE);
 
         /* Free the parsed table information */
-   if (self->ti)
-   {
-       TI_Destructor(self->ti, self->ntab);
-
-       free(self->ti);
-       self->ti = NULL;
-   }
+   SC_initialize_cols_info(self, FALSE, TRUE);
 
    NULL_THE_NAME(self->cursor_name);
    /* Free the parsed field information */
@@ -621,10 +631,10 @@ SC_set_prepared(StatementClass *stmt, BOOL prepared)
 RETCODE
 SC_initialize_stmts(StatementClass *self, BOOL initializeOriginal)
 {
+   ConnectionClass *conn = SC_get_conn(self);
+
    if (self->lock_CC_for_rb > 0)
    {
-       ConnectionClass *conn = SC_get_conn(self);
-
        while (self->lock_CC_for_rb > 0)
        {
            LEAVE_CONN_CS(conn);
@@ -650,6 +660,7 @@ SC_initialize_stmts(StatementClass *self, BOOL initializeOriginal)
        self->num_params = -1; /* unknown */
        self->proc_return = -1; /* unknown */
        self->join_info = 0;
+       SC_init_parse_method(self);
        SC_init_discard_output_params(self);
    }
    if (self->stmt_with_params)
@@ -748,7 +759,7 @@ SC_recycle_statement(StatementClass *self)
             */
            if (!CC_is_in_autocommit(conn) && CC_is_in_trans(conn))
            {
-               if (SC_is_pre_executable(self) && !conn->connInfo.disallow_premature)
+               if (SC_is_pre_executable(self) && !SC_is_parse_tricky(self))
                    CC_abort(conn);
            }
            break;
@@ -765,20 +776,11 @@ SC_recycle_statement(StatementClass *self)
    {
        case NOT_YET_PREPARED:
        case ONCE_DESCRIBED:
-               /* Free the parsed table information */
-           if (self->ti)
-           {
-               TI_Destructor(self->ti, self->ntab);
-               free(self->ti);
-               self->ti = NULL;
-               self->ntab = 0;
-           }
-           /* Free the parsed field information */
-           DC_Destructor((DescriptorClass *) SC_get_IRD(self));
+               /* Free the parsed table/field information */
+           SC_initialize_cols_info(self, TRUE, TRUE);
 
 inolog("SC_clear_parse_status\n");
            SC_clear_parse_status(self, conn);
-           self->updatable = FALSE;
            break;
    }
 
@@ -836,6 +838,131 @@ inolog("%s statement=%p ommitted=0\n", func, self);
    return TRUE;
 }
 
+/*
+ * Scan the query wholly or partially (if specifed next_cmd).
+ * Also count the number of parameters respectviely.
+ */
+void
+SC_scanQueryAndCountParams(const char *query, const ConnectionClass *conn,
+       Int4 *next_cmd, SQLSMALLINT * pcpar,
+       char *multi_st, char *proc_return)
+{
+   CSTR func = "SC_scanQueryAndCountParams";
+   char    literal_quote = LITERAL_QUOTE, identifier_quote = IDENTIFIER_QUOTE, dollar_quote = DOLLAR_QUOTE;
+   const   char *sptr, *tstr, *tag = NULL;
+   size_t  taglen = 0;
+   char    tchar, bchar, escape_in_literal = '\0';
+   char    in_literal = FALSE, in_identifier = FALSE,
+       in_dollar_quote = FALSE, in_escape = FALSE,
+       del_found = FALSE, multi = FALSE;
+   SQLSMALLINT num_p;
+   encoded_str encstr;
+
+   mylog("%s: entering...\n", func);
+   num_p = 0;
+   if (proc_return)
+       *proc_return = 0;
+   if (next_cmd)
+       *next_cmd = -1;
+   tstr = query;
+   make_encoded_str(&encstr, conn, tstr);
+   for (sptr = tstr, bchar = '\0'; *sptr; sptr++)
+   {
+       tchar = encoded_nextchar(&encstr);
+       if (ENCODE_STATUS(encstr) != 0) /* multibyte char */
+       {
+           if ((UCHAR) tchar >= 0x80)
+               bchar = tchar;
+           continue;
+       }
+       if (!multi && del_found)
+       {
+           if (!isspace(tchar))
+           {
+               multi = TRUE;
+               if (next_cmd)
+                   break;
+           }
+       }
+       if (in_dollar_quote)
+       {
+           if (tchar == dollar_quote)
+           {
+               if (strncmp(sptr, tag, taglen) == 0)
+               {
+                   in_dollar_quote = FALSE;
+                   tag = NULL;
+                   sptr += taglen;
+                   sptr--;
+                   encoded_position_shift(&encstr, taglen - 1);
+               }
+           }
+       }
+       else if (in_literal)
+       {
+           if (in_escape)
+               in_escape = FALSE;
+           else if (tchar == escape_in_literal)
+               in_escape = TRUE;
+           else if (tchar == literal_quote)
+               in_literal = FALSE;
+       }
+       else if (in_identifier)
+       {
+           if (tchar == identifier_quote)
+               in_identifier = FALSE;
+       }
+       else
+       {
+           if (tchar == '?')
+           {
+               if (0 == num_p && bchar == '{')
+               {
+                   if (proc_return)
+                       *proc_return = 1;
+               }
+               num_p++;
+           }
+           else if (tchar == ';')
+           {
+               del_found = TRUE;
+               if (next_cmd)
+                   *next_cmd = sptr - query;
+           }
+           else if (tchar == dollar_quote)
+           {
+               taglen = findTag(sptr, dollar_quote, encstr.ccsc);
+               if (taglen > 0)
+               {
+                   in_dollar_quote = TRUE;
+                   tag = sptr;
+                   sptr += (taglen - 1);
+                   encoded_position_shift(&encstr, taglen - 1);
+               }
+               else
+                   num_p++;
+           }
+           else if (tchar == literal_quote)
+           {
+               in_literal = TRUE;
+               escape_in_literal = CC_get_escape(conn);
+               if (!escape_in_literal)
+               {
+                   if (LITERAL_EXT == sptr[-1])
+                       escape_in_literal = ESCAPE_IN_LITERAL;
+               }
+           }
+           else if (tchar == identifier_quote)
+               in_identifier = TRUE;
+           if (!isspace(tchar))
+               bchar = tchar;
+       }
+   }
+   if (pcpar)
+       *pcpar = num_p;
+   if (multi_st)
+       *multi_st = multi;
+}
 
 /*
  * Pre-execute a statement (for SQLPrepare/SQLDescribeCol) 
@@ -972,7 +1099,7 @@ static struct
    { STMT_ROW_VERSION_CHANGED,  "01001", "01001" }, /* data changed */
    { STMT_POS_BEFORE_RECORDSET, "01S06", "01S06" },
    { STMT_TRUNCATED, "01004", "01004" }, /* data truncated */
-   { STMT_INFO_ONLY, "00000", "00000" }, /* just information that is returned, no error */
+   { STMT_INFO_ONLY, "00000", "00000" }, /* just an information that is returned, no error */
 
    { STMT_OK,  "00000", "00000" }, /* OK */
    { STMT_EXEC_ERROR, "HY000", "S1000" }, /* also a general error */
@@ -1900,7 +2027,7 @@ inolog("!!SC_fetch return =%d\n", ret);
                {
                    apara = apdopts->parameters + i;    
                    ret = PGAPI_GetData(hstmt, gidx + 1, apara->CType, apara->buffer + offset, apara->buflen, apara->used ? LENADDR_SHIFT(apara->used, offset) : NULL);
-                   if (ret != SQL_SUCCESS)
+                   if (SQL_SUCCESS != ret && SQL_SUCCESS_WITH_INFO != ret)
                    {
                        SC_set_error(self, STMT_EXEC_ERROR, "GetData to Procedure return failed.", func);
                        break;
@@ -1924,7 +2051,7 @@ cleanup:
    /* self->status = STMT_FINISHED; */
    if (SC_get_errornumber(self) == STMT_OK)
        return SQL_SUCCESS;
-   else if (SC_get_errornumber(self) == STMT_INFO_ONLY)
+   else if (SC_get_errornumber(self) < STMT_OK)
        return SQL_SUCCESS_WITH_INFO;
    else
    {
@@ -2106,7 +2233,7 @@ QResultClass *SendSyncAndReceive(StatementClass *stmt, QResultClass *res, const
    Int4        response_length;
    UInt4       oid;
    int     num_p, num_io_params;
-   int     i;
+   int     i, pidx;
    Int2        num_discard_params, paramType;
    BOOL        rcvend = FALSE, msg_truncated;
    char        msgbuffer[ERROR_MSG_LENGTH + 1];
@@ -2198,32 +2325,54 @@ inolog("num_params=%d info=%d\n", stmt->num_params, num_p);
                    num_discard_params = stmt->proc_return;
                if (num_p + num_discard_params != (int) stmt->num_params)
                {
-                   mylog("ParamInfo unmatch num_params=%d! info=%d+discard=%d\n", stmt->num_params, num_p, num_discard_params);
-                   stmt->num_params = (Int2) num_p + num_discard_params;
+                   mylog("ParamInfo unmatch num_params(=%d) != info(=%d)+discard(=%d)\n", stmt->num_params, num_p, num_discard_params);
+                   /* stmt->num_params = (Int2) num_p + num_discard_params; it's possible in case of multi command queries */
                }
                ipdopts = SC_get_IPDF(stmt);
                extend_iparameter_bindings(ipdopts, stmt->num_params);
+#ifdef NOT_USED
                if (stmt->discard_output_params)
                {
-                   for (i = stmt->proc_return; i < stmt->num_params; i++)
+                   for (i = 0, pidx = stmt->proc_return; i < num_p && pidx < stmt->num_params; pidx++)
                    {
-                       paramType = ipdopts->parameters[i].paramType;
+                       paramType = ipdopts->parameters[pidx].paramType;
                        if (SQL_PARAM_OUTPUT == paramType)
+                       {
+                           i++;
                            continue;
+                       }
                        oid = SOCK_get_int(sock, 4);
-                       ipdopts->parameters[i].PGType = oid;
+                       ipdopts->parameters[pidx].PGType = oid;
                    }
                }
                else
                {
-                   for (i = 0; i < num_p; i++)
+                   for (i = 0, pidx = stmt->proc_return; i < num_p; i++, pidx++)
                    {
-                       paramType = ipdopts->parameters[i].paramType;   
+                       paramType = ipdopts->parameters[pidx].paramType;    
                        oid = SOCK_get_int(sock, 4);
                        if (SQL_PARAM_OUTPUT != paramType ||
                            PG_TYPE_VOID != oid)
-                           ipdopts->parameters[i + stmt->proc_return].PGType = oid;
+                           ipdopts->parameters[pidx].PGType = oid;
+                   }
+               }
+#endif /* NOT_USED */
+               pidx = stmt->current_exec_param;
+               if (pidx >= 0)
+                   pidx--;
+               for (i = 0; i < num_p; i++)
+               {
+                   SC_param_next(stmt, &pidx, NULL, NULL);
+                   if (pidx >= stmt->num_params)
+                   {
+                       mylog("%dth parameter's position(%d) is out of bound[%d]\n", i, pidx, stmt->num_params);
+                       break;
                    }
+                   oid = SOCK_get_int(sock, 4);
+                   paramType = ipdopts->parameters[pidx].paramType;    
+                   if (SQL_PARAM_OUTPUT != paramType ||
+                       PG_TYPE_VOID != oid)
+                       ipdopts->parameters[pidx].PGType = oid;
                }
                break;
            case 'T': /* RowDesription */
@@ -2283,14 +2432,16 @@ inolog("!![%d].PGType %u->%u\n", i, ipdopts->parameters[i].PGType, CI_get_oid(re
 }
 
 BOOL
-SendParseRequest(StatementClass *stmt, const char *plan_name, const char *query)
+SendParseRequest(StatementClass *stmt, const char *plan_name, const char *query, Int4 qlen, Int2 num_params)
 {
    CSTR    func = "SendParseRequest";
    ConnectionClass *conn = SC_get_conn(stmt);
    SocketClass *sock = conn->sock;
+   Int4        sta_pidx, end_pidx;
    size_t      pileng, leng;
 
    mylog("%s: plan_name=%s query=%s\n", func, plan_name, query);
+   qlog("%s: plan_name=%s query=%s\n", func, plan_name, query);
    if (!RequestStart(stmt, conn, func))
        return FALSE;
 
@@ -2303,20 +2454,53 @@ SendParseRequest(StatementClass *stmt, const char *plan_name, const char *query)
    }
 
    pileng = sizeof(Int2);
-   if (!stmt->discard_output_params)
-       pileng += sizeof(UInt4) * (stmt->num_params - stmt->proc_return); 
-   leng = strlen(plan_name) + 1 + strlen(query) + 1 + pileng;
+   if (stmt->discard_output_params)
+       num_params = 0;
+   else if (num_params != 0)
+   {
+#ifdef NOT_USED
+       sta_pidx += stmt->proc_return;
+#endif /* NOT_USED */
+       int pidx;
+
+       sta_pidx = stmt->current_exec_param;
+       if (num_params < 0)
+           end_pidx = stmt->num_params - 1;
+       else
+           end_pidx = sta_pidx + num_params - 1;
+#ifdef NOT_USED
+       num_params = end_pidx - sta_pidx + 1;
+#endif /* NOT_USED */
+       for (num_params = 0, pidx = sta_pidx - 1;;)
+       {
+           SC_param_next(stmt, &pidx, NULL, NULL);
+           if (pidx > end_pidx)
+               break;
+           else if (pidx < end_pidx)
+               num_params++;
+           else
+           {
+               num_params++;
+               break;
+           }
+       }
+mylog("sta_pidx=%d end_pidx=%d num_p=%d\n", sta_pidx, end_pidx, num_params);
+       pileng += (sizeof(UInt4) * num_params);
+   }
+   qlen = (SQL_NTS == qlen) ? strlen(query) : qlen; 
+   leng = strlen(plan_name) + 1 + qlen + 1 + pileng;
    SOCK_put_int(sock, (Int4) (leng + 4), 4); /* length */
 inolog("parse leng=%d\n", leng);
    SOCK_put_string(sock, plan_name);
-   SOCK_put_string(sock, query);
-   SOCK_put_int(sock, stmt->num_params - stmt->proc_return, sizeof(Int2)); /* number of parameters unspecified */
-   if (!stmt->discard_output_params)
+   SOCK_put_n_char(sock, query, qlen);
+   SOCK_put_char(sock, '\0');
+   SOCK_put_int(sock, num_params, sizeof(Int2)); /* number of parameters specified */
+   if (num_params > 0)
    {
        int i;
        IPDFields   *ipdopts = SC_get_IPDF(stmt);
 
-       for (i = stmt->proc_return; i < stmt->num_params; i++)
+       for (i = sta_pidx; i <= end_pidx; i++)
        {
            if (i < ipdopts->allocated &&
                SQL_PARAM_OUTPUT == ipdopts->parameters[i].paramType)
@@ -2388,6 +2572,7 @@ SendExecuteRequest(StatementClass *stmt, const char *plan_name, UInt4 count)
    if (sock = conn->sock, !sock)   return FALSE;
 
    mylog("%s: plan_name=%s count=%d\n", func, plan_name, count);
+   qlog("%s: plan_name=%s count=%d\n", func, plan_name, count);
    if (!SC_is_fetchcursor(stmt))
    {
        switch (stmt->prepared)
@@ -2411,10 +2596,10 @@ SendExecuteRequest(StatementClass *stmt, const char *plan_name, UInt4 count)
    }
 
    leng = strlen(plan_name) + 1 + 4;
-   SOCK_put_int(sock, (Int4) (leng + 4), 4); /* length */
+   SOCK_put_int(sock, (Int4) (leng + 4), sizeof(Int4)); /* length */
 inolog("execute leng=%d\n", leng);
-   SOCK_put_string(sock, plan_name);
-   SOCK_put_int(sock, count, 4);
+   SOCK_put_string(sock, plan_name);   /* portal name == plan name */
+   SOCK_put_int(sock, count, sizeof(Int4));
    if (0 == count) /* will send a Close portal command */
    {
        SOCK_put_char(sock, 'C');   /* Close command */
index 0e2beee59c7e5d1bb384d67cf12c1ba24009781e..441183fa5978152b811faa3159130fba4c14e324 100644 (file)
@@ -210,12 +210,14 @@ struct StatementClass_
    TABLE_INFO  **ti;
    Int2        ntab;
    Int2        num_key_fields;
-   char        parse_status;
-   char        proc_return;
    Int2        statement_type; /* According to the defines above */
-   int     current_exec_param;     /* The current parameter for
-                            * SQLPutData */
+   Int2        num_params;
+   Int2        data_at_exec; /* Number of params needing SQLPutData */
+   Int2        current_exec_param; /* The current parameter for
+                        * SQLPutData */
    PutDataInfo pdata_info;
+   char        parse_status;
+   char        proc_return;
    char        put_data;   /* Has SQLPutData been called ? */
    char        catalog_result; /* Is this a result of catalog function ? */
    char        prepare;    /* is this a prepared statement ? */
@@ -231,10 +233,9 @@ struct StatementClass_
    char        ref_CC_error;   /* refer to CC_error ? */
    char        lock_CC_for_rb; /* lock CC for statement rollback ? */
    char        join_info;  /* have joins ? */
+   char        parse_method;   /* parse_statement is forced or ? */
    pgNAME      cursor_name;
    char        *plan_name;
-   Int2        num_params;
-   Int2        data_at_exec; /* Number of params needing SQLPutData */
 
    char        *stmt_with_params;  /* statement after parameter
                             * substitution */
@@ -313,6 +314,13 @@ do { \
 #define    SC_checked_hasoids(a)   (0 != (a->parse_status & STMT_PARSED_OIDS))
 #define    SC_set_delegate(p, c) (p->execute_delegate = c, c->execute_parent = p)
 
+#define    SC_clear_parse_method(s)    ((s)->parse_method = 0)
+#define    SC_is_parse_forced(s)   (0 != ((s)->parse_method & 1L))
+#define    SC_set_parse_forced(s)  ((s)->parse_method |= 1L)
+#define    SC_is_parse_tricky(s)   (0 != ((s)->parse_method & 2L))
+#define    SC_set_parse_tricky(s)  ((s)->parse_method |= 2L)
+#define    SC_no_parse_tricky(s)   ((s)->parse_method &= ~2L)
+
 #define    SC_cursor_is_valid(s)   (NAME_IS_VALID(s->cursor_name))
 #define    SC_cursor_name(s)   (SAFE_NAME(s->cursor_name))
 
@@ -428,6 +436,7 @@ void        InitializeStatementOptions(StatementOptions *opt);
 char       SC_Destructor(StatementClass *self);
 BOOL       SC_opencheck(StatementClass *self, const char *func);
 RETCODE        SC_initialize_and_recycle(StatementClass *self);
+void       SC_initialize_cols_info(StatementClass *self, BOOL DCdestroy, BOOL parseReset);
 int        statement_type(const char *statement);
 char       parse_statement(StatementClass *stmt, BOOL);
 Int4       SC_pre_execute(StatementClass *self);
@@ -458,6 +467,9 @@ RETCODE     SC_pos_refresh(StatementClass *self, SQLSETPOSIROW irow, SQLULEN index)
 RETCODE        SC_pos_add(StatementClass *self, SQLSETPOSIROW irow);
 int        SC_set_current_col(StatementClass *self, int col);
 void       SC_setInsertedTable(StatementClass *, RETCODE);
+void       SC_scanQueryAndCountParams(const char *, const ConnectionClass *,
+           Int4 *next_cmd, SQLSMALLINT *num_params,
+           char *multi, char *proc_return);
 
 BOOL   SC_IsExecuting(const StatementClass *self);
 BOOL   SC_SetExecuting(StatementClass *self, BOOL on);
@@ -474,7 +486,7 @@ RETCODE     SetStatementSvp(StatementClass *self);
 RETCODE        DiscardStatementSvp(StatementClass *self, RETCODE, BOOL errorOnly);
 
 BOOL       SendParseRequest(StatementClass *self, const char *name,
-               const char *query);
+           const char *query, Int4 qlen, Int2 num_params);
 BOOL       SendDescribeRequest(StatementClass *self, const char *name);
 BOOL       SendBindRequest(StatementClass *self, const char *name);
 BOOL       BuildBindRequest(StatementClass *stmt, const char *name);
index 8ddd82de2a3d6f1c2dc2463f097698ca2efa508f..a3ca83074607ef68849ad646410b2a1f7326b364 100644 (file)
--- a/version.h
+++ b/version.h
@@ -9,8 +9,9 @@
 #ifndef __VERSION_H__
 #define __VERSION_H__
 
-#define POSTGRESDRIVERVERSION      "08.02.0203"
-#define POSTGRES_RESOURCE_VERSION  "08.02.0203\0"
-#define PG_DRVFILE_VERSION     8,2,02,03 
+#define POSTGRESDRIVERVERSION      "08.02.0204"
+#define POSTGRES_RESOURCE_VERSION  "08.02.0204\0"
+#define PG_DRVFILE_VERSION     8,2,02,04
+#define PG_BUILD_VERSION       "200703020002"
 
 #endif
index 588f2c15596be9d1db9b7c3c09ae5607c374874c..04921169018fdd02493bfe9a1c030ddbadd78c22 100644 (file)
--- a/win32.mak
+++ b/win32.mak
@@ -59,6 +59,15 @@ SSL_LIB=C:\OpenSSL\lib\VC
 !MESSAGE Using default OpenSSL Library directory: $(SSL_LIB)
 !ENDIF
 
+!IF "$(LINKMT)" == ""
+LINKMT=MT
+!ENDIF
+!IF "$(LINKMT)" == "MT"
+!MESSAGE Linking static Multithread library
+!ELSE
+!MESSAGE Linking dynamic Multithread library
+!ENDIF
+
 SSL_DLL = "SSLEAY32.dll"
 ADD_DEFINES = $(ADD_DEFINES) /D "SSL_DLL=\"$(SSL_DLL)\""
 
@@ -148,11 +157,13 @@ CLEAN :
 "$(OUTDIR)" :
     if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
 
+$(INTDIR)\connection.obj $(INTDIR)\psqlodbc.res: version.h
+
 CPP=cl.exe
 !IF  "$(CFG)" == "Release"
-CPP_PROJ=/nologo /MT /W3 /GX /O2 /I "$(PG_INC)" /I "$(SSL_INC)" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_CRT_SECURE_NO_DEPRECATE" /D "PSQLODBC_EXPORTS" /D "WIN_MULTITHREAD_SUPPORT" $(ADD_DEFINES) /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+CPP_PROJ=/nologo /$(LINKMT) /W3 /GX /O2 /I "$(PG_INC)" /I "$(SSL_INC)" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_CRT_SECURE_NO_DEPRECATE" /D "PSQLODBC_EXPORTS" /D "WIN_MULTITHREAD_SUPPORT" $(ADD_DEFINES) /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
 !ELSEIF  "$(CFG)" == "Debug"
-CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /I "$(PG_INC)" /I "$(SSL_INC)" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_CRT_SECURE_NO_DEPRECATE" /D "PSQLODBC_EXPORTS" /D "WIN_MULTITHREAD_SUPPORT" $(ADD_DEFINES) /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+CPP_PROJ=/nologo /$(LINKMT)d /W3 /Gm /GX /ZI /Od /I "$(PG_INC)" /I "$(SSL_INC)" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_CRT_SECURE_NO_DEPRECATE" /D "PSQLODBC_EXPORTS" /D "WIN_MULTITHREAD_SUPPORT" $(ADD_DEFINES) /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
 !ENDIF
 
 .c{$(INTDIR)}.obj::