Commit fcbbf82d authored by Tom Lane's avatar Tom Lane

Code and docs review for multiple -c and -f options in psql.

Commit d5563d7d drew complaints from Coverity, which quite
correctly complained that one copy of each -c or -f string was being
leaked.  What's more, simple_action_list_append was allocating enough space
for still a third copy of each string as part of the SimpleActionListCell,
even though that coding method had been superseded by a separate strdup
operation.  There were some other minor coding infelicities too.  The
documentation needed more work as well, eg it forgot to explain that -c
causes psql not to accept any interactive input.
parent a91bdf67
...@@ -39,9 +39,9 @@ PostgreSQL documentation ...@@ -39,9 +39,9 @@ PostgreSQL documentation
queries interactively, issue them to queries interactively, issue them to
<productname>PostgreSQL</productname>, and see the query results. <productname>PostgreSQL</productname>, and see the query results.
Alternatively, input can be from a file or from command line Alternatively, input can be from a file or from command line
arguments. In addition, it provides a number of meta-commands and various arguments. In addition, <application>psql</application> provides a
shell-like features to facilitate writing scripts and automating a wide number of meta-commands and various shell-like features to
variety of tasks. facilitate writing scripts and automating a wide variety of tasks.
</para> </para>
</refsect1> </refsect1>
...@@ -93,7 +93,11 @@ PostgreSQL documentation ...@@ -93,7 +93,11 @@ PostgreSQL documentation
Specifies that <application>psql</application> is to execute the given Specifies that <application>psql</application> is to execute the given
command string, <replaceable class="parameter">command</replaceable>. command string, <replaceable class="parameter">command</replaceable>.
This option can be repeated and combined in any order with This option can be repeated and combined in any order with
the <option>-f</option> option. the <option>-f</option> option. When either <option>-c</option>
or <option>-f</option> is specified, <application>psql</application>
does not read commands from standard input; instead it terminates
after processing all the <option>-c</option> and <option>-f</option>
options in sequence.
</para> </para>
<para> <para>
<replaceable class="parameter">command</replaceable> must be either <replaceable class="parameter">command</replaceable> must be either
...@@ -101,31 +105,35 @@ PostgreSQL documentation ...@@ -101,31 +105,35 @@ PostgreSQL documentation
it contains no <application>psql</application>-specific features), it contains no <application>psql</application>-specific features),
or a single backslash command. Thus you cannot mix or a single backslash command. Thus you cannot mix
<acronym>SQL</acronym> and <application>psql</application> <acronym>SQL</acronym> and <application>psql</application>
meta-commands with this option. To achieve that, you could meta-commands within a <option>-c</option> option. To achieve that,
use repeated <option>-c</option> options or pipe the string you could use repeated <option>-c</option> options or pipe the string
into <application>psql</application>, for example: into <application>psql</application>, for example:
<literal>psql -c '\x' -c 'SELECT * FROM foo;'</literal> or <programlisting>
<literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>. psql -c '\x' -c 'SELECT * FROM foo;'
</programlisting>
or
<programlisting>
echo '\x \\ SELECT * FROM foo;' | psql
</programlisting>
(<literal>\\</> is the separator meta-command.) (<literal>\\</> is the separator meta-command.)
</para> </para>
<para> <para>
Each command string passed to <option>-c</option> is sent to the server Each <acronym>SQL</acronym> command string passed
as a single query. Because of this, the server executes it as a single to <option>-c</option> is sent to the server as a single query.
transaction, even if a command string contains Because of this, the server executes it as a single transaction even
multiple <acronym>SQL</acronym> commands, unless there are if the string contains multiple <acronym>SQL</acronym> commands,
explicit <command>BEGIN</>/<command>COMMIT</> commands included in the unless there are explicit <command>BEGIN</>/<command>COMMIT</>
string to divide it into multiple transactions. Also, the server only commands included in the string to divide it into multiple
returns the result of the last <acronym>SQL</acronym> command to the transactions. Also, <application>psql</application> only prints the
client. This is different from the behavior when the same string with result of the last <acronym>SQL</acronym> command in the string.
multiple <acronym>SQL</acronym> commands is fed This is different from the behavior when the same string is read from
to <application>psql</application>'s standard input because a file or fed to <application>psql</application>'s standard input,
then <application>psql</application> sends each <acronym>SQL</acronym> because then <application>psql</application> sends
command separately. each <acronym>SQL</acronym> command separately.
</para> </para>
<para> <para>
Putting more than one command in the <option>-c</option> string often Because of this behavior, putting more than one command in a
has unexpected results. This is a result of the fact that the whole single <option>-c</option> string often has unexpected results.
string is sent to the server as a single query.
It's better to use repeated <option>-c</option> commands or feed It's better to use repeated <option>-c</option> commands or feed
multiple commands to <application>psql</application>'s standard input, multiple commands to <application>psql</application>'s standard input,
either using <application>echo</application> as illustrated above, or either using <application>echo</application> as illustrated above, or
...@@ -192,18 +200,26 @@ EOF ...@@ -192,18 +200,26 @@ EOF
<term><option>--file=<replaceable class="parameter">filename</replaceable></></term> <term><option>--file=<replaceable class="parameter">filename</replaceable></></term>
<listitem> <listitem>
<para> <para>
Use the file <replaceable class="parameter">filename</replaceable> Read commands from the
as the source of commands instead of reading commands interactively. file <replaceable class="parameter">filename</replaceable>,
rather than standard input.
This option can be repeated and combined in any order with This option can be repeated and combined in any order with
the <option>-c</option> option. After the commands in the <option>-c</option> option. When either <option>-c</option>
every <option>-c</option> command string and <option>-f</option> file or <option>-f</option> is specified, <application>psql</application>
are processed, <application>psql</application> terminates. This option does not read commands from standard input; instead it terminates
is in many ways equivalent to the meta-command <command>\i</command>. after processing all the <option>-c</option> and <option>-f</option>
options in sequence.
Except for that, this option is largely equivalent to the
meta-command <command>\i</command>.
</para> </para>
<para> <para>
If <replaceable>filename</replaceable> is <literal>-</literal> If <replaceable>filename</replaceable> is <literal>-</literal>
(hyphen), then standard input is read. (hyphen), then standard input is read until an EOF indication
or <command>\q</> meta-command. This can be used to intersperse
interactive input with input from files. Note however that Readline
is not used in this case (much as if <option>-n</option> had been
specified).
</para> </para>
<para> <para>
...@@ -550,12 +566,13 @@ EOF ...@@ -550,12 +566,13 @@ EOF
<term><option>--single-transaction</option></term> <term><option>--single-transaction</option></term>
<listitem> <listitem>
<para> <para>
When <application>psql</application> executes commands from a script This option can only be used in combination with one or more
and/or a <option>-c</option> option, adding this option <option>-c</option> and/or <option>-f</option> options. It causes
wraps <command>BEGIN</>/<command>COMMIT</> around all of those <application>psql</application> to issue a <command>BEGIN</> command
commands as a whole to execute them as a single transaction. This before the first such option and a <command>COMMIT</> command after
ensures that either all the commands complete successfully, or no the last one, thereby wrapping all the commands into a single
changes are applied. transaction. This ensures that either all the commands complete
successfully, or no changes are applied.
</para> </para>
<para> <para>
...@@ -3799,16 +3816,6 @@ PSQL_EDITOR_LINENUMBER_ARG='--line ' ...@@ -3799,16 +3816,6 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
<title>Notes</title> <title>Notes</title>
<itemizedlist> <itemizedlist>
<listitem>
<para>
In an earlier life <application>psql</application> allowed the
first argument of a single-letter backslash command to start
directly after the command, without intervening whitespace.
As of <productname>PostgreSQL</productname> 8.4 this is no
longer allowed.
</para>
</listitem>
<listitem> <listitem>
<para><application>psql</application> works best with servers of the same <para><application>psql</application> works best with servers of the same
or an older major version. Backslash commands are particularly likely or an older major version. Backslash commands are particularly likely
...@@ -3824,8 +3831,8 @@ PSQL_EDITOR_LINENUMBER_ARG='--line ' ...@@ -3824,8 +3831,8 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
If you want to use <application>psql</application> to connect to several If you want to use <application>psql</application> to connect to several
servers of different major versions, it is recommended that you use the servers of different major versions, it is recommended that you use the
newest version of <application>psql</application>. Alternatively, you newest version of <application>psql</application>. Alternatively, you
can keep a copy of <application>psql</application> from each major can keep around a copy of <application>psql</application> from each
version around and be sure to use the version that matches the major version and be sure to use the version that matches the
respective server. But in practice, this additional complication should respective server. But in practice, this additional complication should
not be necessary. not be necessary.
</para> </para>
...@@ -3833,8 +3840,19 @@ PSQL_EDITOR_LINENUMBER_ARG='--line ' ...@@ -3833,8 +3840,19 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
<listitem> <listitem>
<para> <para>
Before <productname>PostgreSQL</productname> 9.6, <option>-c</option> Before <productname>PostgreSQL</productname> 9.6,
implied <option>-X</option>; this is no longer the case. the <option>-c</option> option implied <option>-X</option>
(<option>--no-psqlrc</>); this is no longer the case.
</para>
</listitem>
<listitem>
<para>
Before <productname>PostgreSQL</productname> 8.4,
<application>psql</application> allowed the
first argument of a single-letter backslash command to start
directly after the command, without intervening whitespace.
Now, some whitespace is required.
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
......
...@@ -58,7 +58,7 @@ enum _actions ...@@ -58,7 +58,7 @@ enum _actions
typedef struct SimpleActionListCell typedef struct SimpleActionListCell
{ {
struct SimpleActionListCell *next; struct SimpleActionListCell *next;
int action; enum _actions action;
char *val; char *val;
} SimpleActionListCell; } SimpleActionListCell;
...@@ -84,11 +84,11 @@ struct adhoc_opts ...@@ -84,11 +84,11 @@ struct adhoc_opts
static void parse_psql_options(int argc, char *argv[], static void parse_psql_options(int argc, char *argv[],
struct adhoc_opts * options); struct adhoc_opts * options);
static void simple_action_list_append(SimpleActionList *list,
enum _actions action, const char *val);
static void process_psqlrc(char *argv0); static void process_psqlrc(char *argv0);
static void process_psqlrc_file(char *filename); static void process_psqlrc_file(char *filename);
static void showVersion(void); static void showVersion(void);
static void simple_action_list_append(SimpleActionList *list,
int action, const char *val);
static void EstablishVariableSpace(void); static void EstablishVariableSpace(void);
#define NOPAGER 0 #define NOPAGER 0
...@@ -172,9 +172,6 @@ main(int argc, char *argv[]) ...@@ -172,9 +172,6 @@ main(int argc, char *argv[])
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2); SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3); SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
options.actions.head = NULL;
options.actions.tail = NULL;
parse_psql_options(argc, argv, &options); parse_psql_options(argc, argv, &options);
/* /*
...@@ -298,8 +295,8 @@ main(int argc, char *argv[]) ...@@ -298,8 +295,8 @@ main(int argc, char *argv[])
process_psqlrc(argv[0]); process_psqlrc(argv[0]);
/* /*
* If any actions were given by caller, process them in the order in * If any actions were given by user, process them in the order in which
* which they were specified. * they were specified. Note single_txn is only effective in this mode.
*/ */
if (options.actions.head != NULL) if (options.actions.head != NULL)
{ {
...@@ -356,7 +353,7 @@ main(int argc, char *argv[]) ...@@ -356,7 +353,7 @@ main(int argc, char *argv[])
else else
{ {
/* should never come here */ /* should never come here */
Assert(0); Assert(false);
} }
if (successResult != EXIT_SUCCESS && pset.on_error_stop) if (successResult != EXIT_SUCCESS && pset.on_error_stop)
...@@ -473,11 +470,11 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options) ...@@ -473,11 +470,11 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
if (optarg[0] == '\\') if (optarg[0] == '\\')
simple_action_list_append(&options->actions, simple_action_list_append(&options->actions,
ACT_SINGLE_SLASH, ACT_SINGLE_SLASH,
pstrdup(optarg + 1)); optarg + 1);
else else
simple_action_list_append(&options->actions, simple_action_list_append(&options->actions,
ACT_SINGLE_QUERY, ACT_SINGLE_QUERY,
pstrdup(optarg)); optarg);
break; break;
case 'd': case 'd':
options->dbname = pg_strdup(optarg); options->dbname = pg_strdup(optarg);
...@@ -491,7 +488,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options) ...@@ -491,7 +488,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
case 'f': case 'f':
simple_action_list_append(&options->actions, simple_action_list_append(&options->actions,
ACT_FILE, ACT_FILE,
pg_strdup(optarg)); optarg);
break; break;
case 'F': case 'F':
pset.popt.topt.fieldSep.separator = pg_strdup(optarg); pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
...@@ -672,6 +669,33 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options) ...@@ -672,6 +669,33 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
} }
/*
* Append a new item to the end of the SimpleActionList.
* Note that "val" is copied if it's not NULL.
*/
static void
simple_action_list_append(SimpleActionList *list,
enum _actions action, const char *val)
{
SimpleActionListCell *cell;
cell = (SimpleActionListCell *) pg_malloc(sizeof(SimpleActionListCell));
cell->next = NULL;
cell->action = action;
if (val)
cell->val = pg_strdup(val);
else
cell->val = NULL;
if (list->tail)
list->tail->next = cell;
else
list->head = cell;
list->tail = cell;
}
/* /*
* Load .psqlrc file, if found. * Load .psqlrc file, if found.
*/ */
...@@ -945,39 +969,6 @@ show_context_hook(const char *newval) ...@@ -945,39 +969,6 @@ show_context_hook(const char *newval)
} }
/*
* Support for list of actions. SimpleStringList cannot be used due possible
* combination different actions with the requirement to save the order.
*/
static void
simple_action_list_append(SimpleActionList *list, int action, const char *val)
{
SimpleActionListCell *cell;
size_t vallen = 0;
if (val)
vallen = strlen(val);
cell = (SimpleActionListCell *)
pg_malloc(offsetof(SimpleActionListCell, val) + vallen + 1);
cell->next = NULL;
cell->action = action;
if (val)
{
cell->val = pg_malloc(vallen + 1);
strcpy(cell->val, val);
}
else
cell->val = NULL;
if (list->tail)
list->tail->next = cell;
else
list->head = cell;
list->tail = cell;
}
static void static void
EstablishVariableSpace(void) EstablishVariableSpace(void)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment