OSDN Git Service

Apply the core parts of Dennis Bjorklund's patch to allow function
[pg-rex/syncrep.git] / src / backend / catalog / pg_proc.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_proc.c
4  *        routines to support manipulation of the pg_proc relation
5  *
6  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.111 2004/01/06 23:55:18 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "access/heapam.h"
18 #include "catalog/catname.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/pg_language.h"
22 #include "catalog/pg_proc.h"
23 #include "executor/executor.h"
24 #include "fmgr.h"
25 #include "miscadmin.h"
26 #include "parser/parse_coerce.h"
27 #include "parser/parse_expr.h"
28 #include "parser/parse_type.h"
29 #include "tcop/tcopprot.h"
30 #include "utils/acl.h"
31 #include "utils/builtins.h"
32 #include "utils/lsyscache.h"
33 #include "utils/sets.h"
34 #include "utils/syscache.h"
35
36
37 /* GUC parameter */
38 bool            check_function_bodies = true;
39
40
41 Datum           fmgr_internal_validator(PG_FUNCTION_ARGS);
42 Datum           fmgr_c_validator(PG_FUNCTION_ARGS);
43 Datum           fmgr_sql_validator(PG_FUNCTION_ARGS);
44
45 static Datum create_parameternames_array(int parameterCount,
46                                                                                  const char *parameterNames[]);
47
48
49 /* ----------------------------------------------------------------
50  *              ProcedureCreate
51  * ----------------------------------------------------------------
52  */
53 Oid
54 ProcedureCreate(const char *procedureName,
55                                 Oid procNamespace,
56                                 bool replace,
57                                 bool returnsSet,
58                                 Oid returnType,
59                                 Oid languageObjectId,
60                                 Oid languageValidator,
61                                 const char *prosrc,
62                                 const char *probin,
63                                 bool isAgg,
64                                 bool security_definer,
65                                 bool isStrict,
66                                 char volatility,
67                                 int parameterCount,
68                                 const Oid *parameterTypes,
69                                 const char *parameterNames[])
70 {
71         int                     i;
72         Relation        rel;
73         HeapTuple       tup;
74         HeapTuple       oldtup;
75         char            nulls[Natts_pg_proc];
76         Datum           values[Natts_pg_proc];
77         char            replaces[Natts_pg_proc];
78         Oid                     typev[FUNC_MAX_ARGS];
79         Datum           namesarray;
80         Oid                     relid;
81         NameData        procname;
82         TupleDesc       tupDesc;
83         Oid                     retval;
84         bool            is_update;
85         ObjectAddress myself,
86                                 referenced;
87
88         /*
89          * sanity checks
90          */
91         Assert(PointerIsValid(prosrc));
92         Assert(PointerIsValid(probin));
93
94         if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
95                 ereport(ERROR,
96                                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
97                                  errmsg("functions cannot have more than %d arguments",
98                                                 FUNC_MAX_ARGS)));
99
100         /*
101          * Do not allow return type ANYARRAY or ANYELEMENT unless at least one
102          * argument is also ANYARRAY or ANYELEMENT
103          */
104         if (returnType == ANYARRAYOID || returnType == ANYELEMENTOID)
105         {
106                 bool            genericParam = false;
107
108                 for (i = 0; i < parameterCount; i++)
109                 {
110                         if (parameterTypes[i] == ANYARRAYOID ||
111                                 parameterTypes[i] == ANYELEMENTOID)
112                         {
113                                 genericParam = true;
114                                 break;
115                         }
116                 }
117
118                 if (!genericParam)
119                         ereport(ERROR,
120                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
121                                          errmsg("cannot determine result data type"),
122                                          errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type.")));
123         }
124
125         /* Make sure we have a zero-padded param type array */
126         MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid));
127         if (parameterCount > 0)
128                 memcpy(typev, parameterTypes, parameterCount * sizeof(Oid));
129
130         /* Process param names, if given */
131         namesarray = create_parameternames_array(parameterCount, parameterNames);
132
133         if (languageObjectId == SQLlanguageId)
134         {
135                 /*
136                  * If this call is defining a set, check if the set is already
137                  * defined by looking to see whether this call's function text
138                  * matches a function already in pg_proc.  If so just return the
139                  * OID of the existing set.
140                  */
141                 if (strcmp(procedureName, GENERICSETNAME) == 0)
142                 {
143 #ifdef SETS_FIXED
144
145                         /*
146                          * The code below doesn't work any more because the PROSRC
147                          * system cache and the pg_proc_prosrc_index have been
148                          * removed. Instead a sequential heap scan or something better
149                          * must get implemented. The reason for removing is that
150                          * nbtree index crashes if sources exceed 2K --- what's likely
151                          * for procedural languages.
152                          *
153                          * 1999/09/30 Jan
154                          */
155                         text       *prosrctext;
156
157                         prosrctext = DatumGetTextP(DirectFunctionCall1(textin,
158                                                                                            CStringGetDatum(prosrc)));
159                         retval = GetSysCacheOid(PROSRC,
160                                                                         PointerGetDatum(prosrctext),
161                                                                         0, 0, 0);
162                         pfree(prosrctext);
163                         if (OidIsValid(retval))
164                                 return retval;
165 #else
166                         elog(ERROR, "lookup for procedure by source needs fix (Jan)");
167 #endif   /* SETS_FIXED */
168                 }
169         }
170
171         /*
172          * don't allow functions of complex types that have the same name as
173          * existing attributes of the type
174          */
175         if (parameterCount == 1 && OidIsValid(typev[0]) &&
176                 (relid = typeidTypeRelid(typev[0])) != InvalidOid &&
177                 get_attnum(relid, (char *) procedureName) != InvalidAttrNumber)
178                 ereport(ERROR,
179                                 (errcode(ERRCODE_DUPLICATE_COLUMN),
180                                  errmsg("\"%s\" is already an attribute of type %s",
181                                                 procedureName, format_type_be(typev[0]))));
182
183         /*
184          * All seems OK; prepare the data to be inserted into pg_proc.
185          */
186
187         for (i = 0; i < Natts_pg_proc; ++i)
188         {
189                 nulls[i] = ' ';
190                 values[i] = (Datum) NULL;
191                 replaces[i] = 'r';
192         }
193
194         i = 0;
195         namestrcpy(&procname, procedureName);
196         values[i++] = NameGetDatum(&procname);          /* proname */
197         values[i++] = ObjectIdGetDatum(procNamespace);          /* pronamespace */
198         values[i++] = Int32GetDatum(GetUserId());       /* proowner */
199         values[i++] = ObjectIdGetDatum(languageObjectId);       /* prolang */
200         values[i++] = BoolGetDatum(isAgg);      /* proisagg */
201         values[i++] = BoolGetDatum(security_definer);           /* prosecdef */
202         values[i++] = BoolGetDatum(isStrict);           /* proisstrict */
203         values[i++] = BoolGetDatum(returnsSet);         /* proretset */
204         values[i++] = CharGetDatum(volatility);         /* provolatile */
205         values[i++] = UInt16GetDatum(parameterCount);           /* pronargs */
206         values[i++] = ObjectIdGetDatum(returnType); /* prorettype */
207         values[i++] = PointerGetDatum(typev);           /* proargtypes */
208         values[i++] = namesarray;                                       /* proargnames */
209         if (namesarray == PointerGetDatum(NULL))
210                 nulls[Anum_pg_proc_proargnames - 1] = 'n';
211         values[i++] = DirectFunctionCall1(textin,       /* prosrc */
212                                                                           CStringGetDatum(prosrc));
213         values[i++] = DirectFunctionCall1(textin,       /* probin */
214                                                                           CStringGetDatum(probin));
215         /* proacl will be handled below */
216
217         rel = heap_openr(ProcedureRelationName, RowExclusiveLock);
218         tupDesc = rel->rd_att;
219
220         /* Check for pre-existing definition */
221         oldtup = SearchSysCache(PROCNAMENSP,
222                                                         PointerGetDatum(procedureName),
223                                                         UInt16GetDatum(parameterCount),
224                                                         PointerGetDatum(typev),
225                                                         ObjectIdGetDatum(procNamespace));
226
227         if (HeapTupleIsValid(oldtup))
228         {
229                 /* There is one; okay to replace it? */
230                 Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);
231
232                 if (!replace)
233                         ereport(ERROR,
234                                         (errcode(ERRCODE_DUPLICATE_FUNCTION),
235                                          errmsg("function \"%s\" already exists with same argument types",
236                                                         procedureName)));
237                 if (GetUserId() != oldproc->proowner && !superuser())
238                         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
239                                                    procedureName);
240
241                 /*
242                  * Not okay to change the return type of the existing proc, since
243                  * existing rules, views, etc may depend on the return type.
244                  */
245                 if (returnType != oldproc->prorettype ||
246                         returnsSet != oldproc->proretset)
247                         ereport(ERROR,
248                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
249                                 errmsg("cannot change return type of existing function"),
250                                          errhint("Use DROP FUNCTION first.")));
251
252                 /* Can't change aggregate status, either */
253                 if (oldproc->proisagg != isAgg)
254                 {
255                         if (oldproc->proisagg)
256                                 ereport(ERROR,
257                                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
258                                                  errmsg("function \"%s\" is an aggregate",
259                                                                 procedureName)));
260                         else
261                                 ereport(ERROR,
262                                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
263                                                  errmsg("function \"%s\" is not an aggregate",
264                                                                 procedureName)));
265                 }
266
267                 /* do not change existing ownership or permissions, either */
268                 replaces[Anum_pg_proc_proowner - 1] = ' ';
269                 replaces[Anum_pg_proc_proacl - 1] = ' ';
270
271                 /* Okay, do it... */
272                 tup = heap_modifytuple(oldtup, rel, values, nulls, replaces);
273                 simple_heap_update(rel, &tup->t_self, tup);
274
275                 ReleaseSysCache(oldtup);
276                 is_update = true;
277         }
278         else
279         {
280                 /* Creating a new procedure */
281
282                 /* start out with empty permissions */
283                 nulls[Anum_pg_proc_proacl - 1] = 'n';
284
285                 tup = heap_formtuple(tupDesc, values, nulls);
286                 simple_heap_insert(rel, tup);
287                 is_update = false;
288         }
289
290         /* Need to update indexes for either the insert or update case */
291         CatalogUpdateIndexes(rel, tup);
292
293         retval = HeapTupleGetOid(tup);
294
295         /*
296          * Create dependencies for the new function.  If we are updating an
297          * existing function, first delete any existing pg_depend entries.
298          */
299         if (is_update)
300                 deleteDependencyRecordsFor(RelOid_pg_proc, retval);
301
302         myself.classId = RelOid_pg_proc;
303         myself.objectId = retval;
304         myself.objectSubId = 0;
305
306         /* dependency on namespace */
307         referenced.classId = get_system_catalog_relid(NamespaceRelationName);
308         referenced.objectId = procNamespace;
309         referenced.objectSubId = 0;
310         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
311
312         /* dependency on implementation language */
313         referenced.classId = get_system_catalog_relid(LanguageRelationName);
314         referenced.objectId = languageObjectId;
315         referenced.objectSubId = 0;
316         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
317
318         /* dependency on return type */
319         referenced.classId = RelOid_pg_type;
320         referenced.objectId = returnType;
321         referenced.objectSubId = 0;
322         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
323
324         /* dependency on input types */
325         for (i = 0; i < parameterCount; i++)
326         {
327                 referenced.classId = RelOid_pg_type;
328                 referenced.objectId = typev[i];
329                 referenced.objectSubId = 0;
330                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
331         }
332
333         heap_freetuple(tup);
334
335         heap_close(rel, RowExclusiveLock);
336
337         /* Verify function body */
338         if (OidIsValid(languageValidator))
339         {
340                 /* Advance command counter so new tuple can be seen by validator */
341                 CommandCounterIncrement();
342                 OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval));
343         }
344
345         return retval;
346 }
347
348
349 /*
350  * create_parameternames_array - build proargnames value from an array
351  * of C strings.  Returns a NULL pointer if no names provided.
352  */
353 static Datum
354 create_parameternames_array(int parameterCount, const char *parameterNames[])
355 {
356         Datum           elems[FUNC_MAX_ARGS];
357         bool            found = false;
358         ArrayType  *names;
359         int                     i;
360
361         if (!parameterNames)
362                 return PointerGetDatum(NULL);
363
364         for (i=0; i<parameterCount; i++)
365         {
366                 const char *s = parameterNames[i];
367
368                 if (s && *s)
369                         found = true;
370                 else
371                         s = "";
372
373                 elems[i] = DirectFunctionCall1(textin, CStringGetDatum(s));
374         }
375
376         if (!found)
377                 return PointerGetDatum(NULL);
378
379         names = construct_array(elems, parameterCount, TEXTOID, -1, false, 'i');
380
381         return PointerGetDatum(names);
382 }
383
384
385 /*
386  * check_sql_fn_retval() -- check return value of a list of sql parse trees.
387  *
388  * The return value of a sql function is the value returned by
389  * the final query in the function.  We do some ad-hoc type checking here
390  * to be sure that the user is returning the type he claims.
391  *
392  * This is normally applied during function definition, but in the case
393  * of a function with polymorphic arguments, we instead apply it during
394  * function execution startup.  The rettype is then the actual resolved
395  * output type of the function, rather than the declared type.  (Therefore,
396  * we should never see ANYARRAY or ANYELEMENT as rettype.)
397  */
398 void
399 check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
400 {
401         Query      *parse;
402         int                     cmd;
403         List       *tlist;
404         List       *tlistitem;
405         int                     tlistlen;
406         Oid                     typerelid;
407         Oid                     restype;
408         Relation        reln;
409         int                     relnatts;               /* physical number of columns in rel */
410         int                     rellogcols;             /* # of nondeleted columns in rel */
411         int                     colindex;               /* physical column index */
412
413         /* guard against empty function body; OK only if void return type */
414         if (queryTreeList == NIL)
415         {
416                 if (rettype != VOIDOID)
417                         ereport(ERROR,
418                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
419                                          errmsg("return type mismatch in function declared to return %s",
420                                                         format_type_be(rettype)),
421                          errdetail("Function's final statement must be a SELECT.")));
422                 return;
423         }
424
425         /* find the final query */
426         parse = (Query *) llast(queryTreeList);
427
428         cmd = parse->commandType;
429         tlist = parse->targetList;
430
431         /*
432          * The last query must be a SELECT if and only if return type isn't
433          * VOID.
434          */
435         if (rettype == VOIDOID)
436         {
437                 if (cmd == CMD_SELECT)
438                         ereport(ERROR,
439                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
440                                          errmsg("return type mismatch in function declared to return %s",
441                                                         format_type_be(rettype)),
442                                          errdetail("Function's final statement must not be a SELECT.")));
443                 return;
444         }
445
446         /* by here, the function is declared to return some type */
447         if (cmd != CMD_SELECT)
448                 ereport(ERROR,
449                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
450                  errmsg("return type mismatch in function declared to return %s",
451                                 format_type_be(rettype)),
452                          errdetail("Function's final statement must be a SELECT.")));
453
454         /*
455          * Count the non-junk entries in the result targetlist.
456          */
457         tlistlen = ExecCleanTargetListLength(tlist);
458
459         typerelid = typeidTypeRelid(rettype);
460
461         if (fn_typtype == 'b' || fn_typtype == 'd')
462         {
463                 /* Shouldn't have a typerelid */
464                 Assert(typerelid == InvalidOid);
465
466                 /*
467                  * For base-type returns, the target list should have exactly one
468                  * entry, and its type should agree with what the user declared.
469                  * (As of Postgres 7.2, we accept binary-compatible types too.)
470                  */
471                 if (tlistlen != 1)
472                         ereport(ERROR,
473                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
474                                          errmsg("return type mismatch in function declared to return %s",
475                                                         format_type_be(rettype)),
476                          errdetail("Final SELECT must return exactly one column.")));
477
478                 restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
479                 if (!IsBinaryCoercible(restype, rettype))
480                         ereport(ERROR,
481                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
482                                          errmsg("return type mismatch in function declared to return %s",
483                                                         format_type_be(rettype)),
484                                          errdetail("Actual return type is %s.",
485                                                            format_type_be(restype))));
486         }
487         else if (fn_typtype == 'c')
488         {
489                 /* Must have a typerelid */
490                 Assert(typerelid != InvalidOid);
491
492                 /*
493                  * If the target list is of length 1, and the type of the varnode
494                  * in the target list matches the declared return type, this is
495                  * okay. This can happen, for example, where the body of the
496                  * function is 'SELECT func2()', where func2 has the same return
497                  * type as the function that's calling it.
498                  */
499                 if (tlistlen == 1)
500                 {
501                         restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
502                         if (IsBinaryCoercible(restype, rettype))
503                                 return;
504                 }
505
506                 /*
507                  * Otherwise verify that the targetlist matches the return tuple
508                  * type. This part of the typechecking is a hack. We look up the
509                  * relation that is the declared return type, and scan the
510                  * non-deleted attributes to ensure that they match the datatypes
511                  * of the non-resjunk columns.
512                  */
513                 reln = relation_open(typerelid, AccessShareLock);
514                 relnatts = reln->rd_rel->relnatts;
515                 rellogcols = 0;                 /* we'll count nondeleted cols as we go */
516                 colindex = 0;
517
518                 foreach(tlistitem, tlist)
519                 {
520                         TargetEntry *tle = (TargetEntry *) lfirst(tlistitem);
521                         Form_pg_attribute attr;
522                         Oid                     tletype;
523                         Oid                     atttype;
524
525                         if (tle->resdom->resjunk)
526                                 continue;
527
528                         do
529                         {
530                                 colindex++;
531                                 if (colindex > relnatts)
532                                         ereport(ERROR,
533                                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
534                                                          errmsg("return type mismatch in function declared to return %s",
535                                                                         format_type_be(rettype)),
536                                         errdetail("Final SELECT returns too many columns.")));
537                                 attr = reln->rd_att->attrs[colindex - 1];
538                         } while (attr->attisdropped);
539                         rellogcols++;
540
541                         tletype = exprType((Node *) tle->expr);
542                         atttype = attr->atttypid;
543                         if (!IsBinaryCoercible(tletype, atttype))
544                                 ereport(ERROR,
545                                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
546                                                  errmsg("return type mismatch in function declared to return %s",
547                                                                 format_type_be(rettype)),
548                                                  errdetail("Final SELECT returns %s instead of %s at column %d.",
549                                                                    format_type_be(tletype),
550                                                                    format_type_be(atttype),
551                                                                    rellogcols)));
552                 }
553
554                 for (;;)
555                 {
556                         colindex++;
557                         if (colindex > relnatts)
558                                 break;
559                         if (!reln->rd_att->attrs[colindex - 1]->attisdropped)
560                                 rellogcols++;
561                 }
562
563                 if (tlistlen != rellogcols)
564                         ereport(ERROR,
565                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
566                                          errmsg("return type mismatch in function declared to return %s",
567                                                         format_type_be(rettype)),
568                                          errdetail("Final SELECT returns too few columns.")));
569
570                 relation_close(reln, AccessShareLock);
571         }
572         else if (rettype == RECORDOID)
573         {
574                 /* Shouldn't have a typerelid */
575                 Assert(typerelid == InvalidOid);
576
577                 /*
578                  * For RECORD return type, defer this check until we get the first
579                  * tuple.
580                  */
581         }
582         else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
583         {
584                 /* This should already have been caught ... */
585                 ereport(ERROR,
586                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
587                                  errmsg("cannot determine result data type"),
588                                  errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type.")));
589         }
590         else
591                 ereport(ERROR,
592                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
593                           errmsg("return type %s is not supported for SQL functions",
594                                          format_type_be(rettype))));
595 }
596
597
598
599 /*
600  * Validator for internal functions
601  *
602  * Check that the given internal function name (the "prosrc" value) is
603  * a known builtin function.
604  */
605 Datum
606 fmgr_internal_validator(PG_FUNCTION_ARGS)
607 {
608         Oid                     funcoid = PG_GETARG_OID(0);
609         HeapTuple       tuple;
610         Form_pg_proc proc;
611         bool            isnull;
612         Datum           tmp;
613         char       *prosrc;
614
615         /*
616          * We do not honor check_function_bodies since it's unlikely the
617          * function name will be found later if it isn't there now.
618          */
619
620         tuple = SearchSysCache(PROCOID,
621                                                    ObjectIdGetDatum(funcoid),
622                                                    0, 0, 0);
623         if (!HeapTupleIsValid(tuple))
624                 elog(ERROR, "cache lookup failed for function %u", funcoid);
625         proc = (Form_pg_proc) GETSTRUCT(tuple);
626
627         tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
628         if (isnull)
629                 elog(ERROR, "null prosrc");
630         prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
631
632         if (fmgr_internal_function(prosrc) == InvalidOid)
633                 ereport(ERROR,
634                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
635                                  errmsg("there is no built-in function named \"%s\"",
636                                                 prosrc)));
637
638         ReleaseSysCache(tuple);
639
640         PG_RETURN_VOID();
641 }
642
643
644
645 /*
646  * Validator for C language functions
647  *
648  * Make sure that the library file exists, is loadable, and contains
649  * the specified link symbol. Also check for a valid function
650  * information record.
651  */
652 Datum
653 fmgr_c_validator(PG_FUNCTION_ARGS)
654 {
655         Oid                     funcoid = PG_GETARG_OID(0);
656         void       *libraryhandle;
657         HeapTuple       tuple;
658         Form_pg_proc proc;
659         bool            isnull;
660         Datum           tmp;
661         char       *prosrc;
662         char       *probin;
663
664         /*
665          * It'd be most consistent to skip the check if !check_function_bodies,
666          * but the purpose of that switch is to be helpful for pg_dump loading,
667          * and for pg_dump loading it's much better if we *do* check.
668          */
669
670         tuple = SearchSysCache(PROCOID,
671                                                    ObjectIdGetDatum(funcoid),
672                                                    0, 0, 0);
673         if (!HeapTupleIsValid(tuple))
674                 elog(ERROR, "cache lookup failed for function %u", funcoid);
675         proc = (Form_pg_proc) GETSTRUCT(tuple);
676
677         tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
678         if (isnull)
679                 elog(ERROR, "null prosrc");
680         prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
681
682         tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull);
683         if (isnull)
684                 elog(ERROR, "null probin");
685         probin = DatumGetCString(DirectFunctionCall1(textout, tmp));
686
687         (void) load_external_function(probin, prosrc, true, &libraryhandle);
688         (void) fetch_finfo_record(libraryhandle, prosrc);
689
690         ReleaseSysCache(tuple);
691
692         PG_RETURN_VOID();
693 }
694
695
696 /*
697  * Validator for SQL language functions
698  *
699  * Parse it here in order to be sure that it contains no syntax errors.
700  */
701 Datum
702 fmgr_sql_validator(PG_FUNCTION_ARGS)
703 {
704         Oid                     funcoid = PG_GETARG_OID(0);
705         HeapTuple       tuple;
706         Form_pg_proc proc;
707         List       *querytree_list;
708         bool            isnull;
709         Datum           tmp;
710         char       *prosrc;
711         char            functyptype;
712         bool            haspolyarg;
713         int                     i;
714
715         tuple = SearchSysCache(PROCOID,
716                                                    ObjectIdGetDatum(funcoid),
717                                                    0, 0, 0);
718         if (!HeapTupleIsValid(tuple))
719                 elog(ERROR, "cache lookup failed for function %u", funcoid);
720         proc = (Form_pg_proc) GETSTRUCT(tuple);
721
722         functyptype = get_typtype(proc->prorettype);
723
724         /* Disallow pseudotype result */
725         /* except for RECORD, VOID, ANYARRAY, or ANYELEMENT */
726         if (functyptype == 'p' &&
727                 proc->prorettype != RECORDOID &&
728                 proc->prorettype != VOIDOID &&
729                 proc->prorettype != ANYARRAYOID &&
730                 proc->prorettype != ANYELEMENTOID)
731                 ereport(ERROR,
732                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
733                                  errmsg("SQL functions cannot return type %s",
734                                                 format_type_be(proc->prorettype))));
735
736         /* Disallow pseudotypes in arguments */
737         /* except for ANYARRAY or ANYELEMENT */
738         haspolyarg = false;
739         for (i = 0; i < proc->pronargs; i++)
740         {
741                 if (get_typtype(proc->proargtypes[i]) == 'p')
742                 {
743                         if (proc->proargtypes[i] == ANYARRAYOID ||
744                                 proc->proargtypes[i] == ANYELEMENTOID)
745                                 haspolyarg = true;
746                         else
747                                 ereport(ERROR,
748                                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
749                                  errmsg("SQL functions cannot have arguments of type %s",
750                                                 format_type_be(proc->proargtypes[i]))));
751                 }
752         }
753
754         /* Postpone body checks if !check_function_bodies */
755         if (check_function_bodies)
756         {
757                 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
758                 if (isnull)
759                         elog(ERROR, "null prosrc");
760
761                 prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
762
763                 /*
764                  * We can't do full prechecking of the function definition if there
765                  * are any polymorphic input types, because actual datatypes of
766                  * expression results will be unresolvable.  The check will be done
767                  * at runtime instead.
768                  *
769                  * We can run the text through the raw parser though; this will at
770                  * least catch silly syntactic errors.
771                  */
772                 if (!haspolyarg)
773                 {
774                         querytree_list = pg_parse_and_rewrite(prosrc,
775                                                                                                   proc->proargtypes,
776                                                                                                   proc->pronargs);
777                         check_sql_fn_retval(proc->prorettype, functyptype, querytree_list);
778                 }
779                 else
780                         querytree_list = pg_parse_query(prosrc);
781         }
782
783         ReleaseSysCache(tuple);
784
785         PG_RETURN_VOID();
786 }