aboutsummaryrefslogtreecommitdiff
path: root/src/test/modules/libpq_pipeline/libpq_pipeline.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2024-04-06 20:41:32 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2024-04-06 20:45:11 -0400
commit4643a2b265e967cc5f13ffa0c7c6912dbb3466d0 (patch)
treeae3c3e182c5e0586dcecd93f0957deb2d0416b68 /src/test/modules/libpq_pipeline/libpq_pipeline.c
parent92641d8d651e685b49a6e2842d306aa5fe7ba500 (diff)
downloadpostgresql-4643a2b265e967cc5f13ffa0c7c6912dbb3466d0.tar.gz
postgresql-4643a2b265e967cc5f13ffa0c7c6912dbb3466d0.zip
Support retrieval of results in chunks with libpq.
This patch generalizes libpq's existing single-row mode to allow individual partial-result PGresults to contain up to N rows, rather than always one row. This reduces malloc overhead compared to plain single-row mode, and it is very useful for psql's FETCH_COUNT feature, since otherwise we'd have to add code (and cycles) to either merge single-row PGresults into a bigger one or teach psql's results-printing logic to accept arrays of PGresults. To avoid API breakage, PQsetSingleRowMode() remains the same, and we add a new function PQsetChunkedRowsMode() to invoke the more general case. Also, PGresults obtained the old way continue to carry the PGRES_SINGLE_TUPLE status code, while if PQsetChunkedRowsMode() is used then their status code is PGRES_TUPLES_CHUNK. The underlying logic is the same either way, though. Daniel Vérité, reviewed by Laurenz Albe and myself (and whacked around a bit by me, so any remaining bugs are my fault) Discussion: https://postgr.es/m/CAKZiRmxsVTkO928CM+-ADvsMyePmU3L9DQCa9NwqjvLPcEe5QA@mail.gmail.com
Diffstat (limited to 'src/test/modules/libpq_pipeline/libpq_pipeline.c')
-rw-r--r--src/test/modules/libpq_pipeline/libpq_pipeline.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/src/test/modules/libpq_pipeline/libpq_pipeline.c b/src/test/modules/libpq_pipeline/libpq_pipeline.c
index b7e7a0947cb..928ef6b1700 100644
--- a/src/test/modules/libpq_pipeline/libpq_pipeline.c
+++ b/src/test/modules/libpq_pipeline/libpq_pipeline.c
@@ -1719,6 +1719,46 @@ test_singlerowmode(PGconn *conn)
if (PQgetResult(conn) != NULL)
pg_fatal("expected NULL result");
+ /*
+ * Try chunked mode as well; make sure that it correctly delivers a
+ * partial final chunk.
+ */
+ if (PQsendQueryParams(conn, "SELECT generate_series(1, 5)",
+ 0, NULL, NULL, NULL, NULL, 0) != 1)
+ pg_fatal("failed to send query: %s",
+ PQerrorMessage(conn));
+ if (PQsendFlushRequest(conn) != 1)
+ pg_fatal("failed to send flush request");
+ if (PQsetChunkedRowsMode(conn, 3) != 1)
+ pg_fatal("PQsetChunkedRowsMode() failed");
+ res = PQgetResult(conn);
+ if (res == NULL)
+ pg_fatal("unexpected NULL");
+ if (PQresultStatus(res) != PGRES_TUPLES_CHUNK)
+ pg_fatal("Expected PGRES_TUPLES_CHUNK, got %s: %s",
+ PQresStatus(PQresultStatus(res)),
+ PQerrorMessage(conn));
+ if (PQntuples(res) != 3)
+ pg_fatal("Expected 3 rows, got %d", PQntuples(res));
+ res = PQgetResult(conn);
+ if (res == NULL)
+ pg_fatal("unexpected NULL");
+ if (PQresultStatus(res) != PGRES_TUPLES_CHUNK)
+ pg_fatal("Expected PGRES_TUPLES_CHUNK, got %s",
+ PQresStatus(PQresultStatus(res)));
+ if (PQntuples(res) != 2)
+ pg_fatal("Expected 2 rows, got %d", PQntuples(res));
+ res = PQgetResult(conn);
+ if (res == NULL)
+ pg_fatal("unexpected NULL");
+ if (PQresultStatus(res) != PGRES_TUPLES_OK)
+ pg_fatal("Expected PGRES_TUPLES_OK, got %s",
+ PQresStatus(PQresultStatus(res)));
+ if (PQntuples(res) != 0)
+ pg_fatal("Expected 0 rows, got %d", PQntuples(res));
+ if (PQgetResult(conn) != NULL)
+ pg_fatal("expected NULL result");
+
if (PQexitPipelineMode(conn) != 1)
pg_fatal("failed to end pipeline mode: %s", PQerrorMessage(conn));