Skip to content

Commit 64c5065

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 4db7eaa commit 64c5065

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
@@ -160,8 +160,7 @@ EOF
160160
Echo the actual queries generated by <command>\d</command> and other backslash
161161
commands. You can use this to study <application>psql</application>'s
162162
internal operations. This is equivalent to
163-
setting the variable <varname>ECHO_HIDDEN</varname> from within
164-
<application>psql</application>.
163+
setting the variable <varname>ECHO_HIDDEN</varname> to <literal>on</>.
165164
</para>
166165
</listitem>
167166
</varlistentry>
@@ -320,8 +319,8 @@ EOF
320319
quietly. By default, it prints welcome messages and various
321320
informational output. If this option is used, none of this
322321
happens. This is useful with the <option>-c</option> option.
323-
Within <application>psql</application> you can also set the
324-
<varname>QUIET</varname> variable to achieve the same effect.
322+
This is equivalent to setting the variable <varname>QUIET</varname>
323+
to <literal>on</>.
325324
</para>
326325
</listitem>
327326
</varlistentry>
@@ -2720,8 +2719,9 @@ bar
27202719
<term><varname>ECHO_HIDDEN</varname></term>
27212720
<listitem>
27222721
<para>
2723-
When this variable is set and a backslash command queries the
2724-
database, the query is first shown. This way you can study the
2722+
When this variable is set to <literal>on</> and a backslash command
2723+
queries the database, the query is first shown.
2724+
This feature helps you to study
27252725
<productname>PostgreSQL</productname> internals and provide
27262726
similar functionality in your own programs. (To select this behavior
27272727
on program start-up, use the switch <option>-E</option>.) If you set
@@ -2879,16 +2879,16 @@ bar
28792879
<term><varname>ON_ERROR_ROLLBACK</varname></term>
28802880
<listitem>
28812881
<para>
2882-
When <literal>on</>, if a statement in a transaction block
2882+
When set to <literal>on</>, if a statement in a transaction block
28832883
generates an error, the error is ignored and the transaction
2884-
continues. When <literal>interactive</>, such errors are only
2884+
continues. When set to <literal>interactive</>, such errors are only
28852885
ignored in interactive sessions, and not when reading script
2886-
files. When <literal>off</> (the default), a statement in a
2886+
files. When unset or set to <literal>off</>, a statement in a
28872887
transaction block that generates an error aborts the entire
2888-
transaction. The on_error_rollback-on mode works by issuing an
2888+
transaction. The error rollback mode works by issuing an
28892889
implicit <command>SAVEPOINT</> for you, just before each command
2890-
that is in a transaction block, and rolls back to the savepoint
2891-
on error.
2890+
that is in a transaction block, and then rolling back to the
2891+
savepoint if the command fails.
28922892
</para>
28932893
</listitem>
28942894
</varlistentry>
@@ -2898,7 +2898,8 @@ bar
28982898
<listitem>
28992899
<para>
29002900
By default, command processing continues after an error. When this
2901-
variable is set, it will instead stop immediately. In interactive mode,
2901+
variable is set to <literal>on</>, processing will instead stop
2902+
immediately. In interactive mode,
29022903
<application>psql</application> will return to the command prompt;
29032904
otherwise, <application>psql</application> will exit, returning
29042905
error code 3 to distinguish this case from fatal error
@@ -2940,8 +2941,8 @@ bar
29402941
<term><varname>QUIET</varname></term>
29412942
<listitem>
29422943
<para>
2943-
This variable is equivalent to the command line option
2944-
<option>-q</option>. It is probably not too useful in
2944+
Setting this variable to <literal>on</> is equivalent to the command
2945+
line option <option>-q</option>. It is probably not too useful in
29452946
interactive mode.
29462947
</para>
29472948
</listitem>
@@ -2951,8 +2952,8 @@ bar
29512952
<term><varname>SINGLELINE</varname></term>
29522953
<listitem>
29532954
<para>
2954-
This variable is equivalent to the command line option
2955-
<option>-S</option>.
2955+
Setting this variable to <literal>on</> is equivalent to the command
2956+
line option <option>-S</option>.
29562957
</para>
29572958
</listitem>
29582959
</varlistentry>
@@ -2961,8 +2962,8 @@ bar
29612962
<term><varname>SINGLESTEP</varname></term>
29622963
<listitem>
29632964
<para>
2964-
This variable is equivalent to the command line option
2965-
<option>-s</option>.
2965+
Setting this variable to <literal>on</> is equivalent to the command
2966+
line option <option>-s</option>.
29662967
</para>
29672968
</listitem>
29682969
</varlistentry>

src/bin/psql/command.c

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

12931293
if (opt)
1294-
pset.timing = ParseVariableBool(opt);
1294+
pset.timing = ParseVariableBool(opt, "\\timing");
12951295
else
12961296
pset.timing = !pset.timing;
12971297
if (!pset.quiet)
@@ -2223,12 +2223,14 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
22232223
}
22242224

22252225
/* set expanded/vertical mode */
2226-
else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
2226+
else if (strcmp(param, "x") == 0 ||
2227+
strcmp(param, "expanded") == 0 ||
2228+
strcmp(param, "vertical") == 0)
22272229
{
22282230
if (value && pg_strcasecmp(value, "auto") == 0)
22292231
popt->topt.expanded = 2;
22302232
else if (value)
2231-
popt->topt.expanded = ParseVariableBool(value);
2233+
popt->topt.expanded = ParseVariableBool(value, param);
22322234
else
22332235
popt->topt.expanded = !popt->topt.expanded;
22342236
if (!quiet)
@@ -2246,7 +2248,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
22462248
else if (strcmp(param, "numericlocale") == 0)
22472249
{
22482250
if (value)
2249-
popt->topt.numericLocale = ParseVariableBool(value);
2251+
popt->topt.numericLocale = ParseVariableBool(value, param);
22502252
else
22512253
popt->topt.numericLocale = !popt->topt.numericLocale;
22522254
if (!quiet)
@@ -2330,7 +2332,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
23302332
else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
23312333
{
23322334
if (value)
2333-
popt->topt.tuples_only = ParseVariableBool(value);
2335+
popt->topt.tuples_only = ParseVariableBool(value, param);
23342336
else
23352337
popt->topt.tuples_only = !popt->topt.tuples_only;
23362338
if (!quiet)
@@ -2384,10 +2386,12 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
23842386
if (value && pg_strcasecmp(value, "always") == 0)
23852387
popt->topt.pager = 2;
23862388
else if (value)
2387-
if (ParseVariableBool(value))
2389+
{
2390+
if (ParseVariableBool(value, param))
23882391
popt->topt.pager = 1;
23892392
else
23902393
popt->topt.pager = 0;
2394+
}
23912395
else if (popt->topt.pager == 1)
23922396
popt->topt.pager = 0;
23932397
else
@@ -2407,7 +2411,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
24072411
else if (strcmp(param, "footer") == 0)
24082412
{
24092413
if (value)
2410-
popt->topt.default_footer = ParseVariableBool(value);
2414+
popt->topt.default_footer = ParseVariableBool(value, param);
24112415
else
24122416
popt->topt.default_footer = !popt->topt.default_footer;
24132417
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,
@@ -109,6 +122,7 @@ typedef struct _psqlSettings
109122
PSQL_ECHO echo;
110123
PSQL_ECHO_HIDDEN echo_hidden;
111124
PSQL_ERROR_ROLLBACK on_error_rollback;
125+
PSQL_COMP_CASE comp_case;
112126
HistControl histcontrol;
113127
const char *prompt1;
114128
const char *prompt2;

src/bin/psql/startup.c

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -667,31 +667,31 @@ showVersion(void)
667667
static void
668668
autocommit_hook(const char *newval)
669669
{
670-
pset.autocommit = ParseVariableBool(newval);
670+
pset.autocommit = ParseVariableBool(newval, "AUTOCOMMIT");
671671
}
672672

673673
static void
674674
on_error_stop_hook(const char *newval)
675675
{
676-
pset.on_error_stop = ParseVariableBool(newval);
676+
pset.on_error_stop = ParseVariableBool(newval, "ON_ERROR_STOP");
677677
}
678678

679679
static void
680680
quiet_hook(const char *newval)
681681
{
682-
pset.quiet = ParseVariableBool(newval);
682+
pset.quiet = ParseVariableBool(newval, "QUIET");
683683
}
684684

685685
static void
686686
singleline_hook(const char *newval)
687687
{
688-
pset.singleline = ParseVariableBool(newval);
688+
pset.singleline = ParseVariableBool(newval, "SINGLELINE");
689689
}
690690

691691
static void
692692
singlestep_hook(const char *newval)
693693
{
694-
pset.singlestep = ParseVariableBool(newval);
694+
pset.singlestep = ParseVariableBool(newval, "SINGLESTEP");
695695
}
696696

697697
static void
@@ -705,25 +705,31 @@ echo_hook(const char *newval)
705705
{
706706
if (newval == NULL)
707707
pset.echo = PSQL_ECHO_NONE;
708-
else if (strcmp(newval, "queries") == 0)
708+
else if (pg_strcasecmp(newval, "queries") == 0)
709709
pset.echo = PSQL_ECHO_QUERIES;
710-
else if (strcmp(newval, "all") == 0)
710+
else if (pg_strcasecmp(newval, "all") == 0)
711711
pset.echo = PSQL_ECHO_ALL;
712+
else if (pg_strcasecmp(newval, "none") == 0)
713+
pset.echo = PSQL_ECHO_NONE;
712714
else
715+
{
716+
psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
717+
newval, "ECHO", "none");
713718
pset.echo = PSQL_ECHO_NONE;
719+
}
714720
}
715721

716722
static void
717723
echo_hidden_hook(const char *newval)
718724
{
719725
if (newval == NULL)
720726
pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
721-
else if (strcmp(newval, "noexec") == 0)
727+
else if (pg_strcasecmp(newval, "noexec") == 0)
722728
pset.echo_hidden = PSQL_ECHO_HIDDEN_NOEXEC;
723-
else if (pg_strcasecmp(newval, "off") == 0)
724-
pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
725-
else
729+
else if (ParseVariableBool(newval, "ECHO_HIDDEN"))
726730
pset.echo_hidden = PSQL_ECHO_HIDDEN_ON;
731+
else /* ParseVariableBool printed msg if needed */
732+
pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
727733
}
728734

729735
static void
@@ -733,25 +739,52 @@ on_error_rollback_hook(const char *newval)
733739
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
734740
else if (pg_strcasecmp(newval, "interactive") == 0)
735741
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_INTERACTIVE;
736-
else if (pg_strcasecmp(newval, "off") == 0)
742+
else if (ParseVariableBool(newval, "ON_ERROR_ROLLBACK"))
743+
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_ON;
744+
else /* ParseVariableBool printed msg if needed */
737745
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
746+
}
747+
748+
static void
749+
comp_keyword_case_hook(const char *newval)
750+
{
751+
if (newval == NULL)
752+
pset.comp_case = PSQL_COMP_CASE_PRESERVE_UPPER;
753+
else if (pg_strcasecmp(newval, "preserve-upper") == 0)
754+
pset.comp_case = PSQL_COMP_CASE_PRESERVE_UPPER;
755+
else if (pg_strcasecmp(newval, "preserve-lower") == 0)
756+
pset.comp_case = PSQL_COMP_CASE_PRESERVE_LOWER;
757+
else if (pg_strcasecmp(newval, "upper") == 0)
758+
pset.comp_case = PSQL_COMP_CASE_UPPER;
759+
else if (pg_strcasecmp(newval, "lower") == 0)
760+
pset.comp_case = PSQL_COMP_CASE_LOWER;
738761
else
739-
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_ON;
762+
{
763+
psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
764+
newval, "COMP_KEYWORD_CASE", "preserve-upper");
765+
pset.comp_case = PSQL_COMP_CASE_PRESERVE_UPPER;
766+
}
740767
}
741768

742769
static void
743770
histcontrol_hook(const char *newval)
744771
{
745772
if (newval == NULL)
746773
pset.histcontrol = hctl_none;
747-
else if (strcmp(newval, "ignorespace") == 0)
774+
else if (pg_strcasecmp(newval, "ignorespace") == 0)
748775
pset.histcontrol = hctl_ignorespace;
749-
else if (strcmp(newval, "ignoredups") == 0)
776+
else if (pg_strcasecmp(newval, "ignoredups") == 0)
750777
pset.histcontrol = hctl_ignoredups;
751-
else if (strcmp(newval, "ignoreboth") == 0)
778+
else if (pg_strcasecmp(newval, "ignoreboth") == 0)
752779
pset.histcontrol = hctl_ignoreboth;
780+
else if (pg_strcasecmp(newval, "none") == 0)
781+
pset.histcontrol = hctl_none;
753782
else
783+
{
784+
psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
785+
newval, "HISTCONTROL", "none");
754786
pset.histcontrol = hctl_none;
787+
}
755788
}
756789

757790
static void
@@ -777,14 +810,18 @@ verbosity_hook(const char *newval)
777810
{
778811
if (newval == NULL)
779812
pset.verbosity = PQERRORS_DEFAULT;
780-
else if (strcmp(newval, "default") == 0)
813+
else if (pg_strcasecmp(newval, "default") == 0)
781814
pset.verbosity = PQERRORS_DEFAULT;
782-
else if (strcmp(newval, "terse") == 0)
815+
else if (pg_strcasecmp(newval, "terse") == 0)
783816
pset.verbosity = PQERRORS_TERSE;
784-
else if (strcmp(newval, "verbose") == 0)
817+
else if (pg_strcasecmp(newval, "verbose") == 0)
785818
pset.verbosity = PQERRORS_VERBOSE;
786819
else
820+
{
821+
psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
822+
newval, "VERBOSITY", "default");
787823
pset.verbosity = PQERRORS_DEFAULT;
824+
}
788825

789826
if (pset.db)
790827
PQsetErrorVerbosity(pset.db, pset.verbosity);
@@ -805,6 +842,7 @@ EstablishVariableSpace(void)
805842
SetVariableAssignHook(pset.vars, "ECHO", echo_hook);
806843
SetVariableAssignHook(pset.vars, "ECHO_HIDDEN", echo_hidden_hook);
807844
SetVariableAssignHook(pset.vars, "ON_ERROR_ROLLBACK", on_error_rollback_hook);
845+
SetVariableAssignHook(pset.vars, "COMP_KEYWORD_CASE", comp_keyword_case_hook);
808846
SetVariableAssignHook(pset.vars, "HISTCONTROL", histcontrol_hook);
809847
SetVariableAssignHook(pset.vars, "PROMPT1", prompt1_hook);
810848
SetVariableAssignHook(pset.vars, "PROMPT2", prompt2_hook);

0 commit comments

Comments
 (0)