Skip to content

Commit 7582cce

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 ed0e032 commit 7582cce

File tree

7 files changed

+123
-75
lines changed

7 files changed

+123
-75
lines changed

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

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,7 @@ EOF
161161
Echo the actual queries generated by <command>\d</command> and other backslash
162162
commands. You can use this to study <application>psql</application>'s
163163
internal operations. This is equivalent to
164-
setting the variable <varname>ECHO_HIDDEN</varname> from within
165-
<application>psql</application>.
164+
setting the variable <varname>ECHO_HIDDEN</varname> to <literal>on</>.
166165
</para>
167166
</listitem>
168167
</varlistentry>
@@ -321,8 +320,8 @@ EOF
321320
quietly. By default, it prints welcome messages and various
322321
informational output. If this option is used, none of this
323322
happens. This is useful with the <option>-c</option> option.
324-
Within <application>psql</application> you can also set the
325-
<varname>QUIET</varname> variable to achieve the same effect.
323+
This is equivalent to setting the variable <varname>QUIET</varname>
324+
to <literal>on</>.
326325
</para>
327326
</listitem>
328327
</varlistentry>
@@ -2813,8 +2812,9 @@ bar
28132812
<term><varname>ECHO_HIDDEN</varname></term>
28142813
<listitem>
28152814
<para>
2816-
When this variable is set and a backslash command queries the
2817-
database, the query is first shown. This way you can study the
2815+
When this variable is set to <literal>on</> and a backslash command
2816+
queries the database, the query is first shown.
2817+
This feature helps you to study
28182818
<productname>PostgreSQL</productname> internals and provide
28192819
similar functionality in your own programs. (To select this behavior
28202820
on program start-up, use the switch <option>-E</option>.) If you set
@@ -2972,16 +2972,16 @@ bar
29722972
<term><varname>ON_ERROR_ROLLBACK</varname></term>
29732973
<listitem>
29742974
<para>
2975-
When <literal>on</>, if a statement in a transaction block
2975+
When set to <literal>on</>, if a statement in a transaction block
29762976
generates an error, the error is ignored and the transaction
2977-
continues. When <literal>interactive</>, such errors are only
2977+
continues. When set to <literal>interactive</>, such errors are only
29782978
ignored in interactive sessions, and not when reading script
2979-
files. When <literal>off</> (the default), a statement in a
2979+
files. When unset or set to <literal>off</>, a statement in a
29802980
transaction block that generates an error aborts the entire
2981-
transaction. The on_error_rollback-on mode works by issuing an
2981+
transaction. The error rollback mode works by issuing an
29822982
implicit <command>SAVEPOINT</> for you, just before each command
2983-
that is in a transaction block, and rolls back to the savepoint
2984-
on error.
2983+
that is in a transaction block, and then rolling back to the
2984+
savepoint if the command fails.
29852985
</para>
29862986
</listitem>
29872987
</varlistentry>
@@ -2991,7 +2991,8 @@ bar
29912991
<listitem>
29922992
<para>
29932993
By default, command processing continues after an error. When this
2994-
variable is set, it will instead stop immediately. In interactive mode,
2994+
variable is set to <literal>on</>, processing will instead stop
2995+
immediately. In interactive mode,
29952996
<application>psql</application> will return to the command prompt;
29962997
otherwise, <application>psql</application> will exit, returning
29972998
error code 3 to distinguish this case from fatal error
@@ -3033,8 +3034,8 @@ bar
30333034
<term><varname>QUIET</varname></term>
30343035
<listitem>
30353036
<para>
3036-
This variable is equivalent to the command line option
3037-
<option>-q</option>. It is probably not too useful in
3037+
Setting this variable to <literal>on</> is equivalent to the command
3038+
line option <option>-q</option>. It is probably not too useful in
30383039
interactive mode.
30393040
</para>
30403041
</listitem>
@@ -3044,8 +3045,8 @@ bar
30443045
<term><varname>SINGLELINE</varname></term>
30453046
<listitem>
30463047
<para>
3047-
This variable is equivalent to the command line option
3048-
<option>-S</option>.
3048+
Setting this variable to <literal>on</> is equivalent to the command
3049+
line option <option>-S</option>.
30493050
</para>
30503051
</listitem>
30513052
</varlistentry>
@@ -3054,8 +3055,8 @@ bar
30543055
<term><varname>SINGLESTEP</varname></term>
30553056
<listitem>
30563057
<para>
3057-
This variable is equivalent to the command line option
3058-
<option>-s</option>.
3058+
Setting this variable to <literal>on</> is equivalent to the command
3059+
line option <option>-s</option>.
30593060
</para>
30603061
</listitem>
30613062
</varlistentry>

src/bin/psql/command.c

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

13231323
if (opt)
1324-
pset.timing = ParseVariableBool(opt);
1324+
pset.timing = ParseVariableBool(opt, "\\timing");
13251325
else
13261326
pset.timing = !pset.timing;
13271327
if (!pset.quiet)
@@ -2295,12 +2295,14 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
22952295
}
22962296

22972297
/* set expanded/vertical mode */
2298-
else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
2298+
else if (strcmp(param, "x") == 0 ||
2299+
strcmp(param, "expanded") == 0 ||
2300+
strcmp(param, "vertical") == 0)
22992301
{
23002302
if (value && pg_strcasecmp(value, "auto") == 0)
23012303
popt->topt.expanded = 2;
23022304
else if (value)
2303-
popt->topt.expanded = ParseVariableBool(value);
2305+
popt->topt.expanded = ParseVariableBool(value, param);
23042306
else
23052307
popt->topt.expanded = !popt->topt.expanded;
23062308
if (!quiet)
@@ -2318,7 +2320,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
23182320
else if (strcmp(param, "numericlocale") == 0)
23192321
{
23202322
if (value)
2321-
popt->topt.numericLocale = ParseVariableBool(value);
2323+
popt->topt.numericLocale = ParseVariableBool(value, param);
23222324
else
23232325
popt->topt.numericLocale = !popt->topt.numericLocale;
23242326
if (!quiet)
@@ -2402,7 +2404,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
24022404
else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
24032405
{
24042406
if (value)
2405-
popt->topt.tuples_only = ParseVariableBool(value);
2407+
popt->topt.tuples_only = ParseVariableBool(value, param);
24062408
else
24072409
popt->topt.tuples_only = !popt->topt.tuples_only;
24082410
if (!quiet)
@@ -2456,10 +2458,12 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
24562458
if (value && pg_strcasecmp(value, "always") == 0)
24572459
popt->topt.pager = 2;
24582460
else if (value)
2459-
if (ParseVariableBool(value))
2461+
{
2462+
if (ParseVariableBool(value, param))
24602463
popt->topt.pager = 1;
24612464
else
24622465
popt->topt.pager = 0;
2466+
}
24632467
else if (popt->topt.pager == 1)
24642468
popt->topt.pager = 0;
24652469
else
@@ -2479,7 +2483,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
24792483
else if (strcmp(param, "footer") == 0)
24802484
{
24812485
if (value)
2482-
popt->topt.default_footer = ParseVariableBool(value);
2486+
popt->topt.default_footer = ParseVariableBool(value, param);
24832487
else
24842488
popt->topt.default_footer = !popt->topt.default_footer;
24852489
if (!quiet)

src/bin/psql/settings.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727
#define DEFAULT_PROMPT2 "%/%R%# "
2828
#define DEFAULT_PROMPT3 ">> "
2929

30+
/*
31+
* Note: these enums should generally be chosen so that zero corresponds
32+
* to the default behavior.
33+
*/
34+
3035
typedef enum
3136
{
3237
PSQL_ECHO_NONE,
@@ -48,6 +53,14 @@ typedef enum
4853
PSQL_ERROR_ROLLBACK_ON
4954
} PSQL_ERROR_ROLLBACK;
5055

56+
typedef enum
57+
{
58+
PSQL_COMP_CASE_PRESERVE_UPPER,
59+
PSQL_COMP_CASE_PRESERVE_LOWER,
60+
PSQL_COMP_CASE_UPPER,
61+
PSQL_COMP_CASE_LOWER
62+
} PSQL_COMP_CASE;
63+
5164
typedef enum
5265
{
5366
hctl_none = 0,
@@ -110,6 +123,7 @@ typedef struct _psqlSettings
110123
PSQL_ECHO echo;
111124
PSQL_ECHO_HIDDEN echo_hidden;
112125
PSQL_ERROR_ROLLBACK on_error_rollback;
126+
PSQL_COMP_CASE comp_case;
113127
HistControl histcontrol;
114128
const char *prompt1;
115129
const char *prompt2;

src/bin/psql/startup.c

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -683,31 +683,31 @@ showVersion(void)
683683
static void
684684
autocommit_hook(const char *newval)
685685
{
686-
pset.autocommit = ParseVariableBool(newval);
686+
pset.autocommit = ParseVariableBool(newval, "AUTOCOMMIT");
687687
}
688688

689689
static void
690690
on_error_stop_hook(const char *newval)
691691
{
692-
pset.on_error_stop = ParseVariableBool(newval);
692+
pset.on_error_stop = ParseVariableBool(newval, "ON_ERROR_STOP");
693693
}
694694

695695
static void
696696
quiet_hook(const char *newval)
697697
{
698-
pset.quiet = ParseVariableBool(newval);
698+
pset.quiet = ParseVariableBool(newval, "QUIET");
699699
}
700700

701701
static void
702702
singleline_hook(const char *newval)
703703
{
704-
pset.singleline = ParseVariableBool(newval);
704+
pset.singleline = ParseVariableBool(newval, "SINGLELINE");
705705
}
706706

707707
static void
708708
singlestep_hook(const char *newval)
709709
{
710-
pset.singlestep = ParseVariableBool(newval);
710+
pset.singlestep = ParseVariableBool(newval, "SINGLESTEP");
711711
}
712712

713713
static void
@@ -721,25 +721,31 @@ echo_hook(const char *newval)
721721
{
722722
if (newval == NULL)
723723
pset.echo = PSQL_ECHO_NONE;
724-
else if (strcmp(newval, "queries") == 0)
724+
else if (pg_strcasecmp(newval, "queries") == 0)
725725
pset.echo = PSQL_ECHO_QUERIES;
726-
else if (strcmp(newval, "all") == 0)
726+
else if (pg_strcasecmp(newval, "all") == 0)
727727
pset.echo = PSQL_ECHO_ALL;
728+
else if (pg_strcasecmp(newval, "none") == 0)
729+
pset.echo = PSQL_ECHO_NONE;
728730
else
731+
{
732+
psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
733+
newval, "ECHO", "none");
729734
pset.echo = PSQL_ECHO_NONE;
735+
}
730736
}
731737

732738
static void
733739
echo_hidden_hook(const char *newval)
734740
{
735741
if (newval == NULL)
736742
pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
737-
else if (strcmp(newval, "noexec") == 0)
743+
else if (pg_strcasecmp(newval, "noexec") == 0)
738744
pset.echo_hidden = PSQL_ECHO_HIDDEN_NOEXEC;
739-
else if (pg_strcasecmp(newval, "off") == 0)
740-
pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
741-
else
745+
else if (ParseVariableBool(newval, "ECHO_HIDDEN"))
742746
pset.echo_hidden = PSQL_ECHO_HIDDEN_ON;
747+
else /* ParseVariableBool printed msg if needed */
748+
pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
743749
}
744750

745751
static void
@@ -749,25 +755,52 @@ on_error_rollback_hook(const char *newval)
749755
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
750756
else if (pg_strcasecmp(newval, "interactive") == 0)
751757
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_INTERACTIVE;
752-
else if (pg_strcasecmp(newval, "off") == 0)
758+
else if (ParseVariableBool(newval, "ON_ERROR_ROLLBACK"))
759+
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_ON;
760+
else /* ParseVariableBool printed msg if needed */
753761
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
762+
}
763+
764+
static void
765+
comp_keyword_case_hook(const char *newval)
766+
{
767+
if (newval == NULL)
768+
pset.comp_case = PSQL_COMP_CASE_PRESERVE_UPPER;
769+
else if (pg_strcasecmp(newval, "preserve-upper") == 0)
770+
pset.comp_case = PSQL_COMP_CASE_PRESERVE_UPPER;
771+
else if (pg_strcasecmp(newval, "preserve-lower") == 0)
772+
pset.comp_case = PSQL_COMP_CASE_PRESERVE_LOWER;
773+
else if (pg_strcasecmp(newval, "upper") == 0)
774+
pset.comp_case = PSQL_COMP_CASE_UPPER;
775+
else if (pg_strcasecmp(newval, "lower") == 0)
776+
pset.comp_case = PSQL_COMP_CASE_LOWER;
754777
else
755-
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_ON;
778+
{
779+
psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
780+
newval, "COMP_KEYWORD_CASE", "preserve-upper");
781+
pset.comp_case = PSQL_COMP_CASE_PRESERVE_UPPER;
782+
}
756783
}
757784

758785
static void
759786
histcontrol_hook(const char *newval)
760787
{
761788
if (newval == NULL)
762789
pset.histcontrol = hctl_none;
763-
else if (strcmp(newval, "ignorespace") == 0)
790+
else if (pg_strcasecmp(newval, "ignorespace") == 0)
764791
pset.histcontrol = hctl_ignorespace;
765-
else if (strcmp(newval, "ignoredups") == 0)
792+
else if (pg_strcasecmp(newval, "ignoredups") == 0)
766793
pset.histcontrol = hctl_ignoredups;
767-
else if (strcmp(newval, "ignoreboth") == 0)
794+
else if (pg_strcasecmp(newval, "ignoreboth") == 0)
768795
pset.histcontrol = hctl_ignoreboth;
796+
else if (pg_strcasecmp(newval, "none") == 0)
797+
pset.histcontrol = hctl_none;
769798
else
799+
{
800+
psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
801+
newval, "HISTCONTROL", "none");
770802
pset.histcontrol = hctl_none;
803+
}
771804
}
772805

773806
static void
@@ -793,14 +826,18 @@ verbosity_hook(const char *newval)
793826
{
794827
if (newval == NULL)
795828
pset.verbosity = PQERRORS_DEFAULT;
796-
else if (strcmp(newval, "default") == 0)
829+
else if (pg_strcasecmp(newval, "default") == 0)
797830
pset.verbosity = PQERRORS_DEFAULT;
798-
else if (strcmp(newval, "terse") == 0)
831+
else if (pg_strcasecmp(newval, "terse") == 0)
799832
pset.verbosity = PQERRORS_TERSE;
800-
else if (strcmp(newval, "verbose") == 0)
833+
else if (pg_strcasecmp(newval, "verbose") == 0)
801834
pset.verbosity = PQERRORS_VERBOSE;
802835
else
836+
{
837+
psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
838+
newval, "VERBOSITY", "default");
803839
pset.verbosity = PQERRORS_DEFAULT;
840+
}
804841

805842
if (pset.db)
806843
PQsetErrorVerbosity(pset.db, pset.verbosity);
@@ -821,6 +858,7 @@ EstablishVariableSpace(void)
821858
SetVariableAssignHook(pset.vars, "ECHO", echo_hook);
822859
SetVariableAssignHook(pset.vars, "ECHO_HIDDEN", echo_hidden_hook);
823860
SetVariableAssignHook(pset.vars, "ON_ERROR_ROLLBACK", on_error_rollback_hook);
861+
SetVariableAssignHook(pset.vars, "COMP_KEYWORD_CASE", comp_keyword_case_hook);
824862
SetVariableAssignHook(pset.vars, "HISTCONTROL", histcontrol_hook);
825863
SetVariableAssignHook(pset.vars, "PROMPT1", prompt1_hook);
826864
SetVariableAssignHook(pset.vars, "PROMPT2", prompt2_hook);

0 commit comments

Comments
 (0)