diff --git a/doc/src/sgml/plhandler.sgml b/doc/src/sgml/plhandler.sgml index 54b88ef372..024ef9d3b8 100644 --- a/doc/src/sgml/plhandler.sgml +++ b/doc/src/sgml/plhandler.sgml @@ -200,6 +200,13 @@ CREATE LANGUAGE plsample 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 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 + CREATE FUNCTION code only executes SET clauses + attached to a function when check_function_bodies is on. + Therefore, checks whose results might be affected by GUC parameters + definitely should be skipped when check_function_bodies is + off, to avoid false failures when reloading a dump. diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 2a98ca9598..05a550e726 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -668,24 +668,34 @@ ProcedureCreate(const char *procedureName, /* 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)); diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out index 271706d31e..7b5a624eb8 100644 --- a/src/test/regress/expected/guc.out +++ b/src/test/regress/expected/guc.out @@ -718,3 +718,19 @@ select myfunc(1), current_setting('work_mem'); 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; diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql index 0c21792381..3de8a6b55d 100644 --- a/src/test/regress/sql/guc.sql +++ b/src/test/regress/sql/guc.sql @@ -257,3 +257,21 @@ set work_mem = '1MB'; 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;