Hi, I notice that PQsetSingleRowMode() doesn't work when getting batch results.
The function is documented as: " int PQsetSingleRowMode(PGconn *conn); This function can only be called immediately after PQsendQuery or one of its sibling functions, before any other operation on the connection such as PQconsumeInput or PQgetResult" But PQbatchQueueProcess() unconditionally clears conn->singleRowMode, so whatever it was when sending the query gets lost, and besides other queries might have been submitted in the meantime. Also if trying to set that mode when fetching like this while (QbatchQueueProcess(conn)) { r = PQsetSingleRowMode(conn); if (r!=1) { fprintf(stderr, "PQsetSingleRowMode() failed"); } .. it might work the first time, but on the next iterations, conn->asyncStatus might be PGASYNC_READY, which is a failure condition for PQsetSingleRowMode(), so that won't do. ISTM that the simplest fix would be that when in batch mode, PQsetSingleRowMode() should register that the last submitted query does request that mode, and when later QbatchQueueProcess dequeues the batch entry for the corresponding query, this flag would be popped off and set as the current mode. Please find attached the suggested fix, against the v5 of the patch. Best regards, -- Daniel Vérité PostgreSQL-powered mailer: http://www.manitou-mail.org Twitter: @DanielVerite
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 3c0be46..8ddf63d 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -1425,7 +1425,7 @@ PQmakePipelinedCommand(PGconn *conn) } entry->next = NULL; entry->query = NULL; - + entry->singleRowMode = false; return entry; } @@ -1783,16 +1783,28 @@ PQsetSingleRowMode(PGconn *conn) /* * Only allow setting the flag when we have launched a query and not yet * received any results. + * In batch mode, store the flag in the queue for applying it later. */ if (!conn) return 0; - if (conn->asyncStatus != PGASYNC_BUSY) - return 0; if (conn->queryclass != PGQUERY_SIMPLE && conn->queryclass != PGQUERY_EXTENDED) return 0; if (conn->result) return 0; + if (conn->batch_status == PQBATCH_MODE_OFF) + { + if (conn->asyncStatus != PGASYNC_BUSY) + return 0; + } + else + { + /* apply to the last submitted query in the batch, or fail */ + if (conn->cmd_queue_tail != NULL) + conn->cmd_queue_tail->singleRowMode = true; + else + return 0; + } /* OK, set flag */ conn->singleRowMode = true; @@ -2120,9 +2132,8 @@ PQbatchQueueProcess(PGconn *conn) * Initialize async result-accumulation state */ pqClearAsyncResult(conn); - /* reset single-row processing mode */ - conn->singleRowMode = false; - + /* Set single-row processing mode */ + conn->singleRowMode = next_query->singleRowMode; conn->last_query = next_query->query; next_query->query = NULL; diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 33f212f..af4f753 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -315,6 +315,7 @@ typedef struct pgCommandQueueEntry { PGQueryClass queryclass; /* Query type; PGQUERY_SYNC for sync msg */ char *query; /* SQL command, or NULL if unknown */ + bool singleRowMode; /* apply single row mode to this query */ struct pgCommandQueueEntry *next; } PGcommandQueueEntry;
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers