From d55322b0da60a8798ffdb8b78ef90db0fb5be18e Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 22 Aug 2024 16:25:57 +0900 Subject: psql: Add more meta-commands able to use the extended protocol Currently, only unnamed prepared statement are supported by psql with the meta-command \bind. With only this command, it is not possible to test named statement creation, execution or close through the extended protocol. This commit introduces three additional commands: * \parse creates a prepared statement using the extended protocol, acting as a wrapper of libpq's PQsendPrepare(). * \bind_named binds and executes an existing prepared statement using the extended protocol, for PQsendQueryPrepared(). * \close closes an existing prepared statement using the extended protocol, for PQsendClosePrepared(). This is going to be useful to add regression tests for the extended query protocol, and I have some plans for that on separate threads. Note that \bind relies on PQsendQueryParams(). The code of psql is refactored so as bind_flag is replaced by an enum in _psqlSettings that tracks the type of libpq routine to execute, based on the meta-command involved, with the default being PQsendQuery(). This refactoring piece has been written by me, while Anthonin has implemented the rest. Author: Anthonin Bonnefoy, Michael Paquier Reviewed-by: Aleksander Alekseev, Jelte Fennema-Nio Discussion: https://postgr.es/m/CAO6_XqpSq0Q0kQcVLCbtagY94V2GxNP3zCnR6WnOM8WqXPK4nw@mail.gmail.com --- src/bin/psql/common.c | 59 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 12 deletions(-) (limited to 'src/bin/psql/common.c') diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index fe8e049c4c1..be265aa05a4 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -1274,15 +1274,28 @@ sendquery_cleanup: pset.gsavepopt = NULL; } - /* clean up after \bind */ - if (pset.bind_flag) + /* clean up after extended protocol queries */ + switch (pset.send_mode) { - for (i = 0; i < pset.bind_nparams; i++) - free(pset.bind_params[i]); - free(pset.bind_params); - pset.bind_params = NULL; - pset.bind_flag = false; + case PSQL_SEND_EXTENDED_CLOSE: /* \close */ + free(pset.stmtName); + break; + case PSQL_SEND_EXTENDED_PARSE: /* \parse */ + free(pset.stmtName); + break; + case PSQL_SEND_EXTENDED_QUERY_PARAMS: /* \bind */ + case PSQL_SEND_EXTENDED_QUERY_PREPARED: /* \bind_named */ + for (i = 0; i < pset.bind_nparams; i++) + free(pset.bind_params[i]); + free(pset.bind_params); + free(pset.stmtName); + pset.bind_params = NULL; + break; + case PSQL_SEND_QUERY: + break; } + pset.stmtName = NULL; + pset.send_mode = PSQL_SEND_QUERY; /* reset \gset trigger */ if (pset.gset_prefix) @@ -1456,7 +1469,7 @@ ExecQueryAndProcessResults(const char *query, const printQueryOpt *opt, FILE *printQueryFout) { bool timing = pset.timing; - bool success; + bool success = false; bool return_early = false; instr_time before, after; @@ -1469,10 +1482,32 @@ ExecQueryAndProcessResults(const char *query, else INSTR_TIME_SET_ZERO(before); - if (pset.bind_flag) - success = PQsendQueryParams(pset.db, query, pset.bind_nparams, NULL, (const char *const *) pset.bind_params, NULL, NULL, 0); - else - success = PQsendQuery(pset.db, query); + switch (pset.send_mode) + { + case PSQL_SEND_EXTENDED_CLOSE: + success = PQsendClosePrepared(pset.db, pset.stmtName); + break; + case PSQL_SEND_EXTENDED_PARSE: + success = PQsendPrepare(pset.db, pset.stmtName, query, 0, NULL); + break; + case PSQL_SEND_EXTENDED_QUERY_PARAMS: + Assert(pset.stmtName == NULL); + success = PQsendQueryParams(pset.db, query, + pset.bind_nparams, NULL, + (const char *const *) pset.bind_params, + NULL, NULL, 0); + break; + case PSQL_SEND_EXTENDED_QUERY_PREPARED: + Assert(pset.stmtName != NULL); + success = PQsendQueryPrepared(pset.db, pset.stmtName, + pset.bind_nparams, + (const char *const *) pset.bind_params, + NULL, NULL, 0); + break; + case PSQL_SEND_QUERY: + success = PQsendQuery(pset.db, query); + break; + } if (!success) { -- cgit v1.2.3