diff options
| -rw-r--r-- | doc/src/sgml/ref/alter_system.sgml | 12 | ||||
| -rw-r--r-- | doc/src/sgml/ref/set.sgml | 24 | ||||
| -rw-r--r-- | src/backend/parser/gram.y | 20 | ||||
| -rw-r--r-- | src/backend/utils/adt/ruleutils.c | 6 | ||||
| -rw-r--r-- | src/backend/utils/adt/varlena.c | 6 | ||||
| -rw-r--r-- | src/backend/utils/misc/guc_funcs.c | 38 | ||||
| -rw-r--r-- | src/bin/pg_dump/dumputils.c | 6 | ||||
| -rw-r--r-- | src/bin/pg_dump/pg_dump.c | 6 | ||||
| -rw-r--r-- | src/test/regress/expected/guc.out | 22 | ||||
| -rw-r--r-- | src/test/regress/expected/rules.out | 2 | ||||
| -rw-r--r-- | src/test/regress/sql/guc.sql | 9 | ||||
| -rw-r--r-- | src/test/regress/sql/rules.sql | 1 |
12 files changed, 135 insertions, 17 deletions
diff --git a/doc/src/sgml/ref/alter_system.sgml b/doc/src/sgml/ref/alter_system.sgml index 1bde66d6ad2..b28919d1b26 100644 --- a/doc/src/sgml/ref/alter_system.sgml +++ b/doc/src/sgml/ref/alter_system.sgml @@ -84,6 +84,8 @@ ALTER SYSTEM RESET ALL constants, identifiers, numbers, or comma-separated lists of these, as appropriate for the particular parameter. Values that are neither numbers nor valid identifiers must be quoted. + If the parameter accepts a list of values, <literal>NULL</literal> + can be written to specify an empty list. <literal>DEFAULT</literal> can be written to specify removing the parameter and its value from <filename>postgresql.auto.conf</filename>. </para> @@ -136,7 +138,15 @@ ALTER SYSTEM SET wal_level = replica; in <filename>postgresql.conf</filename>: <programlisting> ALTER SYSTEM RESET wal_level; -</programlisting></para> +</programlisting> + </para> + + <para> + Set the list of preloaded extension modules to be empty: +<programlisting> +ALTER SYSTEM SET shared_preload_libraries TO NULL; +</programlisting> + </para> </refsect1> <refsect1> diff --git a/doc/src/sgml/ref/set.sgml b/doc/src/sgml/ref/set.sgml index 2218f54682e..16c7e9a7b26 100644 --- a/doc/src/sgml/ref/set.sgml +++ b/doc/src/sgml/ref/set.sgml @@ -21,8 +21,8 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -SET [ SESSION | LOCAL ] <replaceable class="parameter">configuration_parameter</replaceable> { TO | = } { <replaceable class="parameter">value</replaceable> | '<replaceable class="parameter">value</replaceable>' | DEFAULT } -SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="parameter">value</replaceable> | '<replaceable class="parameter">value</replaceable>' | LOCAL | DEFAULT } +SET [ SESSION | LOCAL ] <replaceable class="parameter">configuration_parameter</replaceable> { TO | = } { <replaceable class="parameter">value</replaceable> [, ...] | DEFAULT } +SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="parameter">value</replaceable> | LOCAL | DEFAULT } </synopsis> </refsynopsisdiv> @@ -123,7 +123,7 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="parameter">value</replac <term><replaceable class="parameter">configuration_parameter</replaceable></term> <listitem> <para> - Name of a settable run-time parameter. Available parameters are + Name of a settable configuration parameter. Available parameters are documented in <xref linkend="runtime-config"/> and below. </para> </listitem> @@ -133,9 +133,12 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="parameter">value</replac <term><replaceable class="parameter">value</replaceable></term> <listitem> <para> - New value of parameter. Values can be specified as string + New value of the parameter. Values can be specified as string constants, identifiers, numbers, or comma-separated lists of these, as appropriate for the particular parameter. + Values that are neither numbers nor valid identifiers must be quoted. + If the parameter accepts a list of values, <literal>NULL</literal> + can be written to specify an empty list. <literal>DEFAULT</literal> can be written to specify resetting the parameter to its default value (that is, whatever value it would have had if no <command>SET</command> had been executed @@ -284,6 +287,19 @@ SELECT setseed(<replaceable>value</replaceable>); <programlisting> SET search_path TO my_schema, public; </programlisting> + Note that this is not the same as +<programlisting> +SET search_path TO 'my_schema, public'; +</programlisting> + which would have the effect of setting <varname>search_path</varname> + to contain a single, probably-nonexistent schema name. + </para> + + <para> + Set the list of temporary tablespace names to be empty: +<programlisting> +SET temp_tablespaces TO NULL; +</programlisting> </para> <para> diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index a65097f19cf..8a0470d5b84 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -1716,6 +1716,26 @@ generic_set: n->location = @3; $$ = n; } + | var_name TO NULL_P + { + VariableSetStmt *n = makeNode(VariableSetStmt); + + n->kind = VAR_SET_VALUE; + n->name = $1; + n->args = list_make1(makeNullAConst(@3)); + n->location = @3; + $$ = n; + } + | var_name '=' NULL_P + { + VariableSetStmt *n = makeNode(VariableSetStmt); + + n->kind = VAR_SET_VALUE; + n->name = $1; + n->args = list_make1(makeNullAConst(@3)); + n->location = @3; + $$ = n; + } | var_name TO DEFAULT { VariableSetStmt *n = makeNode(VariableSetStmt); diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 79ec136231b..5398679cce2 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3087,7 +3087,8 @@ pg_get_functiondef(PG_FUNCTION_ARGS) * string literals. (The elements may be double-quoted as-is, * but we can't just feed them to the SQL parser; it would do * the wrong thing with elements that are zero-length or - * longer than NAMEDATALEN.) + * longer than NAMEDATALEN.) Also, we need a special case for + * empty lists. * * Variables that are not so marked should just be emitted as * simple string literals. If the variable is not known to @@ -3105,6 +3106,9 @@ pg_get_functiondef(PG_FUNCTION_ARGS) /* this shouldn't fail really */ elog(ERROR, "invalid list syntax in proconfig item"); } + /* Special case: represent an empty list as NULL */ + if (namelist == NIL) + appendStringInfoString(&buf, "NULL"); foreach(lc, namelist) { char *curname = (char *) lfirst(lc); diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 8d735786e51..3894457ab40 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -2753,7 +2753,7 @@ SplitIdentifierString(char *rawstring, char separator, nextp++; /* skip leading whitespace */ if (*nextp == '\0') - return true; /* allow empty string */ + return true; /* empty string represents empty list */ /* At the top of the loop, we are at start of a new identifier. */ do @@ -2880,7 +2880,7 @@ SplitDirectoriesString(char *rawstring, char separator, nextp++; /* skip leading whitespace */ if (*nextp == '\0') - return true; /* allow empty string */ + return true; /* empty string represents empty list */ /* At the top of the loop, we are at start of a new directory. */ do @@ -3001,7 +3001,7 @@ SplitGUCList(char *rawstring, char separator, nextp++; /* skip leading whitespace */ if (*nextp == '\0') - return true; /* allow empty string */ + return true; /* empty string represents empty list */ /* At the top of the loop, we are at start of a new identifier. */ do diff --git a/src/backend/utils/misc/guc_funcs.c b/src/backend/utils/misc/guc_funcs.c index 4f58fa3d4e0..9dbc5d3aeb9 100644 --- a/src/backend/utils/misc/guc_funcs.c +++ b/src/backend/utils/misc/guc_funcs.c @@ -210,12 +210,29 @@ flatten_set_variable_args(const char *name, List *args) else flags = 0; - /* Complain if list input and non-list variable */ - if ((flags & GUC_LIST_INPUT) == 0 && - list_length(args) != 1) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("SET %s takes only one argument", name))); + /* + * Handle special cases for list input. + */ + if (flags & GUC_LIST_INPUT) + { + /* NULL represents an empty list. */ + if (list_length(args) == 1) + { + Node *arg = (Node *) linitial(args); + + if (IsA(arg, A_Const) && + ((A_Const *) arg)->isnull) + return pstrdup(""); + } + } + else + { + /* Complain if list input and non-list variable. */ + if (list_length(args) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("SET %s takes only one argument", name))); + } initStringInfo(&buf); @@ -246,6 +263,12 @@ flatten_set_variable_args(const char *name, List *args) elog(ERROR, "unrecognized node type: %d", (int) nodeTag(arg)); con = (A_Const *) arg; + /* Complain if NULL is used with a non-list variable. */ + if (con->isnull) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("NULL is an invalid value for %s", name))); + switch (nodeTag(&con->val)) { case T_Integer: @@ -269,6 +292,9 @@ flatten_set_variable_args(const char *name, List *args) Datum interval; char *intervalout; + /* gram.y ensures this is only reachable for TIME ZONE */ + Assert(!(flags & GUC_LIST_QUOTE)); + typenameTypeIdAndMod(NULL, typeName, &typoid, &typmod); Assert(typoid == INTERVALOID); diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index 05b84c0d6e7..2d22723aa91 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -781,7 +781,7 @@ SplitGUCList(char *rawstring, char separator, nextp++; /* skip leading whitespace */ if (*nextp == '\0') - return true; /* allow empty string */ + return true; /* empty string represents empty list */ /* At the top of the loop, we are at start of a new identifier. */ do @@ -893,6 +893,7 @@ makeAlterConfigCommand(PGconn *conn, const char *configitem, * elements as string literals. (The elements may be double-quoted as-is, * but we can't just feed them to the SQL parser; it would do the wrong * thing with elements that are zero-length or longer than NAMEDATALEN.) + * Also, we need a special case for empty lists. * * Variables that are not so marked should just be emitted as simple * string literals. If the variable is not known to @@ -908,6 +909,9 @@ makeAlterConfigCommand(PGconn *conn, const char *configitem, /* this shouldn't fail really */ if (SplitGUCList(pos, ',', &namelist)) { + /* Special case: represent an empty list as NULL */ + if (*namelist == NULL) + appendPQExpBufferStr(buf, "NULL"); for (nameptr = namelist; *nameptr; nameptr++) { if (nameptr != namelist) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 47913178a93..a00918bacb4 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -13764,7 +13764,8 @@ dumpFunc(Archive *fout, const FuncInfo *finfo) * and then quote the elements as string literals. (The elements may * be double-quoted as-is, but we can't just feed them to the SQL * parser; it would do the wrong thing with elements that are - * zero-length or longer than NAMEDATALEN.) + * zero-length or longer than NAMEDATALEN.) Also, we need a special + * case for empty lists. * * Variables that are not so marked should just be emitted as simple * string literals. If the variable is not known to @@ -13780,6 +13781,9 @@ dumpFunc(Archive *fout, const FuncInfo *finfo) /* this shouldn't fail really */ if (SplitGUCList(pos, ',', &namelist)) { + /* Special case: represent an empty list as NULL */ + if (*namelist == NULL) + appendPQExpBufferStr(q, "NULL"); for (nameptr = namelist; *nameptr; nameptr++) { if (nameptr != namelist) diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out index 7f9e29c765c..d6fb879f500 100644 --- a/src/test/regress/expected/guc.out +++ b/src/test/regress/expected/guc.out @@ -31,6 +31,28 @@ SELECT '2006-08-13 12:34:56'::timestamptz; 2006-08-13 12:34:56-07 (1 row) +-- Check handling of list GUCs +SET search_path = 'pg_catalog', Foo, 'Bar', ''; +SHOW search_path; + search_path +---------------------------- + pg_catalog, foo, "Bar", "" +(1 row) + +SET search_path = null; -- means empty list +SHOW search_path; + search_path +------------- + +(1 row) + +SET search_path = null, null; -- syntax error +ERROR: syntax error at or near "," +LINE 1: SET search_path = null, null; + ^ +SET enable_seqscan = null; -- error +ERROR: NULL is an invalid value for enable_seqscan +RESET search_path; -- SET LOCAL has no effect outside of a transaction SET LOCAL vacuum_cost_delay TO 50; WARNING: SET LOCAL can only be used in transaction blocks diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 77e25ca029e..2bf968ae3d3 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -3572,6 +3572,7 @@ CREATE FUNCTION func_with_set_params() RETURNS integer SET extra_float_digits TO 2 SET work_mem TO '4MB' SET datestyle to iso, mdy + SET temp_tablespaces to NULL SET local_preload_libraries TO "Mixed/Case", 'c:/''a"/path', '', '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789' IMMUTABLE STRICT; SELECT pg_get_functiondef('func_with_set_params()'::regprocedure); @@ -3585,6 +3586,7 @@ SELECT pg_get_functiondef('func_with_set_params()'::regprocedure); SET extra_float_digits TO '2' + SET work_mem TO '4MB' + SET "DateStyle" TO 'iso, mdy' + + SET temp_tablespaces TO NULL + SET local_preload_libraries TO 'Mixed/Case', 'c:/''a"/path', '', '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789'+ AS $function$select 1;$function$ + diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql index f65f84a2632..bafaf067e82 100644 --- a/src/test/regress/sql/guc.sql +++ b/src/test/regress/sql/guc.sql @@ -12,6 +12,15 @@ SHOW vacuum_cost_delay; SHOW datestyle; SELECT '2006-08-13 12:34:56'::timestamptz; +-- Check handling of list GUCs +SET search_path = 'pg_catalog', Foo, 'Bar', ''; +SHOW search_path; +SET search_path = null; -- means empty list +SHOW search_path; +SET search_path = null, null; -- syntax error +SET enable_seqscan = null; -- error +RESET search_path; + -- SET LOCAL has no effect outside of a transaction SET LOCAL vacuum_cost_delay TO 50; SHOW vacuum_cost_delay; diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql index fdd3ff1d161..3f240bec7b0 100644 --- a/src/test/regress/sql/rules.sql +++ b/src/test/regress/sql/rules.sql @@ -1217,6 +1217,7 @@ CREATE FUNCTION func_with_set_params() RETURNS integer SET extra_float_digits TO 2 SET work_mem TO '4MB' SET datestyle to iso, mdy + SET temp_tablespaces to NULL SET local_preload_libraries TO "Mixed/Case", 'c:/''a"/path', '', '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789' IMMUTABLE STRICT; SELECT pg_get_functiondef('func_with_set_params()'::regprocedure); |
