8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
20
20
#include "catalog/pg_language.h"
21
21
#include "catalog/pg_proc.h"
22
22
#include "executor/executor.h"
23
+ #include "fmgr.h"
23
24
#include "miscadmin.h"
24
25
#include "parser/parse_coerce.h"
25
26
#include "parser/parse_expr.h"
32
33
33
34
34
35
static 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 );
35
39
36
40
37
41
/* ----------------------------------------------------------------
@@ -45,6 +49,7 @@ ProcedureCreate(const char *procedureName,
45
49
bool returnsSet ,
46
50
Oid returnType ,
47
51
Oid languageObjectId ,
52
+ Oid languageValidator ,
48
53
const char * prosrc ,
49
54
const char * probin ,
50
55
bool isAgg ,
@@ -66,7 +71,6 @@ ProcedureCreate(const char *procedureName,
66
71
char nulls [Natts_pg_proc ];
67
72
Datum values [Natts_pg_proc ];
68
73
char replaces [Natts_pg_proc ];
69
- List * querytree_list ;
70
74
Oid typev [FUNC_MAX_ARGS ];
71
75
Oid relid ;
72
76
NameData procname ;
@@ -126,12 +130,6 @@ ProcedureCreate(const char *procedureName,
126
130
}
127
131
}
128
132
129
- if (!OidIsValid (returnType ))
130
- {
131
- if (languageObjectId == SQLlanguageId )
132
- elog (ERROR ,"SQL functions cannot return type \"opaque\"" );
133
- }
134
-
135
133
/*
136
134
* don't allow functions of complex types that have the same name as
137
135
* existing attributes of the type
@@ -142,65 +140,6 @@ ProcedureCreate(const char *procedureName,
142
140
elog (ERROR ,"method %s already an attribute of type %s" ,
143
141
procedureName ,format_type_be (typev [0 ]));
144
142
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
- }
204
143
205
144
/*
206
145
* All seems OK; prepare the data to be inserted into pg_proc.
@@ -316,6 +255,14 @@ ProcedureCreate(const char *procedureName,
316
255
317
256
heap_close (rel ,RowExclusiveLock );
318
257
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
+
319
266
return retval ;
320
267
}
321
268
@@ -454,3 +401,122 @@ checkretval(Oid rettype, List *queryTreeList)
454
401
455
402
heap_close (reln ,AccessShareLock );
456
403
}
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
+ }