diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/interfaces/libpq/fe-exec.c | 117 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-protocol3.c | 18 | ||||
-rw-r--r-- | src/test/modules/libpq_pipeline/libpq_pipeline.c | 12 |
3 files changed, 36 insertions, 111 deletions
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 97f6894244d..0274c1b156c 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -1433,7 +1433,6 @@ static int PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery) { PGcmdQueueEntry *entry = NULL; - PGcmdQueueEntry *entry2 = NULL; if (!PQsendQueryStart(conn, newQuery)) return 0; @@ -1446,103 +1445,48 @@ PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery) return 0; } - entry = pqAllocCmdQueueEntry(conn); - if (entry == NULL) - return 0; /* error msg already set */ if (conn->pipelineStatus != PQ_PIPELINE_OFF) { - entry2 = pqAllocCmdQueueEntry(conn); - if (entry2 == NULL) - goto sendFailed; + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("%s not allowed in pipeline mode\n"), + "PQsendQuery"); + return 0; } + entry = pqAllocCmdQueueEntry(conn); + if (entry == NULL) + return 0; /* error msg already set */ + /* Send the query message(s) */ - if (conn->pipelineStatus == PQ_PIPELINE_OFF) + /* construct the outgoing Query message */ + if (pqPutMsgStart('Q', conn) < 0 || + pqPuts(query, conn) < 0 || + pqPutMsgEnd(conn) < 0) { - /* construct the outgoing Query message */ - if (pqPutMsgStart('Q', conn) < 0 || - pqPuts(query, conn) < 0 || - pqPutMsgEnd(conn) < 0) - { - /* error message should be set up already */ - pqRecycleCmdQueueEntry(conn, entry); - return 0; - } - - /* remember we are using simple query protocol */ - entry->queryclass = PGQUERY_SIMPLE; - /* and remember the query text too, if possible */ - entry->query = strdup(query); + /* error message should be set up already */ + pqRecycleCmdQueueEntry(conn, entry); + return 0; } - else - { - /* - * In pipeline mode we cannot use the simple protocol, so we send - * Parse, Bind, Describe Portal, Execute, Close Portal (with the - * unnamed portal). - */ - if (pqPutMsgStart('P', conn) < 0 || - pqPuts("", conn) < 0 || - pqPuts(query, conn) < 0 || - pqPutInt(0, 2, conn) < 0 || - pqPutMsgEnd(conn) < 0) - goto sendFailed; - if (pqPutMsgStart('B', conn) < 0 || - pqPuts("", conn) < 0 || - pqPuts("", conn) < 0 || - pqPutInt(0, 2, conn) < 0 || - pqPutInt(0, 2, conn) < 0 || - pqPutInt(0, 2, conn) < 0 || - pqPutMsgEnd(conn) < 0) - goto sendFailed; - if (pqPutMsgStart('D', conn) < 0 || - pqPutc('P', conn) < 0 || - pqPuts("", conn) < 0 || - pqPutMsgEnd(conn) < 0) - goto sendFailed; - if (pqPutMsgStart('E', conn) < 0 || - pqPuts("", conn) < 0 || - pqPutInt(0, 4, conn) < 0 || - pqPutMsgEnd(conn) < 0) - goto sendFailed; - if (pqPutMsgStart('C', conn) < 0 || - pqPutc('P', conn) < 0 || - pqPuts("", conn) < 0 || - pqPutMsgEnd(conn) < 0) - goto sendFailed; - entry->queryclass = PGQUERY_EXTENDED; - entry->query = strdup(query); - } + /* remember we are using simple query protocol */ + entry->queryclass = PGQUERY_SIMPLE; + /* and remember the query text too, if possible */ + entry->query = strdup(query); /* * Give the data a push. In nonblock mode, don't complain if we're unable * to send it all; PQgetResult() will do any additional flushing needed. */ - if (pqPipelineFlush(conn) < 0) + if (pqFlush(conn) < 0) goto sendFailed; /* OK, it's launched! */ pqAppendCmdQueueEntry(conn, entry); - /* - * When pipeline mode is in use, we need a second entry in the command - * queue to represent Close Portal message. This allows us later to wait - * for the CloseComplete message to be received before getting in IDLE - * state. - */ - if (conn->pipelineStatus != PQ_PIPELINE_OFF) - { - entry2->queryclass = PGQUERY_CLOSE; - entry2->query = NULL; - pqAppendCmdQueueEntry(conn, entry2); - } - return 1; sendFailed: pqRecycleCmdQueueEntry(conn, entry); - pqRecycleCmdQueueEntry(conn, entry2); /* error message should be set up already */ return 0; } @@ -2246,22 +2190,6 @@ PQgetResult(PGconn *conn) break; } - /* If the next command we expect is CLOSE, read and consume it */ - if (conn->asyncStatus == PGASYNC_PIPELINE_IDLE && - conn->cmd_queue_head && - conn->cmd_queue_head->queryclass == PGQUERY_CLOSE) - { - if (res && res->resultStatus != PGRES_FATAL_ERROR) - { - conn->asyncStatus = PGASYNC_BUSY; - parseInput(conn); - conn->asyncStatus = PGASYNC_PIPELINE_IDLE; - } - else - /* we won't ever see the Close */ - pqCommandQueueAdvance(conn); - } - /* Time to fire PGEVT_RESULTCREATE events, if there are any */ if (res && res->nEvents > 0) (void) PQfireResultCreateEvents(conn, res); @@ -2977,8 +2905,9 @@ PQfn(PGconn *conn, if (conn->pipelineStatus != PQ_PIPELINE_OFF) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("PQfn not allowed in pipeline mode\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("%s not allowed in pipeline mode\n"), + "PQfn"); return NULL; } diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index bbfb55542df..f001137b769 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -282,24 +282,8 @@ pqParseInput3(PGconn *conn) } break; case '2': /* Bind Complete */ - /* Nothing to do for this message type */ - break; case '3': /* Close Complete */ - /* - * If we get CloseComplete when waiting for it, consume - * the queue element and keep going. A result is not - * expected from this message; it is just there so that - * we know to wait for it when PQsendQuery is used in - * pipeline mode, before going in IDLE state. Failing to - * do this makes us receive CloseComplete when IDLE, which - * creates problems. - */ - if (conn->cmd_queue_head && - conn->cmd_queue_head->queryclass == PGQUERY_CLOSE) - { - pqCommandQueueAdvance(conn); - } - + /* Nothing to do for these message types */ break; case 'S': /* parameter status */ if (getParameterStatus(conn)) diff --git a/src/test/modules/libpq_pipeline/libpq_pipeline.c b/src/test/modules/libpq_pipeline/libpq_pipeline.c index de4d75cfa82..c609f422589 100644 --- a/src/test/modules/libpq_pipeline/libpq_pipeline.c +++ b/src/test/modules/libpq_pipeline/libpq_pipeline.c @@ -106,6 +106,18 @@ test_disallowed_in_pipeline(PGconn *conn) res = PQexec(conn, "SELECT 1"); if (PQresultStatus(res) != PGRES_FATAL_ERROR) pg_fatal("PQexec should fail in pipeline mode but succeeded"); + if (strcmp(PQerrorMessage(conn), + "synchronous command execution functions are not allowed in pipeline mode\n") != 0) + pg_fatal("did not get expected error message; got: \"%s\"", + PQerrorMessage(conn)); + + /* PQsendQuery should fail in pipeline mode */ + if (PQsendQuery(conn, "SELECT 1") != 0) + pg_fatal("PQsendQuery should fail in pipeline mode but succeeded"); + if (strcmp(PQerrorMessage(conn), + "PQsendQuery not allowed in pipeline mode\n") != 0) + pg_fatal("did not get expected error message; got: \"%s\"", + PQerrorMessage(conn)); /* Entering pipeline mode when already in pipeline mode is OK */ if (PQenterPipelineMode(conn) != 1) |