88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.73 2002/05/21 22:05:54 tgl Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.74 2002/05/22 17:20:58 petere Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
2020#include "catalog/pg_language.h"
2121#include "catalog/pg_proc.h"
2222#include "executor/executor.h"
23+ #include "fmgr.h"
2324#include "miscadmin.h"
2425#include "parser/parse_coerce.h"
2526#include "parser/parse_expr.h"
3233
3334
3435static void checkretval (Oid rettype ,List * queryTreeList );
36+ Datum fmgr_internal_validator (PG_FUNCTION_ARGS );
37+ Datum fmgr_c_validator (PG_FUNCTION_ARGS );
38+ Datum fmgr_sql_validator (PG_FUNCTION_ARGS );
3539
3640
3741/* ----------------------------------------------------------------
@@ -45,6 +49,7 @@ ProcedureCreate(const char *procedureName,
4549bool returnsSet ,
4650Oid returnType ,
4751Oid languageObjectId ,
52+ Oid languageValidator ,
4853const char * prosrc ,
4954const char * probin ,
5055bool isAgg ,
@@ -66,7 +71,6 @@ ProcedureCreate(const char *procedureName,
6671char nulls [Natts_pg_proc ];
6772Datum values [Natts_pg_proc ];
6873char replaces [Natts_pg_proc ];
69- List * querytree_list ;
7074Oid typev [FUNC_MAX_ARGS ];
7175Oid relid ;
7276NameData procname ;
@@ -126,12 +130,6 @@ ProcedureCreate(const char *procedureName,
126130}
127131}
128132
129- if (!OidIsValid (returnType ))
130- {
131- if (languageObjectId == SQLlanguageId )
132- elog (ERROR ,"SQL functions cannot return type \"opaque\"" );
133- }
134-
135133/*
136134 * don't allow functions of complex types that have the same name as
137135 * existing attributes of the type
@@ -142,65 +140,6 @@ ProcedureCreate(const char *procedureName,
142140elog (ERROR ,"method %s already an attribute of type %s" ,
143141procedureName ,format_type_be (typev [0 ]));
144142
145- /*
146- * If this is a postquel procedure, we parse it here in order to be
147- * sure that it contains no syntax errors.We should store the plan
148- * in an Inversion file for use later, but for now, we just store the
149- * procedure's text in the prosrc attribute.
150- */
151-
152- if (languageObjectId == SQLlanguageId )
153- {
154- querytree_list = pg_parse_and_rewrite ((char * )prosrc ,
155- typev ,
156- parameterCount );
157- /* typecheck return value */
158- checkretval (returnType ,querytree_list );
159- }
160-
161- /*
162- * If this is an internal procedure, check that the given internal
163- * function name (the 'prosrc' value) is a known builtin function.
164- *
165- * NOTE: in Postgres versions before 6.5, the SQL name of the created
166- * function could not be different from the internal name, and
167- * 'prosrc' wasn't used. So there is code out there that does CREATE
168- * FUNCTION xyz AS '' LANGUAGE 'internal'.To preserve some modicum
169- * of backwards compatibility, accept an empty 'prosrc' value as
170- * meaning the supplied SQL function name.
171- */
172- if (languageObjectId == INTERNALlanguageId )
173- {
174- if (strlen (prosrc )== 0 )
175- prosrc = procedureName ;
176- if (fmgr_internal_function ((char * )prosrc )== InvalidOid )
177- elog (ERROR ,
178- "there is no built-in function named \"%s\"" ,
179- prosrc );
180- }
181-
182- /*
183- * If this is a dynamically loadable procedure, make sure that the
184- * library file exists, is loadable, and contains the specified link
185- * symbol.Also check for a valid function information record.
186- *
187- * We used to perform these checks only when the function was first
188- * called, but it seems friendlier to verify the library's validity at
189- * CREATE FUNCTION time.
190- */
191- if (languageObjectId == ClanguageId )
192- {
193- void * libraryhandle ;
194-
195- /* If link symbol is specified as "-", substitute procedure name */
196- if (strcmp (prosrc ,"-" )== 0 )
197- prosrc = procedureName ;
198- (void )load_external_function ((char * )probin ,
199- (char * )prosrc ,
200- true,
201- & libraryhandle );
202- (void )fetch_finfo_record (libraryhandle , (char * )prosrc );
203- }
204143
205144/*
206145 * All seems OK; prepare the data to be inserted into pg_proc.
@@ -316,6 +255,14 @@ ProcedureCreate(const char *procedureName,
316255
317256heap_close (rel ,RowExclusiveLock );
318257
258+ /* Verify function body */
259+ if (OidIsValid (languageValidator ))
260+ {
261+ /* Advance command counter so recursive functions can be defined */
262+ CommandCounterIncrement ();
263+ OidFunctionCall1 (languageValidator ,retval );
264+ }
265+
319266return retval ;
320267}
321268
@@ -454,3 +401,122 @@ checkretval(Oid rettype, List *queryTreeList)
454401
455402heap_close (reln ,AccessShareLock );
456403}
404+
405+
406+
407+ /*
408+ * Validator for internal functions
409+ *
410+ * Check that the given internal function name (the "prosrc" value) is
411+ * a known builtin function.
412+ */
413+ Datum
414+ fmgr_internal_validator (PG_FUNCTION_ARGS )
415+ {
416+ Oid funcoid = PG_GETARG_OID (0 );
417+ HeapTuple tuple ;
418+ Form_pg_proc proc ;
419+ bool isnull ;
420+ Datum tmp ;
421+ char * prosrc ;
422+
423+ tuple = SearchSysCache (PROCOID ,funcoid ,0 ,0 ,0 );
424+ if (!HeapTupleIsValid (tuple ))
425+ elog (ERROR ,"cache lookup of function %u failed" ,funcoid );
426+ proc = (Form_pg_proc )GETSTRUCT (tuple );
427+
428+ tmp = SysCacheGetAttr (PROCOID ,tuple ,Anum_pg_proc_prosrc ,& isnull );
429+ if (isnull )
430+ elog (ERROR ,"null prosrc" );
431+ prosrc = DatumGetCString (DirectFunctionCall1 (textout ,tmp ));
432+
433+ if (fmgr_internal_function (prosrc )== InvalidOid )
434+ elog (ERROR ,"there is no built-in function named \"%s\"" ,prosrc );
435+
436+ ReleaseSysCache (tuple );
437+ PG_RETURN_BOOL (true);
438+ }
439+
440+
441+
442+ /*
443+ * Validator for C language functions
444+ *
445+ * Make sure that the library file exists, is loadable, and contains
446+ * the specified link symbol. Also check for a valid function
447+ * information record.
448+ */
449+ Datum
450+ fmgr_c_validator (PG_FUNCTION_ARGS )
451+ {
452+ Oid funcoid = PG_GETARG_OID (0 );
453+ void * libraryhandle ;
454+ HeapTuple tuple ;
455+ Form_pg_proc proc ;
456+ bool isnull ;
457+ Datum tmp ;
458+ char * prosrc ;
459+ char * probin ;
460+
461+ tuple = SearchSysCache (PROCOID ,funcoid ,0 ,0 ,0 );
462+ if (!HeapTupleIsValid (tuple ))
463+ elog (ERROR ,"cache lookup of function %u failed" ,funcoid );
464+ proc = (Form_pg_proc )GETSTRUCT (tuple );
465+
466+ tmp = SysCacheGetAttr (PROCOID ,tuple ,Anum_pg_proc_prosrc ,& isnull );
467+ if (isnull )
468+ elog (ERROR ,"null prosrc" );
469+ prosrc = DatumGetCString (DirectFunctionCall1 (textout ,tmp ));
470+
471+ tmp = SysCacheGetAttr (PROCOID ,tuple ,Anum_pg_proc_probin ,& isnull );
472+ if (isnull )
473+ elog (ERROR ,"null probin" );
474+ probin = DatumGetCString (DirectFunctionCall1 (textout ,tmp ));
475+
476+ (void )load_external_function (probin ,prosrc , true,& libraryhandle );
477+ (void )fetch_finfo_record (libraryhandle ,prosrc );
478+
479+ ReleaseSysCache (tuple );
480+ PG_RETURN_BOOL (true);
481+ }
482+
483+
484+
485+ /*
486+ * Validator for SQL language functions
487+ *
488+ * Parse it here in order to be sure that it contains no syntax
489+ * errors.
490+ */
491+ Datum
492+ fmgr_sql_validator (PG_FUNCTION_ARGS )
493+ {
494+ Oid funcoid = PG_GETARG_OID (0 );
495+ HeapTuple tuple ;
496+ Form_pg_proc proc ;
497+ List * querytree_list ;
498+ bool isnull ;
499+ Datum tmp ;
500+ char * prosrc ;
501+
502+ tuple = SearchSysCache (PROCOID ,funcoid ,0 ,0 ,0 );
503+ if (!HeapTupleIsValid (tuple ))
504+ elog (ERROR ,"cache lookup of function %u failed" ,funcoid );
505+
506+ proc = (Form_pg_proc )GETSTRUCT (tuple );
507+
508+ if (!OidIsValid (proc -> prorettype ))
509+ elog (ERROR ,"SQL functions cannot return type \"opaque\"" );
510+
511+ tmp = SysCacheGetAttr (PROCOID ,tuple ,Anum_pg_proc_prosrc ,& isnull );
512+ if (isnull )
513+ elog (ERROR ,"null prosrc" );
514+
515+ prosrc = DatumGetCString (DirectFunctionCall1 (textout ,tmp ));
516+
517+ querytree_list = pg_parse_and_rewrite (prosrc ,proc -> proargtypes ,proc -> pronargs );
518+ checkretval (proc -> prorettype ,querytree_list );
519+
520+ ReleaseSysCache (tuple );
521+ PG_RETURN_BOOL (true);
522+ }