of having a validator is not to let the call handler omit checks, but
to notify the user immediately if there are obvious errors in a
<command>CREATE FUNCTION</> command.)
+ While the choice of exactly what to check is mostly left to the
+ discretion of the validator function, note that the core
+ <command>CREATE FUNCTION</> code only executes <literal>SET</> clauses
+ attached to a function when <varname>check_function_bodies</> is on.
+ Therefore, checks whose results might be affected by GUC parameters
+ definitely should be skipped when <varname>check_function_bodies</> is
+ off, to avoid false failures when reloading a dump.
</para>
<para>
/* Verify function body */
if (OidIsValid(languageValidator))
{
- ArrayType *set_items;
- int save_nestlevel;
+ ArrayType *set_items = NULL;
+ int save_nestlevel = 0;
/* Advance command counter so new tuple can be seen by validator */
CommandCounterIncrement();
- /* Set per-function configuration parameters */
- set_items = (ArrayType *) DatumGetPointer(proconfig);
- if (set_items) /* Need a new GUC nesting level */
+ /*
+ * Set per-function configuration parameters so that the validation is
+ * done with the environment the function expects. However, if
+ * check_function_bodies is off, we don't do this, because that would
+ * create dump ordering hazards that pg_dump doesn't know how to deal
+ * with. (For example, a SET clause might refer to a not-yet-created
+ * text search configuration.) This means that the validator
+ * shouldn't complain about anything that might depend on a GUC
+ * parameter when check_function_bodies is off.
+ */
+ if (check_function_bodies)
{
- save_nestlevel = NewGUCNestLevel();
- ProcessGUCArray(set_items,
- (superuser() ? PGC_SUSET : PGC_USERSET),
- PGC_S_SESSION,
- GUC_ACTION_SAVE);
+ set_items = (ArrayType *) DatumGetPointer(proconfig);
+ if (set_items) /* Need a new GUC nesting level */
+ {
+ save_nestlevel = NewGUCNestLevel();
+ ProcessGUCArray(set_items,
+ (superuser() ? PGC_SUSET : PGC_USERSET),
+ PGC_S_SESSION,
+ GUC_ACTION_SAVE);
+ }
}
- else
- save_nestlevel = 0; /* keep compiler quiet */
OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval));
2MB | 2MB
(1 row)
+-- Normally, CREATE FUNCTION should complain about invalid values in
+-- function SET options; but not if check_function_bodies is off,
+-- because that creates ordering hazards for pg_dump
+create function func_with_bad_set() returns int as $$ select 1 $$
+language sql
+set default_text_search_config = no_such_config;
+NOTICE: text search configuration "no_such_config" does not exist
+ERROR: invalid value for parameter "default_text_search_config": "no_such_config"
+set check_function_bodies = off;
+create function func_with_bad_set() returns int as $$ select 1 $$
+language sql
+set default_text_search_config = no_such_config;
+NOTICE: text search configuration "no_such_config" does not exist
+select func_with_bad_set();
+ERROR: invalid value for parameter "default_text_search_config": "no_such_config"
+reset check_function_bodies;
select myfunc(0);
select current_setting('work_mem');
select myfunc(1), current_setting('work_mem');
+
+-- Normally, CREATE FUNCTION should complain about invalid values in
+-- function SET options; but not if check_function_bodies is off,
+-- because that creates ordering hazards for pg_dump
+
+create function func_with_bad_set() returns int as $$ select 1 $$
+language sql
+set default_text_search_config = no_such_config;
+
+set check_function_bodies = off;
+
+create function func_with_bad_set() returns int as $$ select 1 $$
+language sql
+set default_text_search_config = no_such_config;
+
+select func_with_bad_set();
+
+reset check_function_bodies;