</para>
<para>
- In pipeline mode, command strings containing more than one SQL command
- are disallowed.
+ In pipeline mode, this function is disallowed.
</para>
</listitem>
</varlistentry>
<xref linkend="libpq-PQpipelineStatus"/> can be used
to test whether pipeline mode is active.
In pipeline mode, only <link linkend="libpq-async">asynchronous operations</link>
+ that utilize the extended query protocol
are permitted, command strings containing multiple SQL commands are
disallowed, and so is <literal>COPY</literal>.
Using synchronous command execution functions
<function>PQdescribePrepared</function>,
<function>PQdescribePortal</function>,
is an error condition.
+ <function>PQsendQuery</function> is
+ also disallowed, because it uses the simple query protocol.
Once all dispatched commands have had their results processed, and
the end pipeline result has been consumed, the application may return
to non-pipelined mode with <xref linkend="libpq-PQexitPipelineMode"/>.
<para>
After entering pipeline mode, the application dispatches requests using
- <xref linkend="libpq-PQsendQuery"/>,
- <xref linkend="libpq-PQsendQueryParams"/>,
+ <xref linkend="libpq-PQsendQueryParams"/>
or its prepared-query sibling
<xref linkend="libpq-PQsendQueryPrepared"/>.
These requests are queued on the client-side until flushed to the server;
PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery)
{
PGcmdQueueEntry *entry = NULL;
- PGcmdQueueEntry *entry2 = NULL;
if (!PQsendQueryStart(conn, newQuery))
return 0;
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;
}
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);
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;
}