mirror of
https://github.com/postgres/postgres.git
synced 2025-06-30 21:42:05 +03:00
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
This commit is contained in:
@ -64,10 +64,14 @@ static backslashResult exec_command(const char *cmd,
|
||||
PQExpBuffer previous_buf);
|
||||
static backslashResult exec_command_a(PsqlScanState scan_state, bool active_branch);
|
||||
static backslashResult exec_command_bind(PsqlScanState scan_state, bool active_branch);
|
||||
static backslashResult exec_command_bind_named(PsqlScanState scan_state, bool active_branch,
|
||||
const char *cmd);
|
||||
static backslashResult exec_command_C(PsqlScanState scan_state, bool active_branch);
|
||||
static backslashResult exec_command_connect(PsqlScanState scan_state, bool active_branch);
|
||||
static backslashResult exec_command_cd(PsqlScanState scan_state, bool active_branch,
|
||||
const char *cmd);
|
||||
static backslashResult exec_command_close(PsqlScanState scan_state, bool active_branch,
|
||||
const char *cmd);
|
||||
static backslashResult exec_command_conninfo(PsqlScanState scan_state, bool active_branch);
|
||||
static backslashResult exec_command_copy(PsqlScanState scan_state, bool active_branch);
|
||||
static backslashResult exec_command_copyright(PsqlScanState scan_state, bool active_branch);
|
||||
@ -116,6 +120,8 @@ static backslashResult exec_command_lo(PsqlScanState scan_state, bool active_bra
|
||||
static backslashResult exec_command_out(PsqlScanState scan_state, bool active_branch);
|
||||
static backslashResult exec_command_print(PsqlScanState scan_state, bool active_branch,
|
||||
PQExpBuffer query_buf, PQExpBuffer previous_buf);
|
||||
static backslashResult exec_command_parse(PsqlScanState scan_state, bool active_branch,
|
||||
const char *cmd);
|
||||
static backslashResult exec_command_password(PsqlScanState scan_state, bool active_branch);
|
||||
static backslashResult exec_command_prompt(PsqlScanState scan_state, bool active_branch,
|
||||
const char *cmd);
|
||||
@ -312,12 +318,16 @@ exec_command(const char *cmd,
|
||||
status = exec_command_a(scan_state, active_branch);
|
||||
else if (strcmp(cmd, "bind") == 0)
|
||||
status = exec_command_bind(scan_state, active_branch);
|
||||
else if (strcmp(cmd, "bind_named") == 0)
|
||||
status = exec_command_bind_named(scan_state, active_branch, cmd);
|
||||
else if (strcmp(cmd, "C") == 0)
|
||||
status = exec_command_C(scan_state, active_branch);
|
||||
else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
|
||||
status = exec_command_connect(scan_state, active_branch);
|
||||
else if (strcmp(cmd, "cd") == 0)
|
||||
status = exec_command_cd(scan_state, active_branch, cmd);
|
||||
else if (strcmp(cmd, "close") == 0)
|
||||
status = exec_command_close(scan_state, active_branch, cmd);
|
||||
else if (strcmp(cmd, "conninfo") == 0)
|
||||
status = exec_command_conninfo(scan_state, active_branch);
|
||||
else if (pg_strcasecmp(cmd, "copy") == 0)
|
||||
@ -379,6 +389,8 @@ exec_command(const char *cmd,
|
||||
else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
|
||||
status = exec_command_print(scan_state, active_branch,
|
||||
query_buf, previous_buf);
|
||||
else if (strcmp(cmd, "parse") == 0)
|
||||
status = exec_command_parse(scan_state, active_branch, cmd);
|
||||
else if (strcmp(cmd, "password") == 0)
|
||||
status = exec_command_password(scan_state, active_branch);
|
||||
else if (strcmp(cmd, "prompt") == 0)
|
||||
@ -472,6 +484,7 @@ exec_command_bind(PsqlScanState scan_state, bool active_branch)
|
||||
int nalloc = 0;
|
||||
|
||||
pset.bind_params = NULL;
|
||||
pset.stmtName = NULL;
|
||||
|
||||
while ((opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false)))
|
||||
{
|
||||
@ -485,7 +498,57 @@ exec_command_bind(PsqlScanState scan_state, bool active_branch)
|
||||
}
|
||||
|
||||
pset.bind_nparams = nparams;
|
||||
pset.bind_flag = true;
|
||||
pset.send_mode = PSQL_SEND_EXTENDED_QUERY_PARAMS;
|
||||
}
|
||||
else
|
||||
ignore_slash_options(scan_state);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* \bind_named -- set query parameters for an existing prepared statement
|
||||
*/
|
||||
static backslashResult
|
||||
exec_command_bind_named(PsqlScanState scan_state, bool active_branch,
|
||||
const char *cmd)
|
||||
{
|
||||
backslashResult status = PSQL_CMD_SKIP_LINE;
|
||||
|
||||
if (active_branch)
|
||||
{
|
||||
char *opt;
|
||||
int nparams = 0;
|
||||
int nalloc = 0;
|
||||
|
||||
pset.bind_params = NULL;
|
||||
pset.stmtName = NULL;
|
||||
|
||||
/* get the mandatory prepared statement name */
|
||||
opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
|
||||
if (!opt)
|
||||
{
|
||||
pg_log_error("\\%s: missing required argument", cmd);
|
||||
status = PSQL_CMD_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
pset.stmtName = opt;
|
||||
pset.send_mode = PSQL_SEND_EXTENDED_QUERY_PREPARED;
|
||||
|
||||
/* set of parameters */
|
||||
while ((opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false)))
|
||||
{
|
||||
nparams++;
|
||||
if (nparams > nalloc)
|
||||
{
|
||||
nalloc = nalloc ? nalloc * 2 : 1;
|
||||
pset.bind_params = pg_realloc_array(pset.bind_params, char *, nalloc);
|
||||
}
|
||||
pset.bind_params[nparams - 1] = opt;
|
||||
}
|
||||
pset.bind_nparams = nparams;
|
||||
}
|
||||
}
|
||||
else
|
||||
ignore_slash_options(scan_state);
|
||||
@ -643,6 +706,38 @@ exec_command_cd(PsqlScanState scan_state, bool active_branch, const char *cmd)
|
||||
return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* \close -- close a previously prepared statement
|
||||
*/
|
||||
static backslashResult
|
||||
exec_command_close(PsqlScanState scan_state, bool active_branch, const char *cmd)
|
||||
{
|
||||
backslashResult status = PSQL_CMD_SKIP_LINE;
|
||||
|
||||
if (active_branch)
|
||||
{
|
||||
char *opt = psql_scan_slash_option(scan_state,
|
||||
OT_NORMAL, NULL, false);
|
||||
|
||||
pset.stmtName = NULL;
|
||||
if (!opt)
|
||||
{
|
||||
pg_log_error("\\%s: missing required argument", cmd);
|
||||
status = PSQL_CMD_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
pset.stmtName = opt;
|
||||
pset.send_mode = PSQL_SEND_EXTENDED_CLOSE;
|
||||
status = PSQL_CMD_SEND;
|
||||
}
|
||||
}
|
||||
else
|
||||
ignore_slash_options(scan_state);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* \conninfo -- display information about the current connection
|
||||
*/
|
||||
@ -2096,6 +2191,39 @@ exec_command_print(PsqlScanState scan_state, bool active_branch,
|
||||
return PSQL_CMD_SKIP_LINE;
|
||||
}
|
||||
|
||||
/*
|
||||
* \parse -- parse query
|
||||
*/
|
||||
static backslashResult
|
||||
exec_command_parse(PsqlScanState scan_state, bool active_branch,
|
||||
const char *cmd)
|
||||
{
|
||||
backslashResult status = PSQL_CMD_SKIP_LINE;
|
||||
|
||||
if (active_branch)
|
||||
{
|
||||
char *opt = psql_scan_slash_option(scan_state,
|
||||
OT_NORMAL, NULL, false);
|
||||
|
||||
pset.stmtName = NULL;
|
||||
if (!opt)
|
||||
{
|
||||
pg_log_error("\\%s: missing required argument", cmd);
|
||||
status = PSQL_CMD_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
pset.stmtName = opt;
|
||||
pset.send_mode = PSQL_SEND_EXTENDED_PARSE;
|
||||
status = PSQL_CMD_SEND;
|
||||
}
|
||||
}
|
||||
else
|
||||
ignore_slash_options(scan_state);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* \password -- set user password
|
||||
*/
|
||||
|
Reference in New Issue
Block a user