Hold the first and last result for parametrized SQL statements with array of paramete...
authorHiroshi Inoue <h-inoue@dream.email.ne.jp>
Fri, 26 Jun 2020 13:44:51 +0000 (22:44 +0900)
committerHiroshi Inoue <h-inoue@dream.email.ne.jp>
Wed, 1 Jul 2020 09:32:42 +0000 (18:32 +0900)
connection.c
connection.h
psqlodbc.h
statement.c
statement.h

index dc85fa5da78edacffe82e363573d229bdfc4f805..390832eaf101fba4a640d7c34cbf03a9e3604dde 100644 (file)
@@ -1766,10 +1766,11 @@ CC_internal_rollback(ConnectionClass *self, int rollback_type, BOOL ignore_abort
  * * Send appendq, read result.
  *
  */
-QResultClass *
+QResultHold
 CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UDWORD flag, StatementClass *stmt, const char *appendq)
 {
    CSTR    func = "CC_send_query";
+   QResultHold rhold = {0};
    QResultClass *cmdres = NULL,
               *retres = NULL,
               *res = NULL;
@@ -1815,7 +1816,7 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD
        appendPQExpBuffer(&pbuf, "The connection is down\nFailed to send '%s'", query);
        CC_set_error(self, CONNECTION_COULD_NOT_SEND, pbuf.data, func);
        termPQExpBuffer(&pbuf);
-       return NULL;
+       return rhold;
    }
 
    ENTER_INNER_CONN_CS(self, func_cs_count);
@@ -1823,7 +1824,7 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD
    if ((NULL == query) || (query[0] == '\0'))
    {
        CLEANUP_FUNC_CONN_CS(func_cs_count, self);
-       return NULL;
+       return rhold;
    }
 
    /*
@@ -1833,20 +1834,22 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD
     */
    if (appendq && ignore_roundtrip_time)
    {
-       res = CC_send_query_append(self, query, qi, flag, stmt, NULL);
+       QResultHold rholda;
+
+       rhold = CC_send_query_append(self, query, qi, flag, stmt, NULL);
        if (QR_command_maybe_successful(res))
        {
-           cmdres = CC_send_query_append(self, appendq, qi, flag & (~(GO_INTO_TRANSACTION)), stmt, NULL);
-           if (QR_command_maybe_successful(cmdres))
-               QR_attach(res, cmdres);
+           rholda = CC_send_query_append(self, appendq, qi, flag & (~(GO_INTO_TRANSACTION)), stmt, NULL);
+           if (QR_command_maybe_successful(rholda.first))
+               QR_concat(rhold.last, rholda.first);
            else
            {
-               QR_Destructor(res);
-               res = cmdres;
+               QR_Destructor(rhold.first);
+               rhold = rholda;
            }
        }
        CLEANUP_FUNC_CONN_CS(func_cs_count, self);
-       return res;
+       return rhold;
    }
 
    rollback_on_error = (flag & ROLLBACK_ON_ERROR) != 0;
@@ -1975,7 +1978,7 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD
 
                if (query_completed)    /* allow for "show" style notices */
                {
-                   QR_attach(res, QR_Constructor());
+                   QR_concat(res, QR_Constructor());
                    if (!QR_nextr(res))
                    {
                        CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.", func);
@@ -2098,7 +2101,7 @@ MYLOG(DETAIL_LOG_LEVEL, "Discarded a RELEASE result\n");
            case PGRES_SINGLE_TUPLE:
                if (query_completed)
                {
-                   QR_attach(res, QR_Constructor());
+                   QR_concat(res, QR_Constructor());
                    if (!QR_nextr(res))
                    {
                        CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.", func);
@@ -2191,7 +2194,7 @@ MYLOG(DETAIL_LOG_LEVEL, "Discarded a RELEASE result\n");
            case PGRES_COPY_IN:
                if (query_completed)
                {
-                   QR_attach(res, QR_Constructor());
+                   QR_concat(res, QR_Constructor());
                    if (!QR_nextr(res))
                    {
                        CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.", func);
@@ -2337,7 +2340,7 @@ MYLOG(DETAIL_LOG_LEVEL, " ignored abort_on_conn\n");
 
    if (retres)
        QR_set_conn(retres, self);
-   return retres;
+   return (QResultHold) {retres, res};
 }
 
 #define MAX_SEND_FUNC_ARGS 3
@@ -3092,7 +3095,7 @@ my_appendPQExpBuffer(PQExpBufferData *buf, const char *fmt, const char *s, ssize
 
 /*
  * my_appendPQExpBuffer1 is a extension of my_appendPQExpBuffer.
- * It can have 1 more parameter than my_aapendPQExpBuffer.
+ * It can have 1 more parameter than my_appendPQExpBuffer.
  */
 static void
 my_appendPQExpBuffer1(PQExpBufferData *buf, const char *fmt, const char *s1, const char *s)
@@ -3578,7 +3581,7 @@ CC_set_transact(ConnectionClass *self, UInt4 isolation)
    if (self->default_isolation == 0)
        bShow = TRUE;
    if (bShow)
-       res = CC_send_query_append(self, ISOLATION_SHOW_QUERY, NULL, READ_ONLY_QUERY, NULL, query);
+       res = CC_send_query_append(self, ISOLATION_SHOW_QUERY, NULL, READ_ONLY_QUERY, NULL, query).first;
    else
        res = CC_send_query(self, query, NULL, READ_ONLY_QUERY, NULL);
    if (!QR_command_maybe_successful(res))
index a0026946920891f22095dbdb405e175a322c701d..73e8367db52ac5c37818db9cc97e344b0eaf01f5 100644 (file)
@@ -419,8 +419,8 @@ char        CC_remove_descriptor(ConnectionClass *self, DescriptorClass *desc);
 void       CC_set_error(ConnectionClass *self, int number, const char *message, const char *func);
 void       CC_set_errormsg(ConnectionClass *self, const char *message);
 char       CC_get_error(ConnectionClass *self, int *number, char **message);
-QResultClass *CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UDWORD flag, StatementClass *stmt, const char *appendq);
-#define CC_send_query(self, query, qi, flag, stmt) CC_send_query_append(self, query, qi, flag, stmt, NULL)
+QResultHold CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UDWORD flag, StatementClass *stmt, const char *appendq);
+#define CC_send_query(self, query, qi, flag, stmt) CC_send_query_append(self, query, qi, flag, stmt, NULL).first
 void       handle_pgres_error(ConnectionClass *self, const PGresult *pgres,
                   const char *comment,
                   QResultClass *res, BOOL error_not_a_notice);
index dfa4293181ffaac98c50610f68f6bba8ba7e4bd2..89586e2412c772a51a18b999c21189584f2a0861 100644 (file)
@@ -432,6 +432,10 @@ typedef struct IPDFields_ IPDFields;
 typedef struct col_info COL_INFO;
 typedef struct lo_arg LO_ARG;
 
+typedef struct QResultHold_struct {
+   QResultClass *first;
+   QResultClass *last;
+} QResultHold;
 
 /* pgNAME type define */
 typedef struct
index df882d58916f68a12fbf81cd333bfb576a8f2827..721f7feeed25d9919868297301db497c19e360ad 100644 (file)
@@ -378,7 +378,7 @@ SC_Constructor(ConnectionClass *conn)
    {
        rv->hdbc = conn;
        rv->phstmt = NULL;
-       rv->result = NULL;
+       rv->rhold = (QResultHold) {0};
        rv->curres = NULL;
        rv->catalog_result = FALSE;
        rv->prepare = NON_PREPARE_STATEMENT;
@@ -528,22 +528,49 @@ SC_Destructor(StatementClass *self)
 void
 SC_init_Result(StatementClass *self)
 {
-   self->result = self->curres = NULL;
+   self->rhold = (QResultHold) {0};
+   self->curres = NULL;
    self->curr_param_result = 0;
    MYLOG(0, "leaving(%p)\n", self);
 }
 
 void
-SC_set_Result(StatementClass *self, QResultClass *res)
+SC_set_Result(StatementClass *self, QResultClass *first)
 {
-   if (res != self->result)
+   if (first != self->rhold.first)
    {
-       MYLOG(0, "(%p, %p)\n", self, res);
-       QR_Destructor(self->result);
-       self->result = self->curres = res;
-       if (NULL != res)
+       QResultClass *last = NULL, *res;
+
+       MYLOG(0, "(%p, %p)\n", self, first);
+       QR_Destructor(self->rhold.first);
+       for (res = first; res; res = QR_nextr(res))
+           last = res;
+       self->curres = first;
+       self->rhold = (QResultHold) {first, last};
+       if (NULL != first)
+           self->curr_param_result = 1;
+   }
+}
+
+void
+SC_set_ResultHold(StatementClass *self, QResultHold rhold)
+{
+   if (rhold.first != self->rhold.first)
+   {
+       MYLOG(0, "(%p, {%p, %p})\n", self, rhold.first, rhold.last);
+       QR_Destructor(self->rhold.first);
+       self->curres = rhold.first;
+       self->rhold = rhold;
+       if (NULL != rhold.first)
            self->curr_param_result = 1;
    }
+   else if (rhold.last != self->rhold.last)
+   {
+       self->rhold.last = rhold.last;
+       if (QR_nextr(rhold.last) != NULL)
+           SC_set_error(self, STMT_INTERNAL_ERROR, "last Result is not the last result", __FUNCTION__);
+   }
+
 }
 
 /*
@@ -1842,7 +1869,6 @@ SC_execute(StatementClass *self)
    ConnectionClass *conn;
    IPDFields   *ipdopts;
    char        was_ok, was_nonfatal;
-   QResultClass    *res = NULL;
    Int2        oldstatus,
                numcols;
    QueryInfo   qi;
@@ -1855,6 +1881,7 @@ SC_execute(StatementClass *self)
    int     errnum_sav = STMT_OK, errnum;
    char        *errmsg_sav = NULL;
    SQLULEN     stmt_timeout;
+   QResultHold rhold = {0};
 
    conn = SC_get_conn(self);
    ci = &(conn->connInfo);
@@ -1943,6 +1970,7 @@ SC_execute(StatementClass *self)
    if (conn->stmt_timeout_in_effect != stmt_timeout)
    {
        char query[64];
+       QResultClass *res;
 
        SPRINTF_FIXED(query, "SET statement_timeout = %d",
                 (int) stmt_timeout * 1000);
@@ -1975,11 +2003,13 @@ SC_execute(StatementClass *self)
    isSelectType = (SC_may_use_cursor(self) || self->statement_type == STMT_TYPE_PROCCALL);
    if (use_extended_protocol)
    {
+       QResultClass *first;
+
        if (issue_begin)
            CC_begin(conn);
 
-       res = libpq_bind_and_exec(self);
-       if (!res)
+       first = libpq_bind_and_exec(self);
+       if (!first)
        {
            if (SC_get_errornumber(self) <= 0)
            {
@@ -1987,12 +2017,14 @@ SC_execute(StatementClass *self)
            }
            goto cleanup;
        }
+       rhold = (QResultHold) {first, first};
    }
    else if (isSelectType)
    {
        char        fetch[128];
        const char *appendq = NULL;
        QueryInfo   *qryi = NULL;
+       QResultClass *first;
 
        qflag |= (SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency ? CREATE_KEYSET : 0);
        MYLOG(0, "       Sending SELECT statement on stmt=%p, cursor_name='%s' qflag=%d," FORMAT_UINTEGER "\n", self, SC_cursor_name(self), qflag, self->options.scroll_concurrency);
@@ -2010,11 +2042,12 @@ SC_execute(StatementClass *self)
            appendq = fetch;
            qflag &= (~READ_ONLY_QUERY); /* must be a SAVEPOINT after DECLARE */
        }
-       res = SC_get_Result(self);
-       if (self->curr_param_result && res)
-           SC_set_Result(self, QR_nextr(res));
-       res = CC_send_query_append(conn, self->stmt_with_params, qryi, qflag, SC_get_ancestor(self), appendq);
-       if (useCursor && QR_command_maybe_successful(res))
+       first = SC_get_Result(self);
+       if (self->curr_param_result && first)
+           SC_set_Result(self, QR_nextr(first));
+       rhold = CC_send_query_append(conn, self->stmt_with_params, qryi, qflag, SC_get_ancestor(self), appendq);
+       first = rhold.first;    
+       if (useCursor && QR_command_maybe_successful(first))
        {
            /*
             * If we sent a DECLARE CURSOR + FETCH, throw away the result of
@@ -2026,7 +2059,7 @@ SC_execute(StatementClass *self)
            {
                QResultClass    *qres, *nres;
 
-               for (qres = res; qres;)
+               for (qres = first; qres;)
                {
                    if (qres->command && strnicmp(qres->command, "fetch", 5) == 0)
                    {
@@ -2053,10 +2086,11 @@ SC_execute(StatementClass *self)
                    if (qres->num_cached_rows < qi.row_size)
                        QR_set_reached_eof(qres);
                }
-               res = qres;
+               first = qres;
+               rhold.first = first;
            }
-           if (res && SC_is_with_hold(self))
-               QR_set_withhold(res);
+           if (first && SC_is_with_hold(self))
+               QR_set_withhold(first);
        }
        MYLOG(0, "     done sending the query:\n");
    }
@@ -2064,7 +2098,7 @@ SC_execute(StatementClass *self)
    {
        /* not a SELECT statement so don't use a cursor */
        MYLOG(0, "      it's NOT a select statement: stmt=%p\n", self);
-       res = CC_send_query(conn, self->stmt_with_params, NULL, qflag, SC_get_ancestor(self));
+       rhold = CC_send_query_append(conn, self->stmt_with_params, NULL, qflag, SC_get_ancestor(self), NULL);
    }
 
    if (!isSelectType)
@@ -2093,10 +2127,12 @@ SC_execute(StatementClass *self)
    LEAVE_INNER_CONN_CS(func_cs_count, conn);
 
    /* Check the status of the result */
-   if (res)
+   if (rhold.first)
    {
-       was_ok = QR_command_successful(res);
-       was_nonfatal = QR_command_nonfatal(res);
+       QResultClass *first = rhold.first;
+
+       was_ok = QR_command_successful(first);
+       was_nonfatal = QR_command_nonfatal(first);
 
        if (0 < SC_get_errornumber(self))
            ;
@@ -2113,14 +2149,14 @@ SC_execute(StatementClass *self)
                SC_set_errornumber(self, STMT_INFO_ONLY);
        }
        else
-           SC_set_errorinfo(self, res, 0);
+           SC_set_errorinfo(self, first, 0);
        /* set cursor before the first tuple in the list */
        self->currTuple = -1;
        SC_set_current_col(self, -1);
        SC_set_rowset_start(self, -1, FALSE);
 
        /* issue "ABORT" when query aborted */
-       if (QR_get_aborted(res))
+       if (QR_get_aborted(first))
        {
        }
        else
@@ -2128,7 +2164,7 @@ SC_execute(StatementClass *self)
            QResultClass    *tres;
 
            /* see if the query did return any result columns */
-           for (tres = res, numcols = 0; !numcols && tres; tres = QR_nextr(tres))
+           for (tres = first, numcols = 0; !numcols && tres; tres = QR_nextr(tres))
            {
                numcols = QR_NumResultCols(tres);
            }
@@ -2139,13 +2175,13 @@ SC_execute(StatementClass *self)
                extend_column_bindings(opts, numcols);
                if (opts->bindings == NULL)
                {
-                   QR_Destructor(res);
+                   QR_Destructor(first);
                    SC_set_error(self, STMT_NO_MEMORY_ERROR,"Could not get enough free memory to store the binding information", func);
                    goto cleanup;
                }
            }
 
-MYLOG(DETAIL_LOG_LEVEL, "!!%p->miscinfo=%x res=%p\n", self, self->miscinfo, res);
+MYLOG(DETAIL_LOG_LEVEL, "!!%p->miscinfo=%x res=%p\n", self, self->miscinfo, first);
            /*
             * special handling of result for keyset driven cursors.
             * Use the columns info of the 1st query and
@@ -2155,16 +2191,14 @@ MYLOG(DETAIL_LOG_LEVEL, "!!%p->miscinfo=%x res=%p\n", self, self->miscinfo, res)
                SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency &&
                !useCursor)
            {
-               if (tres = QR_nextr(res), tres)
+               if (tres = QR_nextr(first), tres)
                {
-                   QR_set_fields(tres, QR_get_fields(res));
-                   QR_set_fields(res,  NULL);
-                   tres->num_fields = res->num_fields;
-                   QR_detach(res);
-                   QR_Destructor(res);
-                   SC_init_Result(self);
+                   QR_set_fields(tres, QR_get_fields(first));
+                   QR_set_fields(first,  NULL);
+                   tres->num_fields = first->num_fields;
+                   QR_detach(first);
                    SC_set_Result(self, tres);
-                   res = tres;
+                   rhold = self->rhold;
                }
            }
        }
@@ -2192,18 +2226,12 @@ MYLOG(DETAIL_LOG_LEVEL, "!!%p->miscinfo=%x res=%p\n", self, self->miscinfo, res)
 
    }
    if (!SC_get_Result(self))
-       SC_set_Result(self, res);
+       SC_set_ResultHold(self, rhold);
    else
    {
-       QResultClass    *last;
-
-       for (last = SC_get_Result(self); NULL != QR_nextr(last); last = QR_nextr(last))
-       {
-           if (last == res)
-               break;
-       }
-       if (last != res)
-           QR_attach(last, res);
+       if (self->rhold.last != rhold.first)
+           QR_concat(self->rhold.last, rhold.first);
+       self->rhold.last = rhold.last;
        self->curr_param_result = 1;
    }
    if (NULL == SC_get_Curres(self))
@@ -2507,7 +2535,7 @@ QResultClass *add_libpq_notice_receiver(StatementClass *stmt, notice_receiver_ar
    QResultClass *res = NULL, *newres = NULL;
 
    if (stmt->curr_param_result)
-       for (res = SC_get_Result(stmt); NULL != res && NULL != QR_nextr(res); res = QR_nextr(res));
+       res = stmt->rhold.last;
    if (!res)
        newres = res = QR_Constructor();
    nrarg->conn = SC_get_conn(stmt);
index 4785e1342100b0a1323872704c3cea6063e30891..84df7de295b3e42f2df977717eea915288eae822 100644 (file)
@@ -205,8 +205,10 @@ struct StatementClass_
 {
    ConnectionClass *hdbc;      /* pointer to ConnectionClass this
                                 * statement belongs to */
-   QResultClass *result;       /* result of the current statement */
+   QResultHold rhold;
+   // QResultClass *result;        /* result of the current statement */
    QResultClass *curres;       /* the current result in the chain */
+   // QResultClass *lastres;       /* maybe the last result in the chain */
    HSTMT      *phstmt;
    StatementOptions options;
    StatementOptions options_orig;
@@ -322,7 +324,9 @@ struct StatementClass_
 #define SC_get_conn(a)   ((a)->hdbc)
 void SC_init_Result(StatementClass *self);
 void SC_set_Result(StatementClass *self, QResultClass *res);
-#define SC_get_Result(a)  ((a)->result)
+void SC_set_ResultHold(StatementClass *self, QResultHold rhold);
+QResultClass *SC_get_lastres(StatementClass *stmt);
+#define SC_get_Result(a)  ((a)->rhold).first
 #define SC_set_Curres(a, b)  ((a)->curres = b)
 #define SC_get_Curres(a)  ((a)->curres)
 #define SC_get_ARD(a)  ((a)->ard)