From 15c194c1d51991deb7b7e6a00c6ce89575654120 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 3 Oct 2003 19:26:49 +0000
Subject: [PATCH] Add GUC parameter check_function_bodies to control whether
 validation of function bodies is done at CREATE FUNCTION time.  This is
 normally true but can be set false to avoid problems with forward references,
 wrong schema search path, etc.  This is just the backend patch, still need to
 adjust pg_dump to make use of it.

---
 doc/src/sgml/runtime.sgml                     | 13 +++-
 src/backend/catalog/pg_proc.c                 | 66 ++++++++++++-------
 src/backend/utils/misc/guc.c                  | 11 +++-
 src/backend/utils/misc/postgresql.conf.sample |  1 +
 4 files changed, 65 insertions(+), 26 deletions(-)

diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 21089df6794..443cd40387f 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.209 2003/09/20 20:12:05 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.210 2003/10/03 19:26:49 tgl Exp $
 -->
 
 <Chapter Id="runtime">
@@ -2085,6 +2085,17 @@ SET ENABLE_SEQSCAN TO OFF;
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term><varname>check_function_bodies</varname> (<type>boolean</type>)</term>
+      <listitem>
+       <para>
+        This parameter is normally true.  When set false, it disables
+	validation of the function body string in <command>CREATE FUNCTION</>.
+	Disabling validation is occasionally useful to avoid problems such as
+	forward references when restoring function definitions from a dump.
+       </para>
+      </listitem>
+     </varlistentry>
 
      <varlistentry>
       <indexterm>
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 99f07549bd2..fde65fd109e 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.108 2003/09/29 00:05:24 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.109 2003/10/03 19:26:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,6 +34,10 @@
 #include "utils/syscache.h"
 
 
+/* GUC parameter */
+bool		check_function_bodies = true;
+
+
 Datum		fmgr_internal_validator(PG_FUNCTION_ARGS);
 Datum		fmgr_c_validator(PG_FUNCTION_ARGS);
 Datum		fmgr_sql_validator(PG_FUNCTION_ARGS);
@@ -560,6 +564,11 @@ fmgr_internal_validator(PG_FUNCTION_ARGS)
 	Datum		tmp;
 	char	   *prosrc;
 
+	/*
+	 * We do not honor check_function_bodies since it's unlikely the
+	 * function name will be found later if it isn't there now.
+	 */
+
 	tuple = SearchSysCache(PROCOID,
 						   ObjectIdGetDatum(funcoid),
 						   0, 0, 0);
@@ -604,6 +613,12 @@ fmgr_c_validator(PG_FUNCTION_ARGS)
 	char	   *prosrc;
 	char	   *probin;
 
+	/*
+	 * It'd be most consistent to skip the check if !check_function_bodies,
+	 * but the purpose of that switch is to be helpful for pg_dump loading,
+	 * and for pg_dump loading it's much better if we *do* check.
+	 */
+
 	tuple = SearchSysCache(PROCOID,
 						   ObjectIdGetDatum(funcoid),
 						   0, 0, 0);
@@ -633,8 +648,7 @@ fmgr_c_validator(PG_FUNCTION_ARGS)
 /*
  * Validator for SQL language functions
  *
- * Parse it here in order to be sure that it contains no syntax
- * errors.
+ * Parse it here in order to be sure that it contains no syntax errors.
  */
 Datum
 fmgr_sql_validator(PG_FUNCTION_ARGS)
@@ -689,30 +703,34 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
 		}
 	}
 
-	tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
-	if (isnull)
-		elog(ERROR, "null prosrc");
+	/* Postpone body checks if !check_function_bodies */
+	if (check_function_bodies)
+	{
+		tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
+		if (isnull)
+			elog(ERROR, "null prosrc");
 
-	prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
+		prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
 
-	/*
-	 * We can't do full prechecking of the function definition if there
-	 * are any polymorphic input types, because actual datatypes of
-	 * expression results will be unresolvable.  The check will be done at
-	 * runtime instead.
-	 *
-	 * We can run the text through the raw parser though; this will at least
-	 * catch silly syntactic errors.
-	 */
-	if (!haspolyarg)
-	{
-		querytree_list = pg_parse_and_rewrite(prosrc,
-											  proc->proargtypes,
-											  proc->pronargs);
-		check_sql_fn_retval(proc->prorettype, functyptype, querytree_list);
+		/*
+		 * We can't do full prechecking of the function definition if there
+		 * are any polymorphic input types, because actual datatypes of
+		 * expression results will be unresolvable.  The check will be done
+		 * at runtime instead.
+		 *
+		 * We can run the text through the raw parser though; this will at
+		 * least catch silly syntactic errors.
+		 */
+		if (!haspolyarg)
+		{
+			querytree_list = pg_parse_and_rewrite(prosrc,
+												  proc->proargtypes,
+												  proc->pronargs);
+			check_sql_fn_retval(proc->prorettype, functyptype, querytree_list);
+		}
+		else
+			querytree_list = pg_parse_query(prosrc);
 	}
-	else
-		querytree_list = pg_parse_query(prosrc);
 
 	ReleaseSysCache(tuple);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 1b085104927..377993a3742 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.161 2003/09/29 00:05:25 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.162 2003/10/03 19:26:49 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -66,6 +66,7 @@
 
 /* XXX these should appear in other modules' header files */
 extern bool Log_connections;
+extern bool check_function_bodies;
 extern int	PreAuthDelay;
 extern int	AuthenticationTimeout;
 extern int	CheckPointTimeout;
@@ -821,6 +822,14 @@ static struct config_bool ConfigureNamesBool[] =
 		&add_missing_from,
 		true, NULL, NULL
 	},
+	{
+		{"check_function_bodies", PGC_USERSET, CLIENT_CONN_STATEMENT,
+			gettext_noop("check function bodies during CREATE FUNCTION"),
+			NULL
+		},
+		&check_function_bodies,
+		true, NULL, NULL
+	},
 
 	/* End-of-list marker */
 	{
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index c04aaab39bb..c880dc40318 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -205,6 +205,7 @@
 # - Statement Behavior -
 
 #search_path = '$user,public'	# schema names
+#check_function_bodies = true
 #default_transaction_isolation = 'read committed'
 #default_transaction_read_only = false
 #statement_timeout = 0		# 0 is disabled, in milliseconds
-- 
GitLab