Skip to content

Commit 2600e44

Browse files
committed
Improve consistency of parsing of psql's magic variables.
For simple boolean variables such as ON_ERROR_STOP, psql has for a long time recognized variant spellings of "on" and "off" (such as "1"/"0"), and it also made a point of warning you if you'd misspelled the setting. But these conveniences did not exist for other keyword-valued variables. In particular, though ECHO_HIDDEN and ON_ERROR_ROLLBACK include "on" and "off" as possible values, none of the alternative spellings for those were recognized; and to make matters worse the code would just silently assume "on" was meant for any unrecognized spelling. Several people have reported getting bitten by this, so let's fix it. In detail, this patch: * Allows all spellings recognized by ParseVariableBool() for ECHO_HIDDEN and ON_ERROR_ROLLBACK. * Reports a warning for unrecognized values for COMP_KEYWORD_CASE, ECHO, ECHO_HIDDEN, HISTCONTROL, ON_ERROR_ROLLBACK, and VERBOSITY. * Recognizes all values for all these variables case-insensitively; previously there was a mishmash of case-sensitive and case-insensitive behaviors. Back-patch to all supported branches. There is a small risk of breaking existing scripts that were accidentally failing to malfunction; but the consensus is that the chance of detecting real problems and preventing future mistakes outweighs this.
1 parent 9b74f35 commit 2600e44

File tree

5 files changed

+81
-53
lines changed

5 files changed

+81
-53
lines changed

doc/src/sgml/ref/psql-ref.sgml

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,7 @@ EOF
157157
Echo the actual queries generated by <command>\d</command> and other backslash
158158
commands. You can use this to study <application>psql</application>'s
159159
internal operations. This is equivalent to
160-
setting the variable <varname>ECHO_HIDDEN</varname> from within
161-
<application>psql</application>.
160+
setting the variable <varname>ECHO_HIDDEN</varname> to <literal>on</>.
162161
</para>
163162
</listitem>
164163
</varlistentry>
@@ -317,8 +316,8 @@ EOF
317316
quietly. By default, it prints welcome messages and various
318317
informational output. If this option is used, none of this
319318
happens. This is useful with the <option>-c</option> option.
320-
Within <application>psql</application> you can also set the
321-
<varname>QUIET</varname> variable to achieve the same effect.
319+
This is equivalent to setting the variable <varname>QUIET</varname>
320+
to <literal>on</>.
322321
</para>
323322
</listitem>
324323
</varlistentry>
@@ -2455,8 +2454,9 @@ bar
24552454
<term><varname>ECHO_HIDDEN</varname></term>
24562455
<listitem>
24572456
<para>
2458-
When this variable is set and a backslash command queries the
2459-
database, the query is first shown. This way you can study the
2457+
When this variable is set to <literal>on</> and a backslash command
2458+
queries the database, the query is first shown.
2459+
This feature helps you to study
24602460
<productname>PostgreSQL</productname> internals and provide
24612461
similar functionality in your own programs. (To select this behavior
24622462
on program start-up, use the switch <option>-E</option>.) If you set
@@ -2614,16 +2614,16 @@ bar
26142614
<term><varname>ON_ERROR_ROLLBACK</varname></term>
26152615
<listitem>
26162616
<para>
2617-
When <literal>on</>, if a statement in a transaction block
2617+
When set to <literal>on</>, if a statement in a transaction block
26182618
generates an error, the error is ignored and the transaction
2619-
continues. When <literal>interactive</>, such errors are only
2619+
continues. When set to <literal>interactive</>, such errors are only
26202620
ignored in interactive sessions, and not when reading script
2621-
files. When <literal>off</> (the default), a statement in a
2621+
files. When unset or set to <literal>off</>, a statement in a
26222622
transaction block that generates an error aborts the entire
2623-
transaction. The on_error_rollback-on mode works by issuing an
2623+
transaction. The error rollback mode works by issuing an
26242624
implicit <command>SAVEPOINT</> for you, just before each command
2625-
that is in a transaction block, and rolls back to the savepoint
2626-
on error.
2625+
that is in a transaction block, and then rolling back to the
2626+
savepoint if the command fails.
26272627
</para>
26282628
</listitem>
26292629
</varlistentry>
@@ -2636,9 +2636,10 @@ bar
26362636
as a malformed <acronym>SQL</acronym> command or internal
26372637
meta-command, processing continues. This has been the
26382638
traditional behavior of <application>psql</application> but it
2639-
is sometimes not desirable. If this variable is set, script
2640-
processing will immediately terminate. If the script was called
2641-
from another script it will terminate in the same fashion. If
2639+
is sometimes not desirable. If this variable is set to <literal>on</>,
2640+
script processing will immediately terminate after an error.
2641+
If the script was called
2642+
from another script, that one will terminate in the same fashion. If
26422643
the outermost script was not called from an interactive
26432644
<application>psql</application> session but rather using the
26442645
<option>-f</option> option, <application>psql</application> will
@@ -2677,8 +2678,8 @@ bar
26772678
<term><varname>QUIET</varname></term>
26782679
<listitem>
26792680
<para>
2680-
This variable is equivalent to the command line option
2681-
<option>-q</option>. It is probably not too useful in
2681+
Setting this variable to <literal>on</> is equivalent to the command
2682+
line option <option>-q</option>. It is probably not too useful in
26822683
interactive mode.
26832684
</para>
26842685
</listitem>
@@ -2688,8 +2689,8 @@ bar
26882689
<term><varname>SINGLELINE</varname></term>
26892690
<listitem>
26902691
<para>
2691-
This variable is equivalent to the command line option
2692-
<option>-S</option>.
2692+
Setting this variable to <literal>on</> is equivalent to the command
2693+
line option <option>-S</option>.
26932694
</para>
26942695
</listitem>
26952696
</varlistentry>
@@ -2698,8 +2699,8 @@ bar
26982699
<term><varname>SINGLESTEP</varname></term>
26992700
<listitem>
27002701
<para>
2701-
This variable is equivalent to the command line option
2702-
<option>-s</option>.
2702+
Setting this variable to <literal>on</> is equivalent to the command
2703+
line option <option>-s</option>.
27032704
</para>
27042705
</listitem>
27052706
</varlistentry>

src/bin/psql/command.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,7 @@ exec_command(const char *cmd,
10251025
OT_NORMAL, NULL, false);
10261026

10271027
if (opt)
1028-
pset.timing = ParseVariableBool(opt);
1028+
pset.timing = ParseVariableBool(opt, "\\timing");
10291029
else
10301030
pset.timing = !pset.timing;
10311031
if (!pset.quiet)
@@ -1882,10 +1882,12 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
18821882
}
18831883

18841884
/* set expanded/vertical mode */
1885-
else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
1885+
else if (strcmp(param, "x") == 0 ||
1886+
strcmp(param, "expanded") == 0 ||
1887+
strcmp(param, "vertical") == 0)
18861888
{
18871889
if (value)
1888-
popt->topt.expanded = ParseVariableBool(value);
1890+
popt->topt.expanded = ParseVariableBool(value, param);
18891891
else
18901892
popt->topt.expanded = !popt->topt.expanded;
18911893
if (!quiet)
@@ -1898,7 +1900,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
18981900
else if (strcmp(param, "numericlocale") == 0)
18991901
{
19001902
if (value)
1901-
popt->topt.numericLocale = ParseVariableBool(value);
1903+
popt->topt.numericLocale = ParseVariableBool(value, param);
19021904
else
19031905
popt->topt.numericLocale = !popt->topt.numericLocale;
19041906
if (!quiet)
@@ -1955,7 +1957,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
19551957
else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
19561958
{
19571959
if (value)
1958-
popt->topt.tuples_only = ParseVariableBool(value);
1960+
popt->topt.tuples_only = ParseVariableBool(value, param);
19591961
else
19601962
popt->topt.tuples_only = !popt->topt.tuples_only;
19611963
if (!quiet)
@@ -2009,10 +2011,12 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
20092011
if (value && pg_strcasecmp(value, "always") == 0)
20102012
popt->topt.pager = 2;
20112013
else if (value)
2012-
if (ParseVariableBool(value))
2014+
{
2015+
if (ParseVariableBool(value, param))
20132016
popt->topt.pager = 1;
20142017
else
20152018
popt->topt.pager = 0;
2019+
}
20162020
else if (popt->topt.pager == 1)
20172021
popt->topt.pager = 0;
20182022
else
@@ -2032,7 +2036,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
20322036
else if (strcmp(param, "footer") == 0)
20332037
{
20342038
if (value)
2035-
popt->default_footer = ParseVariableBool(value);
2039+
popt->default_footer = ParseVariableBool(value, param);
20362040
else
20372041
popt->default_footer = !popt->default_footer;
20382042
if (!quiet)

src/bin/psql/startup.c

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -631,31 +631,31 @@ showVersion(void)
631631
static void
632632
autocommit_hook(const char *newval)
633633
{
634-
pset.autocommit = ParseVariableBool(newval);
634+
pset.autocommit = ParseVariableBool(newval, "AUTOCOMMIT");
635635
}
636636

637637
static void
638638
on_error_stop_hook(const char *newval)
639639
{
640-
pset.on_error_stop = ParseVariableBool(newval);
640+
pset.on_error_stop = ParseVariableBool(newval, "ON_ERROR_STOP");
641641
}
642642

643643
static void
644644
quiet_hook(const char *newval)
645645
{
646-
pset.quiet = ParseVariableBool(newval);
646+
pset.quiet = ParseVariableBool(newval, "QUIET");
647647
}
648648

649649
static void
650650
singleline_hook(const char *newval)
651651
{
652-
pset.singleline = ParseVariableBool(newval);
652+
pset.singleline = ParseVariableBool(newval, "SINGLELINE");
653653
}
654654

655655
static void
656656
singlestep_hook(const char *newval)
657657
{
658-
pset.singlestep = ParseVariableBool(newval);
658+
pset.singlestep = ParseVariableBool(newval, "SINGLESTEP");
659659
}
660660

661661
static void
@@ -669,25 +669,31 @@ echo_hook(const char *newval)
669669
{
670670
if (newval == NULL)
671671
pset.echo = PSQL_ECHO_NONE;
672-
else if (strcmp(newval, "queries") == 0)
672+
else if (pg_strcasecmp(newval, "queries") == 0)
673673
pset.echo = PSQL_ECHO_QUERIES;
674-
else if (strcmp(newval, "all") == 0)
674+
else if (pg_strcasecmp(newval, "all") == 0)
675675
pset.echo = PSQL_ECHO_ALL;
676+
else if (pg_strcasecmp(newval, "none") == 0)
677+
pset.echo = PSQL_ECHO_NONE;
676678
else
679+
{
680+
psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
681+
newval, "ECHO", "none");
677682
pset.echo = PSQL_ECHO_NONE;
683+
}
678684
}
679685

680686
static void
681687
echo_hidden_hook(const char *newval)
682688
{
683689
if (newval == NULL)
684690
pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
685-
else if (strcmp(newval, "noexec") == 0)
691+
else if (pg_strcasecmp(newval, "noexec") == 0)
686692
pset.echo_hidden = PSQL_ECHO_HIDDEN_NOEXEC;
687-
else if (pg_strcasecmp(newval, "off") == 0)
688-
pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
689-
else
693+
else if (ParseVariableBool(newval, "ECHO_HIDDEN"))
690694
pset.echo_hidden = PSQL_ECHO_HIDDEN_ON;
695+
else /* ParseVariableBool printed msg if needed */
696+
pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
691697
}
692698

693699
static void
@@ -697,25 +703,31 @@ on_error_rollback_hook(const char *newval)
697703
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
698704
else if (pg_strcasecmp(newval, "interactive") == 0)
699705
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_INTERACTIVE;
700-
else if (pg_strcasecmp(newval, "off") == 0)
701-
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
702-
else
706+
else if (ParseVariableBool(newval, "ON_ERROR_ROLLBACK"))
703707
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_ON;
708+
else /* ParseVariableBool printed msg if needed */
709+
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
704710
}
705711

706712
static void
707713
histcontrol_hook(const char *newval)
708714
{
709715
if (newval == NULL)
710716
pset.histcontrol = hctl_none;
711-
else if (strcmp(newval, "ignorespace") == 0)
717+
else if (pg_strcasecmp(newval, "ignorespace") == 0)
712718
pset.histcontrol = hctl_ignorespace;
713-
else if (strcmp(newval, "ignoredups") == 0)
719+
else if (pg_strcasecmp(newval, "ignoredups") == 0)
714720
pset.histcontrol = hctl_ignoredups;
715-
else if (strcmp(newval, "ignoreboth") == 0)
721+
else if (pg_strcasecmp(newval, "ignoreboth") == 0)
716722
pset.histcontrol = hctl_ignoreboth;
723+
else if (pg_strcasecmp(newval, "none") == 0)
724+
pset.histcontrol = hctl_none;
717725
else
726+
{
727+
psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
728+
newval, "HISTCONTROL", "none");
718729
pset.histcontrol = hctl_none;
730+
}
719731
}
720732

721733
static void
@@ -741,14 +753,18 @@ verbosity_hook(const char *newval)
741753
{
742754
if (newval == NULL)
743755
pset.verbosity = PQERRORS_DEFAULT;
744-
else if (strcmp(newval, "default") == 0)
756+
else if (pg_strcasecmp(newval, "default") == 0)
745757
pset.verbosity = PQERRORS_DEFAULT;
746-
else if (strcmp(newval, "terse") == 0)
758+
else if (pg_strcasecmp(newval, "terse") == 0)
747759
pset.verbosity = PQERRORS_TERSE;
748-
else if (strcmp(newval, "verbose") == 0)
760+
else if (pg_strcasecmp(newval, "verbose") == 0)
749761
pset.verbosity = PQERRORS_VERBOSE;
750762
else
763+
{
764+
psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
765+
newval, "VERBOSITY", "default");
751766
pset.verbosity = PQERRORS_DEFAULT;
767+
}
752768

753769
if (pset.db)
754770
PQsetErrorVerbosity(pset.db, pset.verbosity);

src/bin/psql/variables.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,16 @@ GetVariable(VariableSpace space, const char *name)
4949
}
5050

5151
/*
52-
* Try to interpret value as boolean value. Valid values are: true,
53-
* false, yes, no, on, off, 1, 0; as well as unique prefixes thereof.
52+
* Try to interpret "value" as boolean value.
53+
*
54+
* Valid values are: true, false, yes, no, on, off, 1, 0; as well as unique
55+
* prefixes thereof.
56+
*
57+
* "name" is the name of the variable we're assigning to, to use in error
58+
* report if any. Pass name == NULL to suppress the error report.
5459
*/
5560
bool
56-
ParseVariableBool(const char *value)
61+
ParseVariableBool(const char *value, const char *name)
5762
{
5863
size_t len;
5964

@@ -82,7 +87,9 @@ ParseVariableBool(const char *value)
8287
else
8388
{
8489
/* NULL is treated as false, so a non-matching value is 'true' */
85-
psql_error("unrecognized boolean value; assuming \"on\".\n");
90+
if (name)
91+
psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
92+
value, name, "on");
8693
return true;
8794
}
8895
/* suppress compiler warning */

src/bin/psql/variables.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ typedef struct _variable *VariableSpace;
3939
VariableSpace CreateVariableSpace(void);
4040
const char *GetVariable(VariableSpace space, const char *name);
4141

42-
bool ParseVariableBool(const char *val);
42+
bool ParseVariableBool(const char *value, const char *name);
4343
int ParseVariableNum(const char *val,
4444
int defaultval,
4545
int faultval,

0 commit comments

Comments
 (0)