summaryrefslogtreecommitdiff
path: root/src/test/modules/libpq_pipeline/libpq_pipeline.c
diff options
context:
space:
mode:
authorMichael Paquier <michael@paquier.xyz>2023-07-04 14:48:10 +0900
committerMichael Paquier <michael@paquier.xyz>2023-07-04 14:48:10 +0900
commit28b5726561841556dc3e00ffe26b01a8107ee654 (patch)
tree79a4dad5f2ebae14b3ed650b367a79d7a1f23964 /src/test/modules/libpq_pipeline/libpq_pipeline.c
parent03f80daac8cff257294108caf908fe0397c40e1a (diff)
libpq: Add support for Close on portals and statements
The following routines are added to libpq: PGresult *PQclosePrepared(PGconn *conn, const char *stmt); PGresult *PQclosePortal(PGconn *conn, const char *portal); int PQsendClosePrepared(PGconn *conn, const char *stmt); int PQsendClosePortal(PGconn *conn, const char *portal); The "send" routines are non-blocking versions of the two others. Close messages are part of the protocol but they did not have a libpq implementation. And, having these routines is for instance useful with connection poolers as these can detect more easily Close messages than DEALLOCATE queries. The implementation takes advantage of what the Describe routines rely on for portals and statements. Some regression tests are added in libpq_pipeline, for the four new routines, by closing portals and statements created already by the tests. Author: Jelte Fennema Reviewed-by: Jian He, Michael Paquier Discussion: https://postgr.es/m/CAGECzQTb4xFAopAVokudB+L62Kt44mNAL4Z9zZ7UTrs1TRFvWA@mail.gmail.com
Diffstat (limited to 'src/test/modules/libpq_pipeline/libpq_pipeline.c')
-rw-r--r--src/test/modules/libpq_pipeline/libpq_pipeline.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/src/test/modules/libpq_pipeline/libpq_pipeline.c b/src/test/modules/libpq_pipeline/libpq_pipeline.c
index 1933b078ebf..9907bc86004 100644
--- a/src/test/modules/libpq_pipeline/libpq_pipeline.c
+++ b/src/test/modules/libpq_pipeline/libpq_pipeline.c
@@ -947,9 +947,42 @@ test_prepared(PGconn *conn)
if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("expected PGRES_PIPELINE_SYNC, got %s", PQresStatus(PQresultStatus(res)));
+ fprintf(stderr, "closing statement..");
+ if (PQsendClosePrepared(conn, "select_one") != 1)
+ pg_fatal("PQsendClosePrepared failed: %s", PQerrorMessage(conn));
+ if (PQpipelineSync(conn) != 1)
+ pg_fatal("pipeline sync failed: %s", PQerrorMessage(conn));
+
+ res = PQgetResult(conn);
+ if (res == NULL)
+ pg_fatal("expected non-NULL result");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ pg_fatal("expected COMMAND_OK, got %s", PQresStatus(PQresultStatus(res)));
+ PQclear(res);
+ res = PQgetResult(conn);
+ if (res != NULL)
+ pg_fatal("expected NULL result");
+ res = PQgetResult(conn);
+ if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
+ pg_fatal("expected PGRES_PIPELINE_SYNC, got %s", PQresStatus(PQresultStatus(res)));
+
if (PQexitPipelineMode(conn) != 1)
pg_fatal("could not exit pipeline mode: %s", PQerrorMessage(conn));
+ /* Now that it's closed we should get an error when describing */
+ res = PQdescribePrepared(conn, "select_one");
+ if (PQresultStatus(res) != PGRES_FATAL_ERROR)
+ pg_fatal("expected FATAL_ERROR, got %s", PQresStatus(PQresultStatus(res)));
+
+ /*
+ * Also test the blocking close, this should not fail since closing a
+ * non-existent prepared statement is a no-op
+ */
+ res = PQclosePrepared(conn, "select_one");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ pg_fatal("expected COMMAND_OK, got %s", PQresStatus(PQresultStatus(res)));
+
+ fprintf(stderr, "creating portal... ");
PQexec(conn, "BEGIN");
PQexec(conn, "DECLARE cursor_one CURSOR FOR SELECT 1");
PQenterPipelineMode(conn);
@@ -975,9 +1008,41 @@ test_prepared(PGconn *conn)
if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("expected PGRES_PIPELINE_SYNC, got %s", PQresStatus(PQresultStatus(res)));
+ fprintf(stderr, "closing portal... ");
+ if (PQsendClosePortal(conn, "cursor_one") != 1)
+ pg_fatal("PQsendClosePortal failed: %s", PQerrorMessage(conn));
+ if (PQpipelineSync(conn) != 1)
+ pg_fatal("pipeline sync failed: %s", PQerrorMessage(conn));
+
+ res = PQgetResult(conn);
+ if (res == NULL)
+ pg_fatal("expected non-NULL result");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ pg_fatal("expected COMMAND_OK, got %s", PQresStatus(PQresultStatus(res)));
+ PQclear(res);
+ res = PQgetResult(conn);
+ if (res != NULL)
+ pg_fatal("expected NULL result");
+ res = PQgetResult(conn);
+ if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
+ pg_fatal("expected PGRES_PIPELINE_SYNC, got %s", PQresStatus(PQresultStatus(res)));
+
if (PQexitPipelineMode(conn) != 1)
pg_fatal("could not exit pipeline mode: %s", PQerrorMessage(conn));
+ /* Now that it's closed we should get an error when describing */
+ res = PQdescribePortal(conn, "cursor_one");
+ if (PQresultStatus(res) != PGRES_FATAL_ERROR)
+ pg_fatal("expected FATAL_ERROR, got %s", PQresStatus(PQresultStatus(res)));
+
+ /*
+ * Also test the blocking close, this should not fail since closing a
+ * non-existent portal is a no-op
+ */
+ res = PQclosePortal(conn, "cursor_one");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ pg_fatal("expected COMMAND_OK, got %s", PQresStatus(PQresultStatus(res)));
+
fprintf(stderr, "ok\n");
}