Cleanups about the handing of unnamed parsed statements and the handling
authorHiroshi Inoue <inoue@tpf.co.jp>
Sun, 25 Oct 2009 13:36:31 +0000 (13:36 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Sun, 25 Oct 2009 13:36:31 +0000 (13:36 +0000)
of ODBC escape { .

12 files changed:
bind.c
bind.h
connection.c
connection.h
convert.c
execute.c
info.c
parse.c
psqlodbc.h
statement.c
statement.h
version.h

diff --git a/bind.c b/bind.c
index 32a9170294cad8c0de6bf9a480f3a3722a08f925..4c29e29623c8a21834463b520494c6b6540f90bc 100644 (file)
--- a/bind.c
+++ b/bind.c
@@ -348,7 +348,7 @@ inolog("howTo=%d\n", SC_get_prepare_method(stmt));
            case NAMED_PARSE_REQUEST:
            case PARSE_TO_EXEC_ONCE:
            case PARSE_REQ_FOR_INFO:
-               if (ret = prepareParameters(stmt), SQL_ERROR == ret)
+               if (ret = prepareParameters(stmt, TRUE), SQL_ERROR == ret)
                    goto cleanup;
        }
    }
diff --git a/bind.h b/bind.h
index e36ef292e27aa025fd1fd3184383aedff49a2723..9aee864de3cadb38f7ad5f17b77f4fab57df962b 100644 (file)
--- a/bind.h
+++ b/bind.h
@@ -111,7 +111,7 @@ void    reset_a_putdata_info(PutDataInfo *pdata, int ipar);
 void   PDATA_free_params(PutDataInfo *pdata, char option);
 void   SC_param_next(const StatementClass*, int *param_number, ParameterInfoClass **, ParameterImplClass **);
 
-RETCODE       prepareParameters(StatementClass *stmt);
+RETCODE       prepareParameters(StatementClass *stmt, BOOL sync);
 int    decideHowToPrepare(StatementClass *stmt, BOOL force);
 
 #endif
index 3080c3722e0984c4ae439c91f886ddc70f9b791e..dda67d6cd45b0cd6ee04b059064dc8500d940fe0 100644 (file)
@@ -307,6 +307,7 @@ CC_Constructor()
    {
        rv->status = CONN_NOT_CONNECTED;
        rv->transact_status = CONN_IN_AUTOCOMMIT;       /* autocommit by default */
+       rv->stmt_in_extquery = NULL;
 
        CC_conninfo_init(&(rv->connInfo));
        rv->sock = SOCK_Constructor(rv);
@@ -601,6 +602,7 @@ CC_cleanup(ConnectionClass *self)
 
    self->status = CONN_NOT_CONNECTED;
    self->transact_status = CONN_IN_AUTOCOMMIT;
+   self->stmt_in_extquery = NULL;
    CC_conninfo_init(&(self->connInfo));
    if (self->original_client_encoding)
    {
@@ -765,6 +767,7 @@ EatReadyForQuery(ConnectionClass *conn)
                CC_set_in_error_trans(conn);
                break;  
        }
+       conn->stmt_in_extquery = NULL;
    }
    return id;  
 }
@@ -2412,6 +2415,15 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD
        return NULL;
    }
 
+   /* Finish the pending extended query first */
+   if (!SyncParseRequest(self))
+   {
+       if (CC_get_errornumber(self) <= 0)
+       {
+           CC_set_error(self, CONN_EXEC_ERROR, "error occured while calling SyncParseRequest() in CC_send_query_append()", func);
+           return NULL;
+       }
+   }   
    /* Indicate that we are sending a query to the backend */
    maxlen = CC_get_max_query_len(self);
    qrylen = strlen(query);
@@ -2992,6 +3004,15 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
        return FALSE;
    }
 
+   /* Finish the pending extended query first */
+   if (!SyncParseRequest(self))
+   {
+       if (CC_get_errornumber(self) <= 0)
+       {
+           CC_set_error(self, CONN_EXEC_ERROR, "error occured while calling SyncParseRequest() in CC_send_function()", func);
+           return FALSE;
+       }
+   }   
 #define    return DONT_CALL_RETURN_FROM_HERE???
    ENTER_INNER_CONN_CS(self, func_cs_count);
    ci = &(self->connInfo);
index f0d6d047e49b62314a120eb2d4b43c1858a2ac6a..51044f8133c02c6ff7a57f64d369d618731dc5ab 100644 (file)
@@ -462,6 +462,7 @@ struct ConnectionClass_
    int     be_key; /* auth code needed to send cancel */
    UInt4       isolation;
    char        *current_schema;
+   StatementClass  *stmt_in_extquery;
    Int2        max_identifier_length;
    Int2        num_discardp;
    char        **discardp;
index 4ac95d3d681f67eded5ca1a4f9cf624aa956d648..6b5fab3fe887f6dd42f35e3f7aee9b334974d80d 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -1654,7 +1654,6 @@ typedef struct _QueryParse {
    char        token_save[64];
    int     token_len;
    BOOL        prev_token_end;
-   BOOL        proc_no_param;
    size_t      declare_pos;
    UInt4       flags;
    encoded_str encstr;
@@ -1675,7 +1674,6 @@ QP_initialize(QueryParse *q, const StatementClass *stmt)
    q->token_save[0] = '\0';
    q->token_len = 0;
    q->prev_token_end = TRUE;
-   q->proc_no_param = TRUE;
    q->declare_pos = 0;
    q->flags = 0;
    make_encoded_str(&q->encstr, SC_get_conn(stmt), q->statement);
@@ -1707,6 +1705,8 @@ typedef struct _QueryBuild {
    Int2    num_output_params;
    Int2    num_discard_params;
    Int2    proc_return;
+   Int2    brace_level;
+   char    parenthesize_the_first;
    APDFields *apdopts;
    IPDFields *ipdopts;
    PutDataInfo *pdata;
@@ -1736,6 +1736,8 @@ QB_initialize(QueryBuild *qb, size_t size, StatementClass *stmt, ConnectionClass
    qb->num_io_params = 0;
    qb->num_output_params = 0;
    qb->num_discard_params = 0;
+   qb->brace_level = 0;
+   qb->parenthesize_the_first = FALSE;
    if (conn)
        qb->conn = conn;
    else if (stmt)
@@ -2046,6 +2048,73 @@ do { \
 } while (0)
 #endif /* NOT_USED */
 
+static RETCODE
+QB_start_brace(QueryBuild *qb)
+{
+   BOOL    replace_by_parenthesis = TRUE;
+
+   if (0 == qb->brace_level)
+   {
+       if (0 == F_NewPos(qb))
+       {
+           qb->parenthesize_the_first = FALSE;
+           replace_by_parenthesis = FALSE;
+       }
+       else
+           qb->parenthesize_the_first = TRUE;
+   }
+   if (replace_by_parenthesis)
+       CVT_APPEND_CHAR(qb, '(');
+   qb->brace_level++;
+   return SQL_SUCCESS;
+}
+
+static RETCODE
+QB_end_brace(QueryBuild *qb)
+{
+   BOOL    replace_by_parenthesis = TRUE;
+
+   if (qb->brace_level <= 1 &&
+       !qb->parenthesize_the_first)
+       replace_by_parenthesis = FALSE;
+   if (replace_by_parenthesis)
+       CVT_APPEND_CHAR(qb, ')');
+   qb->brace_level--;
+   return SQL_SUCCESS;
+}
+
+static RETCODE QB_append_space_to_separate_identifiers(QueryBuild *qb, const QueryParse *qp)
+{
+   unsigned char   tchar = F_OldChar(qp);
+   encoded_str encstr;
+   BOOL        add_space = FALSE;
+
+   if (ODBC_ESCAPE_END != tchar)
+       return SQL_SUCCESS;
+   encoded_str_constr(&encstr, qb->ccsc, F_OldPtr(qp) + 1);
+   tchar = encoded_nextchar(&encstr);
+   if (ENCODE_STATUS(encstr) != 0)
+       add_space = TRUE;
+   else
+   {
+       if (isalnum(tchar))
+           add_space = TRUE;
+       else
+       {
+           switch (tchar)
+           {
+               case '_':
+               case '$':
+                   add_space = TRUE;
+           }
+       }
+   }
+   if (add_space)
+       CVT_APPEND_CHAR(qb, ' ');
+
+   return SQL_SUCCESS;
+}
+
 /*----------
  * Check if the statement is
  * SELECT ... INTO table FROM .....
@@ -2220,7 +2289,7 @@ insert_without_target(const char *stmt, int *endpos)
 }
 
 static
-RETCODE    prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb);
+RETCODE    prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb, BOOL sync);
 static int
 Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
 {
@@ -2230,6 +2299,7 @@ Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
    ConnectionClass *conn = SC_get_conn(stmt);
    ConnInfo    *ci = &(conn->connInfo);
    BOOL    discardOutput, outpara;
+   BOOL    sync = FALSE;
 
    if (PROTOCOL_74(ci))
    {
@@ -2245,7 +2315,7 @@ Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
    if (QB_initialize(qb, qp->stmt_len, stmt, NULL) < 0)
        return SQL_ERROR;
    if (PROTOCOL_74(ci))
-       return prep_params(stmt, qp, qb);
+       return prep_params(stmt, qp, qb, sync);
    discardOutput = (0 != (qb->flags & FLGB_DISCARD_OUTPUT));
    if (NOT_YET_PREPARED == stmt->prepared) /*  not yet prepared */
    {
@@ -2264,7 +2334,7 @@ Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
 #endif /* NOT_USED */
        CVT_APPEND_STR(qb, "PREPARE \"");
        CVT_APPEND_STR(qb, plan_name);
-       CVT_APPEND_CHAR(qb, '"');
+       CVT_APPEND_CHAR(qb, IDENTIFIER_QUOTE);
        marker_count = stmt->num_params - qb->num_discard_params;
        if (!ipdopts || ipdopts->allocated < marker_count)
        {
@@ -2290,7 +2360,7 @@ Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
                if (outpara)
                    CVT_APPEND_STR(qb, "void");
                else
-                   CVT_APPEND_STR(qb, pgtype_to_name(stmt, ipdopts->parameters[i].PGType, FALSE));
+                   CVT_APPEND_STR(qb, pgtype_to_name(stmt, PIC_dsp_pgtype(stmt, ipdopts->parameters[i]), FALSE));
                oc++;
            }
            CVT_APPEND_CHAR(qb, ')');
@@ -2359,7 +2429,7 @@ inolog("exe_statement=%s\n", exe_statement);
 #define        my_strchr(conn, s1,c1) pg_mbschr(conn->ccsc, s1,c1)
 
 static
-RETCODE    prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
+RETCODE    prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb, BOOL sync)
 {
    CSTR        func = "prep_params";
    RETCODE     retval;
@@ -2411,9 +2481,15 @@ inolog("prep_params\n");
        ret = SendParseRequest(stmt, plan_name, qb->query_statement, SQL_NTS, -1);
    if (!ret)
        goto cleanup;
-   if (!once_descr && (!SendDescribeRequest(stmt, plan_name)))
+   if (!once_descr && (!SendDescribeRequest(stmt, plan_name, TRUE)))
        goto cleanup;
    SC_set_planname(stmt, plan_name);
+   SC_set_prepared(stmt, plan_name[0] ? PREPARING_PERMANENTLY : PREPARING_TEMPORARILY);
+   if (!sync)
+   {
+       retval = SQL_SUCCESS;
+       goto cleanup;
+   }
    if (!(res = SendSyncAndReceive(stmt, NULL, "prepare_and_describe")))
    {
        SC_set_error(stmt, STMT_NO_RESPONSE, "commnication error while preapreand_describe", func);
@@ -2447,7 +2523,7 @@ inolog("prep_params\n");
            stmt->current_exec_param = num_pa;
            ret = SendParseRequest(stmt, plan_name, srvquery, endp2 < 0 ? SQL_NTS : endp2, num_p1);
            if (!ret)   goto cleanup;
-           if (!once_descr && !SendDescribeRequest(stmt, plan_name))
+           if (!once_descr && !SendDescribeRequest(stmt, plan_name, TRUE))
                goto cleanup;
            if (!(res = SendSyncAndReceive(stmt, NULL, "prepare_and_describe")))
            {
@@ -2469,7 +2545,7 @@ cleanup:
    return retval;
 }
 
-RETCODE    prepareParameters(StatementClass *stmt)
+RETCODE    prepareParameters(StatementClass *stmt, BOOL sync)
 {
    switch (stmt->prepared)
    {
@@ -2484,7 +2560,7 @@ inolog("prepareParameters\n");
            qb = &query_crt;
            if (QB_initialize(qb, qp->stmt_len, stmt, NULL) < 0)
                return SQL_ERROR;
-           return prep_params(stmt, qp, qb);
+           return prep_params(stmt, qp, qb, sync);
    }
    return SQL_SUCCESS;
 }
@@ -2504,7 +2580,7 @@ copy_statement_with_parameters(StatementClass *stmt, BOOL buildPrepareStatement)
 
    char       *new_statement;
 
-   BOOL    begin_first = FALSE, prepare_dummy_cursor = FALSE;
+   BOOL    begin_first = FALSE, prepare_dummy_cursor = FALSE, bPrepConv;
    ConnectionClass *conn = SC_get_conn(stmt);
    ConnInfo   *ci = &(conn->connInfo);
    SQLLEN      current_row;
@@ -2593,11 +2669,19 @@ inolog("type=%d concur=%d\n", stmt->options.cursor_type, stmt->options.scroll_co
        SC_set_pre_executable(stmt);
    qb = &query_crt;
    qb->query_statement = NULL;
-   if (PREPARED_PERMANENTLY == stmt->prepared || (buildPrepareStatement && stmt->options.scroll_concurrency == SQL_CONCUR_READ_ONLY))
+   bPrepConv = FALSE;
+   if (PREPARED_PERMANENTLY == stmt->prepared)
+       bPrepConv = TRUE;
+   else if (buildPrepareStatement &&
+        SQL_CONCUR_READ_ONLY == stmt->options.scroll_concurrency)
+       bPrepConv = TRUE;
+   if (bPrepConv)
    {
        retval = Prepare_and_convert(stmt, qp, qb);
        return retval;
    }
+   SC_forget_unnamed(stmt);
+   buildPrepareStatement = FALSE;
 
    if (ci->disallow_premature)
        prepare_dummy_cursor = stmt->pre_executing;
@@ -2780,7 +2864,7 @@ Int4 findTag(const char *tag, char dollar_quote, int ccsc)
 {
    Int4    taglen = 0;
    encoded_str encstr;
-   char        tchar;
+   unsigned char   tchar;
    const char  *sptr;
 
    encoded_str_constr(&encstr, ccsc, tag + 1);
@@ -2800,6 +2884,83 @@ Int4 findTag(const char *tag, char dollar_quote, int ccsc)
    return taglen;
 }
 
+static
+Int4 findIdentifier(const char *str, int ccsc, const char **nextdel)
+{
+   Int4    strlen = 0;
+   encoded_str encstr;
+   unsigned char   tchar;
+   const char  *sptr;
+   BOOL    dquote = FALSE;
+
+   *nextdel = NULL;
+   encoded_str_constr(&encstr, ccsc, str);
+   for (sptr = str; *sptr; sptr++)
+   {
+       tchar = encoded_nextchar(&encstr);
+       if (ENCODE_STATUS(encstr) != 0)
+           continue;
+       if (sptr == str) /* the first character */
+       {
+           if (dquote = (IDENTIFIER_QUOTE == tchar))
+               continue;
+           if (!isalpha(tchar))
+           {
+               strlen = 0;
+               if (!isspace(tchar))
+                   *nextdel = sptr;
+               break;
+           }
+       }
+       if (dquote)
+       {
+           if (IDENTIFIER_QUOTE == tchar)
+           {
+               if (IDENTIFIER_QUOTE == sptr[1])
+               {
+                   encoded_nextchar(&encstr);
+                   sptr++;
+                   continue;
+               }
+               strlen = sptr - str + 1;
+               sptr++;
+               break;
+           }
+       }
+       else
+       {
+           if (isalnum(tchar))
+               continue;
+           if (isspace(tchar))
+           {
+               strlen = sptr - str;
+               break;
+           }
+           switch (tchar)
+           {
+               case '_':
+               case '$':
+                   continue;
+           }
+           strlen = sptr - str;
+           *nextdel = sptr;
+           break;
+       }
+   }
+   if (NULL == *nextdel)
+   {
+       for (; *sptr; sptr++)
+       {
+           if (!isspace(*sptr))
+           {
+               *nextdel = sptr;
+               break;
+           }
+       }
+   }
+   return strlen;
+}
+
 static int
 inner_process_tokens(QueryParse *qp, QueryBuild *qb)
 {
@@ -2905,8 +3066,12 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
     * Handle literals (date, time, timestamp) and ODBC scalar
     * functions
     */
-   else if (oldchar == '{')
+   else if (oldchar == ODBC_ESCAPE_START)
    {
+       int npos = F_NewPos(qb);
+       BOOL    addsp = TRUE;
+       unsigned char   tchar;
+
        if (SQL_ERROR == convert_escape(qp, qb))
        {
            if (0 == qb->errornumber)
@@ -2917,21 +3082,12 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
            mylog("%s convert_escape error\n", func);
            return SQL_ERROR;
        }
-       if (isalnum((UCHAR)F_OldPtr(qp)[1]))
-           CVT_APPEND_CHAR(qb, ' ');
        return SQL_SUCCESS;
    }
    /* End of an escape sequence */
-   else if (oldchar == '}')
+   else if (oldchar == ODBC_ESCAPE_END)
    {
-       if (qp->statement_type == STMT_TYPE_PROCCALL)
-       {
-           if (qp->proc_no_param)
-               CVT_APPEND_STR(qb, "()");
-       }
-       else if (!isspace(F_OldPtr(qp)[1]))
-           CVT_APPEND_CHAR(qb, ' ');
-       return SQL_SUCCESS;
+       return QB_end_brace(qb);
    }
    else if (oldchar == '@' &&
         strnicmp(F_OldPtr(qp), "@@identity", 10) == 0)
@@ -3196,11 +3352,11 @@ inolog("num_p=%d\n", num_p);
                memset(bindreq + leng, 0, sizeof(Int2) * num_p);  /* initialize by text format */
        for (i = stmt->proc_return, j = 0; i < num_params; i++)
        {
-inolog("%dth paramater type oid is %u\n", i, parameters[i].PGType);
+inolog("%dth parameter type oid is %u\n", i, PIC_dsp_pgtype(stmt, parameters[i]));
            if (discard_output &&
                SQL_PARAM_OUTPUT == parameters[i].paramType)
                continue;
-           if (PG_TYPE_BYTEA == parameters[i].PGType)
+           if (PG_TYPE_BYTEA == PIC_dsp_pgtype(stmt, parameters[i]))
            {
                mylog("%dth parameter is of binary format\n", j);
                memcpy(bindreq + leng + sizeof(Int2) * j,
@@ -3649,10 +3805,10 @@ inolog("ipara=%p paramType=%d %d proc_return=%d\n", ipara, ipara ? ipara->paramT
 
    param_ctype = apara->CType;
    param_sqltype = ipara->SQLType;
-   param_pgtype = ipara->PGType;
+   param_pgtype = PIC_dsp_pgtype(qb->stmt, *ipara);
 
-   mylog("%s: from(fcType)=%d, to(fSqlType)=%d\n", func,
-               param_ctype, param_sqltype);
+   mylog("%s: from(fcType)=%d, to(fSqlType)=%d(%u)\n", func,
+               param_ctype, param_sqltype, param_pgtype);
 
    /* replace DEFAULT with something we can use */
    if (param_ctype == SQL_C_DEFAULT)
@@ -4057,8 +4213,10 @@ mylog("buf=%p flag=%d\n", buf, qb->flags);
                lobj_oid = pdata->pdata[param_number].lobj_oid;
            else
            {
+               BOOL    is_in_trans_at_entry = CC_is_in_trans(conn);
+
                /* begin transaction if needed */
-               if (!CC_is_in_trans(conn))
+               if (!is_in_trans_at_entry)
                {
                    if (!CC_begin(conn))
                    {
@@ -4091,7 +4249,7 @@ mylog("buf=%p flag=%d\n", buf, qb->flags);
                odbc_lo_close(conn, lobj_fd);
 
                /* commit transaction if needed */
-               if (!ci->drivers.use_declarefetch && CC_does_autocommit(conn))
+               if (!is_in_trans_at_entry)
                {
                    if (!CC_commit(conn))
                    {
@@ -4260,7 +4418,7 @@ processParameters(QueryParse *qp, QueryBuild *qb,
                    *output_count = F_NewPos(qb);
                break;
 
-           case '}':
+           case ODBC_ESCAPE_END:
                stop = (0 == innerParenthesis);
                break;
 
@@ -4305,12 +4463,13 @@ static int
 convert_escape(QueryParse *qp, QueryBuild *qb)
 {
    CSTR func = "convert_escape";
+   ConnectionClass *conn = qb->conn;
    RETCODE retval = SQL_SUCCESS;
    char        buf[1024], buf_small[128], key[65];
    UCHAR   ucv;
    UInt4       prtlen;
  
-   if (F_OldChar(qp) == '{') /* skip the first { */
+   if (F_OldChar(qp) == ODBC_ESCAPE_START) /* skip the first { */
        F_OldNext(qp);
    /* Separate off the key, skipping leading and trailing whitespace */
    while ((ucv = F_OldChar(qp)) != '\0' && isspace(ucv))
@@ -4318,6 +4477,59 @@ convert_escape(QueryParse *qp, QueryBuild *qb)
    /*
     * procedure calls
     */
+   /* '?=' to accept return values exists ? */
+   if (F_OldChar(qp) == '?')
+   {
+       qb->param_number++;
+       qb->proc_return = 1;
+       if (qb->stmt)
+           qb->stmt->proc_return = 1;
+       while (isspace((UCHAR) qp->statement[++qp->opos]));
+       if (F_OldChar(qp) != '=')
+       {
+           F_OldPrior(qp);
+           return SQL_SUCCESS;
+       }
+       while (isspace((UCHAR) qp->statement[++qp->opos]));
+   }
+   /**
+   if (qp->statement_type == STMT_TYPE_PROCCALL)
+   {
+       int lit_call_len = 4;
+
+       // '?=' to accept return values exists ?
+       if (F_OldChar(qp) == '?')
+       {
+           qb->param_number++;
+           qb->proc_return = 1;
+           if (qb->stmt)
+               qb->stmt->proc_return = 1;
+           while (isspace((UCHAR) qp->statement[++qp->opos]));
+           if (F_OldChar(qp) != '=')
+           {
+               F_OldPrior(qp);
+               return SQL_SUCCESS;
+           }
+           while (isspace((UCHAR) qp->statement[++qp->opos]));
+       }
+       if (strnicmp(F_OldPtr(qp), "call", lit_call_len) ||
+           !isspace((UCHAR) F_OldPtr(qp)[lit_call_len]))
+       {
+           F_OldPrior(qp);
+           return SQL_SUCCESS;
+       }
+       qp->opos += lit_call_len;
+       if (qb->num_io_params > 1 ||
+           (0 == qb->proc_return &&
+            PG_VERSION_GE(conn, 7.3)))
+           CVT_APPEND_STR(qb, "SELECT * FROM");
+       else
+           CVT_APPEND_STR(qb, "SELECT");
+       if (my_strchr(conn, F_OldPtr(qp), '('))
+           qp->proc_no_param = FALSE;
+       return SQL_SUCCESS;
+   }
+   **/
 
    sscanf(F_OldPtr(qp), "%32s", key);
    while ((ucv = F_OldChar(qp)) != '\0' && (!isspace(ucv)))
@@ -4327,62 +4539,83 @@ convert_escape(QueryParse *qp, QueryBuild *qb)
     
    /* Avoid the concatenation of the function name with the previous word. Aceto */
 
-   if (F_NewPos(qb) > 0 && isalnum((UCHAR)F_NewPtr(qb)[-1]))
-       CVT_APPEND_CHAR(qb, ' ');
    
    if (stricmp(key, "call") == 0)
    {
        Int4 funclen;
        const char *nextdel;
 
+       if (SQL_ERROR == QB_start_brace(qb))
+           return SQL_ERROR;
        if (qb->num_io_params > 1 ||
            (0 == qb->proc_return &&
             PG_VERSION_GE(conn, 7.3)))
            CVT_APPEND_STR(qb, "SELECT * FROM ");
        else
            CVT_APPEND_STR(qb, "SELECT ");
-       /* Continue at inner_process_tokens loop */
-       F_OldPrior(qp);
-       return SQL_SUCCESS;
+       funclen = findIdentifier(F_OldPtr(qp), qb->ccsc, &nextdel);
+       if (nextdel && ODBC_ESCAPE_END == *nextdel)
+       {
+           CVT_APPEND_DATA(qb, F_OldPtr(qp), funclen);
+           CVT_APPEND_STR(qb, "()");
+           if (SQL_ERROR == QB_end_brace(qb))
+               return SQL_ERROR;
+           /* positioned at } */
+           qp->opos += (nextdel - F_OldPtr(qp));
+       }
+       else
+       {
+           /* Continue at inner_process_tokens loop */
+           F_OldPrior(qp);
+           return SQL_SUCCESS;
+       }
    }
    else if (stricmp(key, "d") == 0)
    {
        /* Literal; return the escape part adding type cast */
-       F_ExtractOldTo(qp, buf_small, '}', sizeof(buf_small));
-       if (PG_VERSION_LT(qb->conn, 7.3))
-           prtlen = snprintf(buf, sizeof(buf), "%s ", buf_small);
+       F_ExtractOldTo(qp, buf_small, ODBC_ESCAPE_END, sizeof(buf_small));
+       if (PG_VERSION_LT(conn, 7.3))
+           prtlen = snprintf(buf, sizeof(buf), "%s", buf_small);
        else
-           prtlen = snprintf(buf, sizeof(buf), "%s::date ", buf_small);
+           prtlen = snprintf(buf, sizeof(buf), "%s::date", buf_small);
        CVT_APPEND_DATA(qb, buf, prtlen);
+       retval = QB_append_space_to_separate_identifiers(qb, qp);
    }
    else if (stricmp(key, "t") == 0)
    {
        /* Literal; return the escape part adding type cast */
-       F_ExtractOldTo(qp, buf_small, '}', sizeof(buf_small));
+       F_ExtractOldTo(qp, buf_small, ODBC_ESCAPE_END, sizeof(buf_small));
        prtlen = snprintf(buf, sizeof(buf), "%s::time", buf_small);
        CVT_APPEND_DATA(qb, buf, prtlen);
+       retval = QB_append_space_to_separate_identifiers(qb, qp);
    }
    else if (stricmp(key, "ts") == 0)
    {
        /* Literal; return the escape part adding type cast */
-       F_ExtractOldTo(qp, buf_small, '}', sizeof(buf_small));
-       if (PG_VERSION_LT(qb->conn, 7.1))
+       F_ExtractOldTo(qp, buf_small, ODBC_ESCAPE_END, sizeof(buf_small));
+       if (PG_VERSION_LT(conn, 7.1))
            prtlen = snprintf(buf, sizeof(buf), "%s::datetime", buf_small);
        else
            prtlen = snprintf(buf, sizeof(buf), "%s::timestamp", buf_small);
        CVT_APPEND_DATA(qb, buf, prtlen);
+       retval = QB_append_space_to_separate_identifiers(qb, qp);
    }
    else if (stricmp(key, "oj") == 0) /* {oj syntax support for 7.1 * servers */
    {
        if (qb->stmt)
            SC_set_outer_join(qb->stmt);
+       retval = QB_start_brace(qb);
+       /* Continue at inner_process_tokens loop */
        F_OldPrior(qp);
-       return SQL_SUCCESS; /* Continue at inner_process_tokens loop */
+       return retval;
    }
-   else if (stricmp(key, "escape") == 0) /* like escape support for 7.1+ servers */
+   else if (stricmp(key, "escape") == 0) /* like escape syntax support for 7.1+ servers */
    {
-       CVT_APPEND_STR(qb, key);
-       return SQL_SUCCESS;
+       /* Literal; return the escape part adding type cast */
+       F_ExtractOldTo(qp, buf_small, ODBC_ESCAPE_END, sizeof(buf_small));
+       prtlen = snprintf(buf, sizeof(buf), "%s %s", key, buf_small);
+       CVT_APPEND_DATA(qb, buf, prtlen);
+       retval = QB_append_space_to_separate_identifiers(qb, qp);
    }
    else if (stricmp(key, "fn") == 0)
    {
@@ -4627,7 +4860,7 @@ parse_datetime(const char *buf, SIMPLE_TIME *st)
    st->infinity = 0;
 
    /* escape sequence ? */
-   if (buf[0] == '{')
+   if (buf[0] == ODBC_ESCAPE_START)
    {
        while (*(++buf) && *buf != LITERAL_QUOTE);
        if (!(*buf))
@@ -5125,6 +5358,13 @@ convert_lo(StatementClass *stmt, const void *value, SQLSMALLINT fCType, PTR rgbV
    GetDataInfo *gdata_info = SC_get_GDTI(stmt);
    int         factor;
 
+   oid = ATOI32U(value);
+   if (0 == oid)
+   {
+       if (pcbValue)
+           *pcbValue = SQL_NULL_DATA;
+       return COPY_OK;
+   }
    switch (fCType)
    {
        case SQL_C_CHAR:
@@ -5161,7 +5401,6 @@ convert_lo(StatementClass *stmt, const void *value, SQLSMALLINT fCType, PTR rgbV
            }
        }
 
-       oid = ATOI32U(value);
        stmt->lobj_fd = odbc_lo_open(conn, oid, INV_READ);
        if (stmt->lobj_fd < 0)
        {
index 7f55eb1808c4b197d4aead754c7c965f18ff0793..9cb24d17fc8782339f6e0855d281e5bd45b9ec9c 100644 (file)
--- a/execute.c
+++ b/execute.c
@@ -282,6 +282,130 @@ decideHowToPrepare(StatementClass *stmt, BOOL force)
    return method;
 }
 
+/* dont/should/can send Parse request ? */
+enum {
+    doNothing = 0
+   ,allowParse
+   ,preferParse
+   ,shouldParse
+   ,usingCommand
+};
+
+#define    ONESHOT_CALL_PARSE      allowParse
+#define    NOPARAM_ONESHOT_CALL_PARSE  doNothing
+
+static
+int HowToPrepareBeforeExec(StatementClass *stmt, BOOL checkOnly)
+{
+   SQLSMALLINT num_params = stmt->num_params;
+   ConnectionClass *conn = SC_get_conn(stmt);
+   ConnInfo *ci = &(conn->connInfo);
+   int     nCallParse = doNothing, how_to_prepare = 0;
+   BOOL        bNeedsTrans = FALSE;
+
+   if (num_params < 0)
+       PGAPI_NumParams(stmt, &num_params);
+   how_to_prepare = decideHowToPrepare(stmt, checkOnly);
+   if (checkOnly)
+   {
+       if (num_params <= 0)
+           return doNothing;
+   }
+   else
+   {
+       switch (how_to_prepare)
+       {
+           case USING_PREPARE_COMMAND:
+               return usingCommand;
+           case NAMED_PARSE_REQUEST:
+               return shouldParse;
+           case PARSE_TO_EXEC_ONCE:
+               switch (stmt->prepared)
+               {
+                   case PREPARED_TEMPORARILY:
+                       nCallParse = preferParse;
+                       break;
+                   default:
+                       if (num_params <= 0)
+                           nCallParse = NOPARAM_ONESHOT_CALL_PARSE;
+                       else
+                           nCallParse = ONESHOT_CALL_PARSE;
+               }
+               break;
+           default:
+               return doNothing;
+       }
+   }
+   if (PG_VERSION_LE(conn, 7.3))
+       return nCallParse;
+
+   if (num_params > 0)
+   {
+       int param_number = -1;
+       ParameterInfoClass *apara;
+       ParameterImplClass *ipara;
+       OID pgtype;
+
+       while (TRUE)
+       {
+           SC_param_next(stmt, &param_number, &apara, &ipara);
+           if (!ipara || !apara)
+               break;
+           pgtype = PIC_get_pgtype(*ipara);
+           if (checkOnly)
+           {
+               switch (ipara->SQLType)
+               {
+                   case SQL_LONGVARBINARY:
+                       if (0 == pgtype)
+                       {
+                           if (ci->bytea_as_longvarbinary &&
+                               0 != conn->lobj_type)
+                               nCallParse = shouldParse;
+                       }
+                       break;
+                   case SQL_CHAR:
+                       if (ci->cvt_null_date_string)
+                           nCallParse = shouldParse;
+                       break;
+               }
+           }
+           else
+           {
+               BOOL    bBytea = FALSE;
+
+               switch (ipara->SQLType)
+               {
+                   case SQL_LONGVARBINARY:
+                       if (conn->lobj_type == pgtype ||
+                               PG_TYPE_OID == pgtype)
+                           bNeedsTrans = TRUE;
+                       else if (PG_TYPE_BYTEA == pgtype)
+                           bBytea = TRUE;
+                       else if (0 == pgtype)
+                       {
+                           if (ci->bytea_as_longvarbinary)
+                               bBytea = TRUE;
+                           else
+                               bNeedsTrans = TRUE;
+                       }
+                       if (bBytea)
+                           if (nCallParse < preferParse)
+                               nCallParse = preferParse;
+                       break;
+               }
+           }
+       }
+   }
+   if (bNeedsTrans &&
+       PARSE_TO_EXEC_ONCE == how_to_prepare)
+   {
+       if (!CC_is_in_trans(conn) && CC_does_autocommit(conn))
+           nCallParse = doNothing;
+   }
+   return nCallParse;
+}
+
 /*
  * The execution after all parameters were resolved.
  */
@@ -308,15 +432,19 @@ RETCODE   Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end)
    /* Prepare the statement if possible at backend side */
    if (!stmt->inaccurate_result)
    {
+       /**
        switch (decideHowToPrepare(stmt, FALSE))
        {
            case USING_PREPARE_COMMAND:
            case NAMED_PARSE_REQUEST:
 #ifndef    BYPASS_ONESHOT_PLAN_EXECUTION
            case PARSE_TO_EXEC_ONCE:
-#endif/* BYPASS_ONESHOT_PLAN_EXECUTION */
+#endif
                prepare_before_exec = TRUE;
        }
+       **/
+       if (HowToPrepareBeforeExec(stmt, FALSE) >= allowParse)
+           prepare_before_exec = TRUE;
    }
 inolog("prepare_before_exec=%d srv=%d\n", prepare_before_exec, conn->connInfo.use_server_side_prepare);
    /* Create the statement with parameters substituted. */
@@ -903,63 +1031,19 @@ PGAPI_Execute(HSTMT hstmt, UWORD flag)
           We sometimes need to know about the PG type of binding
           parameters even in case of non-prepared statements.
         */
-       BOOL    bCallPrepare = FALSE;
-
-       ConnInfo *ci = &(conn->connInfo);
-       if (NOT_YET_PREPARED == stmt->prepared &&
-           PROTOCOL_74(ci) &&
-           ci->use_server_side_prepare &&
-          (ci->bytea_as_longvarbinary || /* both lo and bytea are LO */
-           ci->cvt_null_date_string))
+       int nCallParse = doNothing;
+
+       if (NOT_YET_PREPARED == stmt->prepared)
        {
-           SQLSMALLINT num_params = stmt->num_params;
-           if (num_params < 0)
-               PGAPI_NumParams(stmt, &num_params);
-           if (num_params > 0)
+           switch (nCallParse = HowToPrepareBeforeExec(stmt, TRUE))
            {
-               int param_number = -1;
-               ParameterInfoClass *apara;
-               ParameterImplClass *ipara;
-               BOOL    reqOK = FALSE;
-
-               switch (decideHowToPrepare(stmt, TRUE))
-               {
-                   case NAMED_PARSE_REQUEST:
-                   case PARSE_TO_EXEC_ONCE:
-                   case PARSE_REQ_FOR_INFO:
-                       reqOK = TRUE;
-               }
-               while (reqOK)
-               {
-                   SC_param_next(stmt, &param_number, &apara, &ipara);
-                   if (!ipara || !apara)
-                       break;
-                   if (SQL_LONGVARBINARY == ipara->SQLType)
-                   {
-                       if (ci->bytea_as_longvarbinary)
-                       {
-                           bCallPrepare = TRUE;
-                           break;
-                       }
-                   }
-                   else if (SQL_CHAR == ipara->SQLType)
-                   {
-                       if (SQL_C_CHAR == apara->CType &&
-                           ci->cvt_null_date_string)
-                       {
-                           bCallPrepare = TRUE;
-                           break;
-                       }
-                   }
-               }
+               case shouldParse:
+                   if (retval = prepareParameters(stmt, TRUE), SQL_ERROR == retval)
+                       goto cleanup;
+                   break;
            }
        }
-       if (bCallPrepare)
-       {
-           if (retval = prepareParameters(stmt), SQL_ERROR == retval)
-               goto cleanup;
-       }
-mylog("prepareParameters %d end\n", stmt->prepare);
+mylog("prepareParameters was %s called, prepare state:%d\n", shouldParse == nCallParse ? "" : "not", stmt->prepare);
 
        if (ipdopts->param_processed_ptr)
            *ipdopts->param_processed_ptr = 0;
@@ -1481,7 +1565,7 @@ PGAPI_PutData(
    char       *buffer, *putbuf, *allocbuf = NULL;
    Int2        ctype;
    SQLLEN      putlen;
-   BOOL        lenset = FALSE;
+   BOOL        lenset = FALSE, handling_lo = FALSE;
 
    mylog("%s: entering...\n", func);
 
@@ -1554,7 +1638,8 @@ PGAPI_PutData(
            putlen = ctype_length(ctype);
    }
    putbuf = rgbValue;
-   if (current_iparam->PGType == conn->lobj_type && SQL_C_CHAR == ctype)
+   handling_lo = (PIC_dsp_pgtype(stmt, *current_iparam) == conn->lobj_type);
+   if (handling_lo && SQL_C_CHAR == ctype)
    {
        allocbuf = malloc(putlen / 2 + 1);
        if (allocbuf)
@@ -1589,7 +1674,7 @@ PGAPI_PutData(
 
        /* Handle Long Var Binary with Large Objects */
        /* if (current_iparam->SQLType == SQL_LONGVARBINARY) */
-       if (current_iparam->PGType == conn->lobj_type)
+       if (handling_lo)
        {
            /* begin transaction if needed */
            if (!CC_is_in_trans(conn))
@@ -1648,7 +1733,7 @@ PGAPI_PutData(
        mylog("PGAPI_PutData: (>1) cbValue = %d\n", cbValue);
 
        /* if (current_iparam->SQLType == SQL_LONGVARBINARY) */
-       if (current_iparam->PGType == conn->lobj_type)
+       if (handling_lo)
        {
            /* the large object fd is in EXEC_buffer */
            retval = odbc_lo_write(conn, estmt->lobj_fd, putbuf, (Int4) putlen);
diff --git a/info.c b/info.c
index 2a32dd921ddc84ce4f26e2157b367a97c16fa083..2c71551c73d00079aad26e469aae7762dd1e8cd2 100644 (file)
--- a/info.c
+++ b/info.c
@@ -2693,7 +2693,7 @@ PGAPI_SpecialColumns(
    SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
    const char  *szSchemaName, *eq_string;
 
-   mylog("%s: entering...stmt=%p scnm=%p len=%d colType=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType);
+   mylog("%s: entering...stmt=%p scnm=%p len=%d colType=%d scope=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType, fScope);
 
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
        return result;
diff --git a/parse.c b/parse.c
index a1bc3e5fdefd02332fbe4b443fb0aa949c6b1c0d..0674cdf637e514266f8a44ff47f36e30ed83904b 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -1207,7 +1207,7 @@ static char *insert_as_to_the_statement(char *stmt, char **pptr, char **ptr)
 static char
 parse_the_statement(StatementClass *stmt, BOOL check_hasoids, BOOL sqlsvr_check)
 {
-   CSTR        func = "parse_statement";
+   CSTR        func = "parse_the_statement";
    char        token[TOKEN_SIZE], stoken[TOKEN_SIZE], btoken[TOKEN_SIZE];
    char        delim,
                quote,
index b7ebf701b03d672a13257ce41bdc874c14c930db..5440ecd8abbc74a762c1497862ac0fb7e9d39a33 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * $Id: psqlodbc.h,v 1.131 2009/07/06 15:23:02 h-saito Exp $
+ * $Id: psqlodbc.h,v 1.132 2009/10/25 13:36:31 hinoue Exp $
  *
  */
 
@@ -268,6 +268,8 @@ BOOL isSqlServr();
 #define    SEARCH_PATTERN_ESCAPE               '\\'
 #define    LITERAL_QUOTE                   '\''
 #define    IDENTIFIER_QUOTE                '\"'
+#define    ODBC_ESCAPE_START               '{'
+#define    ODBC_ESCAPE_END                 '}'
 #define    DOLLAR_QUOTE                    '$'
 #define    LITERAL_EXT                 'E'
 #define    PG_CARRIAGE_RETURN              '\r'
index 28f0c16792ae7a88c24049b081ca5efcefaad427..0e1e342774b0995b5b101e7426a9eff499520d96 100644 (file)
@@ -1006,11 +1006,11 @@ SC_pre_execute(StatementClass *self)
            {
                case NAMED_PARSE_REQUEST:
                case PARSE_TO_EXEC_ONCE:
-                   if (SQL_SUCCESS != prepareParameters(self))
+                   if (SQL_SUCCESS != prepareParameters(self, TRUE))
                        return num_fields;
                    break;
                case PARSE_REQ_FOR_INFO:
-                   if (SQL_SUCCESS != prepareParameters(self))
+                   if (SQL_SUCCESS != prepareParameters(self, TRUE))
                        return num_fields;
                    self->status = STMT_PREMATURE;
                    self->inaccurate_result = TRUE;
@@ -1791,24 +1791,31 @@ SC_execute(StatementClass *self)
     */
    /* in copy_statement... */
    use_extended_protocol = FALSE;
-   if (PREPARED_PERMANENTLY == self->prepared &&
-       PROTOCOL_74(ci))
-       use_extended_protocol = TRUE;
-   else if (PREPARED_TEMPORARILY == self->prepared)
+   switch (self->prepared)
    {
-       switch (SC_get_prepare_method(self))
-       {
+       case PREPARING_PERMANENTLY:
+       case PREPARED_PERMANENTLY:
+               if (PROTOCOL_74(ci))
+               use_extended_protocol = TRUE;
+           break;
+       case PREPARING_TEMPORARILY:
+       case PREPARED_TEMPORARILY:
+           if (!issue_begin)
+           {
+               switch (SC_get_prepare_method(self))
+               {
 #ifndef    BYPASS_ONESHOT_PLAN_EXECUTION
-           case PARSE_TO_EXEC_ONCE:
+                   case PARSE_TO_EXEC_ONCE:
 #endif /* BYPASS_ONESHOT_PLAN_EXECUTION */
-           case NAMED_PARSE_REQUEST:
-               use_extended_protocol = TRUE;
-       }
-       if (!use_extended_protocol)
-       {
-           SC_forget_unnamed(self);
-           SC_set_Result(self, NULL); /* discard the parsed information */
-       }
+                   case NAMED_PARSE_REQUEST:
+                       use_extended_protocol = TRUE;
+               }
+           }
+           if (!use_extended_protocol)
+           {
+               SC_forget_unnamed(self);
+               SC_set_Result(self, NULL); /* discard the parsed information */
+           }
    }
    if (use_extended_protocol)
    {
@@ -1816,8 +1823,6 @@ SC_execute(StatementClass *self)
 
        if (issue_begin)
            CC_begin(conn);
-       for (res = SC_get_Result(self); NULL != res->next; res = res->next) ;
-inolog("get_Result=%p %p %d\n", res, SC_get_Result(self), self->curr_param_result);
        if (!plan_name)
            plan_name = "";
        if (!SendBindRequest(self, plan_name))
@@ -1832,6 +1837,8 @@ inolog("get_Result=%p %p %d\n", res, SC_get_Result(self), self->curr_param_resul
                SC_set_error(self, STMT_EXEC_ERROR, "Execute request error", func);
            goto cleanup;
        }
+       for (res = SC_get_Result(self); NULL != res && NULL != res->next; res = res->next) ;
+inolog("get_Result=%p %p %d\n", res, SC_get_Result(self), self->curr_param_result);
        if (!(res = SendSyncAndReceive(self, self->curr_param_result ? res : NULL, "bind_and_execute")))
        {
            if (SC_get_errornumber(self) <= 0)
@@ -2273,6 +2280,7 @@ SendBindRequest(StatementClass *stmt, const char *plan_name)
        return FALSE;
    if (!BuildBindRequest(stmt, plan_name))
        return FALSE;
+   conn->stmt_in_extquery = stmt;
 
    return TRUE;
 }
@@ -2347,7 +2355,6 @@ inolog(" response_length=%d\n", response_length);
            case 'E': /* ErrorMessage */
                msg_truncated = handle_error_message(conn, msgbuffer, sizeof(msgbuffer), res->sqlstate, comment, res);
 
-               rcvend = TRUE;
                break;
            case 'N': /* Notice */
                msg_truncated = handle_notice_message(conn, msgbuffer, sizeof(msgbuffer), res->sqlstate, comment, res);
@@ -2395,7 +2402,7 @@ inolog("num_params=%d info=%d\n", stmt->num_params, num_p);
                            continue;
                        }
                        oid = SOCK_get_int(sock, 4);
-                       ipdopts->parameters[pidx].PGType = oid;
+                       PIC_set_pgtype(ipdopts->parameters[pidx], oid);
                    }
                }
                else
@@ -2406,7 +2413,7 @@ inolog("num_params=%d info=%d\n", stmt->num_params, num_p);
                        oid = SOCK_get_int(sock, 4);
                        if (SQL_PARAM_OUTPUT != paramType ||
                            PG_TYPE_VOID != oid)
-                           ipdopts->parameters[pidx].PGType = oid;
+                           PIC_set_pgtype(ipdopts->parameters[pidx], oid);
                    }
                }
 #endif /* NOT_USED */
@@ -2425,7 +2432,7 @@ inolog("num_params=%d info=%d\n", stmt->num_params, num_p);
                    paramType = ipdopts->parameters[pidx].paramType;    
                    if (SQL_PARAM_OUTPUT != paramType ||
                        PG_TYPE_VOID != oid)
-                       ipdopts->parameters[pidx].PGType = oid;
+                       PIC_set_pgtype(ipdopts->parameters[pidx], oid);
                }
                break;
            case 'T': /* RowDesription */
@@ -2453,8 +2460,8 @@ inolog("num_params=%d info=%d\n", stmt->num_params, num_p);
                            if (SQL_PARAM_OUTPUT == paramType ||
                                SQL_PARAM_INPUT_OUTPUT == paramType)
                            {
-inolog("!![%d].PGType %u->%u\n", i, ipdopts->parameters[i].PGType, CI_get_oid(res->fields, cidx));
-                               ipdopts->parameters[i].PGType = CI_get_oid(res->fields, cidx);
+inolog("!![%d].PGType %u->%u\n", i, PIC_get_pgtype(ipdopts->parameters[i]), CI_get_oid(res->fields, cidx));
+                               PIC_set_pgtype(ipdopts->parameters[i], CI_get_oid(res->fields, cidx));
                                cidx++;
                            }
                        }
@@ -2481,6 +2488,7 @@ inolog("!![%d].PGType %u->%u\n", i, ipdopts->parameters[i].PGType, CI_get_oid(re
                break;
        }
    }
+   conn->stmt_in_extquery = NULL;
    return res;
 }
 
@@ -2543,7 +2551,6 @@ mylog("sta_pidx=%d end_pidx=%d num_p=%d\n", sta_pidx, end_pidx, 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); */
 inolog("parse leng=" FORMAT_SIZE_T "\n", leng);
    SOCK_put_string(sock, plan_name);
    SOCK_put_n_char(sock, query, qlen);
@@ -2563,12 +2570,51 @@ inolog("parse leng=" FORMAT_SIZE_T "\n", leng);
                SOCK_put_int(sock, 0, sizeof(UInt4));
        }
    }
+   conn->stmt_in_extquery = stmt;
 
    return TRUE;
 }
 
+BOOL   SyncParseRequest(ConnectionClass *conn)
+{
+   StatementClass *stmt = conn->stmt_in_extquery;
+   QResultClass    *res, *last;
+   BOOL    ret = FALSE;
+
+   if (!stmt)
+       return TRUE;
+
+   res = SC_get_Result(stmt);
+   for (last = res; last && last->next; last = last->next)
+       ;
+   if (!(res = SendSyncAndReceive(stmt, stmt->curr_param_result ? last : NULL, __FUNCTION__)))
+   {
+       if (SC_get_errornumber(stmt) <= 0)
+           SC_set_error(stmt, STMT_NO_RESPONSE, "Could not receive the response, communication down ??", __FUNCTION__);
+       CC_on_abort(conn, CONN_DEAD);
+       goto cleanup;
+   }
+
+   if (!last)
+       SC_set_Result(stmt, res);
+   else
+   {
+       if (res != last)
+           last->next = res;
+       stmt->curr_param_result = 1;
+   }
+   if (!QR_command_maybe_successful(res))
+   {
+       SC_set_error(stmt, STMT_EXEC_ERROR, "Error while syncing parse reuest", __FUNCTION__);
+       goto cleanup;
+   }
+   ret = TRUE;
+cleanup:
+   return ret;
+}
+
 BOOL
-SendDescribeRequest(StatementClass *stmt, const char *plan_name)
+SendDescribeRequest(StatementClass *stmt, const char *plan_name, BOOL paramAlso)
 {
    CSTR    func = "SendDescribeRequest";
    ConnectionClass *conn = SC_get_conn(stmt);
@@ -2593,7 +2639,7 @@ SendDescribeRequest(StatementClass *stmt, const char *plan_name)
    if (!sockerr)
    {
 inolog("describe leng=%d\n", leng);
-       SOCK_put_char(sock, 'S'); /* describe a prepared statement */
+       SOCK_put_char(sock, paramAlso ? 'S' : 'P'); /* describe a prepared statement */
        if (SOCK_get_errcode(sock) != 0)
            sockerr = TRUE;
    }
@@ -2609,6 +2655,7 @@ inolog("describe leng=%d\n", leng);
        CC_on_abort(conn, CONN_DEAD);
        return FALSE;
    }
+   conn->stmt_in_extquery = stmt;
 
    return TRUE;
 }
@@ -2670,6 +2717,7 @@ inolog("Close leng=%d\n", leng);
        SOCK_put_char(sock, 'P');   /* Portal */
        SOCK_put_string(sock, plan_name);
    }
+   conn->stmt_in_extquery = stmt;
 
    return TRUE;
 }
@@ -2681,6 +2729,7 @@ BOOL  SendSyncRequest(ConnectionClass *conn)
    SOCK_put_char(sock, 'S');   /* Sync command */
    SOCK_put_int(sock, 4, 4);
    SOCK_flush_output(sock);
+   conn->stmt_in_extquery = NULL;
 
    return TRUE;
 }
@@ -2725,6 +2774,8 @@ BOOL  SC_SetExecuting(StatementClass *self, BOOL on)
    LEAVE_COMMON_CS;
    return exeSet;
 }
+
+#ifdef NOT_USED
 BOOL   SC_SetCancelRequest(StatementClass *self)
 {
    BOOL    enteredCS = FALSE;
@@ -2747,6 +2798,8 @@ BOOL  SC_SetCancelRequest(StatementClass *self)
    LEAVE_COMMON_CS;
    return enteredCS;
 }
+#endif /* NOT_USED */
+
 BOOL   SC_AcceptedCancelRequest(const StatementClass *self)
 {
    BOOL    shouldCancel = FALSE;
index 37ade264fb523476ad88e62ab9a92063db881d6e..78f7fec1d0f20898291ea31877ba6437743a72fe 100644 (file)
@@ -388,6 +388,8 @@ enum {
 enum
 {
    NOT_YET_PREPARED = 0
+   ,PREPARING_PERMANENTLY 
+   ,PREPARING_TEMPORARILY
    ,PREPARED_PERMANENTLY 
    ,PREPARED_TEMPORARILY
    ,ONCE_DESCRIBED
@@ -428,6 +430,7 @@ enum
 #define SC_ref_CC_error(a) ((a->ref_CC_error) = TRUE)
 #define SC_forget_unnamed(a)   (PREPARED_TEMPORARILY == (a)->prepared ? SC_set_prepared(a, ONCE_DESCRIBED) : (void) 0)
 #define SC_returns_rows(a) (STMT_TYPE_SELECT == (a)->statement_type || STMT_TYPE_WITH == (a)->statement_type)
+#define SC_determine_statement_type(a) (STMT_TYPE_SELECT != (a)->statement_type ? (a)->statement_type : ((a)->statement_type = || statement_type((a)->statement)))
 
 
 /* For Multi-thread */
@@ -509,7 +512,8 @@ RETCODE     DiscardStatementSvp(StatementClass *self, RETCODE, BOOL errorOnly);
 
 BOOL       SendParseRequest(StatementClass *self, const char *name,
            const char *query, Int4 qlen, Int2 num_params);
-BOOL       SendDescribeRequest(StatementClass *self, const char *name);
+BOOL       SyncParseRequest(ConnectionClass *conn);
+BOOL       SendDescribeRequest(StatementClass *self, const char *name, BOOL paramAlso);
 BOOL       SendBindRequest(StatementClass *self, const char *name);
 BOOL       BuildBindRequest(StatementClass *stmt, const char *name);
 BOOL       SendExecuteRequest(StatementClass *stmt, const char *portal, UInt4 count);
index 54af6ff6686f2e015a88c4fc59ec2ffa63bff229..286321a544f6047a2b3d3c7ca1bc37136907e7da 100644 (file)
--- a/version.h
+++ b/version.h
@@ -12,6 +12,6 @@
 #define POSTGRESDRIVERVERSION      "08.04.0101"
 #define POSTGRES_RESOURCE_VERSION  "08.04.0101\0"
 #define PG_DRVFILE_VERSION     8,4,01,01
-#define PG_BUILD_VERSION       "200910250003"
+#define PG_BUILD_VERSION       "200910250004"
 
 #endif