diff options
author | Michael Paquier <michael@paquier.xyz> | 2023-07-04 14:48:10 +0900 |
---|---|---|
committer | Michael Paquier <michael@paquier.xyz> | 2023-07-04 14:48:10 +0900 |
commit | 28b5726561841556dc3e00ffe26b01a8107ee654 (patch) | |
tree | 79a4dad5f2ebae14b3ed650b367a79d7a1f23964 /src/test/modules/libpq_pipeline/libpq_pipeline.c | |
parent | 03f80daac8cff257294108caf908fe0397c40e1a (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.c | 65 |
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"); } |