OSDN Git Service

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