1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_proc relation
6 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.111 2004/01/06 23:55:18 tgl Exp $
13 *-------------------------------------------------------------------------
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"
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"
38 bool check_function_bodies = true;
41 Datum fmgr_internal_validator(PG_FUNCTION_ARGS);
42 Datum fmgr_c_validator(PG_FUNCTION_ARGS);
43 Datum fmgr_sql_validator(PG_FUNCTION_ARGS);
45 static Datum create_parameternames_array(int parameterCount,
46 const char *parameterNames[]);
49 /* ----------------------------------------------------------------
51 * ----------------------------------------------------------------
54 ProcedureCreate(const char *procedureName,
60 Oid languageValidator,
64 bool security_definer,
68 const Oid *parameterTypes,
69 const char *parameterNames[])
75 char nulls[Natts_pg_proc];
76 Datum values[Natts_pg_proc];
77 char replaces[Natts_pg_proc];
78 Oid typev[FUNC_MAX_ARGS];
91 Assert(PointerIsValid(prosrc));
92 Assert(PointerIsValid(probin));
94 if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
96 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
97 errmsg("functions cannot have more than %d arguments",
101 * Do not allow return type ANYARRAY or ANYELEMENT unless at least one
102 * argument is also ANYARRAY or ANYELEMENT
104 if (returnType == ANYARRAYOID || returnType == ANYELEMENTOID)
106 bool genericParam = false;
108 for (i = 0; i < parameterCount; i++)
110 if (parameterTypes[i] == ANYARRAYOID ||
111 parameterTypes[i] == ANYELEMENTOID)
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.")));
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));
130 /* Process param names, if given */
131 namesarray = create_parameternames_array(parameterCount, parameterNames);
133 if (languageObjectId == SQLlanguageId)
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.
141 if (strcmp(procedureName, GENERICSETNAME) == 0)
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.
157 prosrctext = DatumGetTextP(DirectFunctionCall1(textin,
158 CStringGetDatum(prosrc)));
159 retval = GetSysCacheOid(PROSRC,
160 PointerGetDatum(prosrctext),
163 if (OidIsValid(retval))
166 elog(ERROR, "lookup for procedure by source needs fix (Jan)");
167 #endif /* SETS_FIXED */
172 * don't allow functions of complex types that have the same name as
173 * existing attributes of the type
175 if (parameterCount == 1 && OidIsValid(typev[0]) &&
176 (relid = typeidTypeRelid(typev[0])) != InvalidOid &&
177 get_attnum(relid, (char *) procedureName) != InvalidAttrNumber)
179 (errcode(ERRCODE_DUPLICATE_COLUMN),
180 errmsg("\"%s\" is already an attribute of type %s",
181 procedureName, format_type_be(typev[0]))));
184 * All seems OK; prepare the data to be inserted into pg_proc.
187 for (i = 0; i < Natts_pg_proc; ++i)
190 values[i] = (Datum) NULL;
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 */
217 rel = heap_openr(ProcedureRelationName, RowExclusiveLock);
218 tupDesc = rel->rd_att;
220 /* Check for pre-existing definition */
221 oldtup = SearchSysCache(PROCNAMENSP,
222 PointerGetDatum(procedureName),
223 UInt16GetDatum(parameterCount),
224 PointerGetDatum(typev),
225 ObjectIdGetDatum(procNamespace));
227 if (HeapTupleIsValid(oldtup))
229 /* There is one; okay to replace it? */
230 Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);
234 (errcode(ERRCODE_DUPLICATE_FUNCTION),
235 errmsg("function \"%s\" already exists with same argument types",
237 if (GetUserId() != oldproc->proowner && !superuser())
238 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
242 * Not okay to change the return type of the existing proc, since
243 * existing rules, views, etc may depend on the return type.
245 if (returnType != oldproc->prorettype ||
246 returnsSet != oldproc->proretset)
248 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
249 errmsg("cannot change return type of existing function"),
250 errhint("Use DROP FUNCTION first.")));
252 /* Can't change aggregate status, either */
253 if (oldproc->proisagg != isAgg)
255 if (oldproc->proisagg)
257 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
258 errmsg("function \"%s\" is an aggregate",
262 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
263 errmsg("function \"%s\" is not an aggregate",
267 /* do not change existing ownership or permissions, either */
268 replaces[Anum_pg_proc_proowner - 1] = ' ';
269 replaces[Anum_pg_proc_proacl - 1] = ' ';
272 tup = heap_modifytuple(oldtup, rel, values, nulls, replaces);
273 simple_heap_update(rel, &tup->t_self, tup);
275 ReleaseSysCache(oldtup);
280 /* Creating a new procedure */
282 /* start out with empty permissions */
283 nulls[Anum_pg_proc_proacl - 1] = 'n';
285 tup = heap_formtuple(tupDesc, values, nulls);
286 simple_heap_insert(rel, tup);
290 /* Need to update indexes for either the insert or update case */
291 CatalogUpdateIndexes(rel, tup);
293 retval = HeapTupleGetOid(tup);
296 * Create dependencies for the new function. If we are updating an
297 * existing function, first delete any existing pg_depend entries.
300 deleteDependencyRecordsFor(RelOid_pg_proc, retval);
302 myself.classId = RelOid_pg_proc;
303 myself.objectId = retval;
304 myself.objectSubId = 0;
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);
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);
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);
324 /* dependency on input types */
325 for (i = 0; i < parameterCount; i++)
327 referenced.classId = RelOid_pg_type;
328 referenced.objectId = typev[i];
329 referenced.objectSubId = 0;
330 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
335 heap_close(rel, RowExclusiveLock);
337 /* Verify function body */
338 if (OidIsValid(languageValidator))
340 /* Advance command counter so new tuple can be seen by validator */
341 CommandCounterIncrement();
342 OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval));
350 * create_parameternames_array - build proargnames value from an array
351 * of C strings. Returns a NULL pointer if no names provided.
354 create_parameternames_array(int parameterCount, const char *parameterNames[])
356 Datum elems[FUNC_MAX_ARGS];
362 return PointerGetDatum(NULL);
364 for (i=0; i<parameterCount; i++)
366 const char *s = parameterNames[i];
373 elems[i] = DirectFunctionCall1(textin, CStringGetDatum(s));
377 return PointerGetDatum(NULL);
379 names = construct_array(elems, parameterCount, TEXTOID, -1, false, 'i');
381 return PointerGetDatum(names);
386 * check_sql_fn_retval() -- check return value of a list of sql parse trees.
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.
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.)
399 check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
409 int relnatts; /* physical number of columns in rel */
410 int rellogcols; /* # of nondeleted columns in rel */
411 int colindex; /* physical column index */
413 /* guard against empty function body; OK only if void return type */
414 if (queryTreeList == NIL)
416 if (rettype != VOIDOID)
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.")));
425 /* find the final query */
426 parse = (Query *) llast(queryTreeList);
428 cmd = parse->commandType;
429 tlist = parse->targetList;
432 * The last query must be a SELECT if and only if return type isn't
435 if (rettype == VOIDOID)
437 if (cmd == CMD_SELECT)
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.")));
446 /* by here, the function is declared to return some type */
447 if (cmd != CMD_SELECT)
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.")));
455 * Count the non-junk entries in the result targetlist.
457 tlistlen = ExecCleanTargetListLength(tlist);
459 typerelid = typeidTypeRelid(rettype);
461 if (fn_typtype == 'b' || fn_typtype == 'd')
463 /* Shouldn't have a typerelid */
464 Assert(typerelid == InvalidOid);
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.)
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.")));
478 restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
479 if (!IsBinaryCoercible(restype, rettype))
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))));
487 else if (fn_typtype == 'c')
489 /* Must have a typerelid */
490 Assert(typerelid != InvalidOid);
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.
501 restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
502 if (IsBinaryCoercible(restype, rettype))
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.
513 reln = relation_open(typerelid, AccessShareLock);
514 relnatts = reln->rd_rel->relnatts;
515 rellogcols = 0; /* we'll count nondeleted cols as we go */
518 foreach(tlistitem, tlist)
520 TargetEntry *tle = (TargetEntry *) lfirst(tlistitem);
521 Form_pg_attribute attr;
525 if (tle->resdom->resjunk)
531 if (colindex > relnatts)
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);
541 tletype = exprType((Node *) tle->expr);
542 atttype = attr->atttypid;
543 if (!IsBinaryCoercible(tletype, atttype))
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),
557 if (colindex > relnatts)
559 if (!reln->rd_att->attrs[colindex - 1]->attisdropped)
563 if (tlistlen != rellogcols)
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.")));
570 relation_close(reln, AccessShareLock);
572 else if (rettype == RECORDOID)
574 /* Shouldn't have a typerelid */
575 Assert(typerelid == InvalidOid);
578 * For RECORD return type, defer this check until we get the first
582 else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
584 /* This should already have been caught ... */
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.")));
592 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
593 errmsg("return type %s is not supported for SQL functions",
594 format_type_be(rettype))));
600 * Validator for internal functions
602 * Check that the given internal function name (the "prosrc" value) is
603 * a known builtin function.
606 fmgr_internal_validator(PG_FUNCTION_ARGS)
608 Oid funcoid = PG_GETARG_OID(0);
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.
620 tuple = SearchSysCache(PROCOID,
621 ObjectIdGetDatum(funcoid),
623 if (!HeapTupleIsValid(tuple))
624 elog(ERROR, "cache lookup failed for function %u", funcoid);
625 proc = (Form_pg_proc) GETSTRUCT(tuple);
627 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
629 elog(ERROR, "null prosrc");
630 prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
632 if (fmgr_internal_function(prosrc) == InvalidOid)
634 (errcode(ERRCODE_UNDEFINED_FUNCTION),
635 errmsg("there is no built-in function named \"%s\"",
638 ReleaseSysCache(tuple);
646 * Validator for C language functions
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.
653 fmgr_c_validator(PG_FUNCTION_ARGS)
655 Oid funcoid = PG_GETARG_OID(0);
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.
670 tuple = SearchSysCache(PROCOID,
671 ObjectIdGetDatum(funcoid),
673 if (!HeapTupleIsValid(tuple))
674 elog(ERROR, "cache lookup failed for function %u", funcoid);
675 proc = (Form_pg_proc) GETSTRUCT(tuple);
677 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
679 elog(ERROR, "null prosrc");
680 prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
682 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull);
684 elog(ERROR, "null probin");
685 probin = DatumGetCString(DirectFunctionCall1(textout, tmp));
687 (void) load_external_function(probin, prosrc, true, &libraryhandle);
688 (void) fetch_finfo_record(libraryhandle, prosrc);
690 ReleaseSysCache(tuple);
697 * Validator for SQL language functions
699 * Parse it here in order to be sure that it contains no syntax errors.
702 fmgr_sql_validator(PG_FUNCTION_ARGS)
704 Oid funcoid = PG_GETARG_OID(0);
707 List *querytree_list;
715 tuple = SearchSysCache(PROCOID,
716 ObjectIdGetDatum(funcoid),
718 if (!HeapTupleIsValid(tuple))
719 elog(ERROR, "cache lookup failed for function %u", funcoid);
720 proc = (Form_pg_proc) GETSTRUCT(tuple);
722 functyptype = get_typtype(proc->prorettype);
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)
732 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
733 errmsg("SQL functions cannot return type %s",
734 format_type_be(proc->prorettype))));
736 /* Disallow pseudotypes in arguments */
737 /* except for ANYARRAY or ANYELEMENT */
739 for (i = 0; i < proc->pronargs; i++)
741 if (get_typtype(proc->proargtypes[i]) == 'p')
743 if (proc->proargtypes[i] == ANYARRAYOID ||
744 proc->proargtypes[i] == ANYELEMENTOID)
748 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
749 errmsg("SQL functions cannot have arguments of type %s",
750 format_type_be(proc->proargtypes[i]))));
754 /* Postpone body checks if !check_function_bodies */
755 if (check_function_bodies)
757 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
759 elog(ERROR, "null prosrc");
761 prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
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.
769 * We can run the text through the raw parser though; this will at
770 * least catch silly syntactic errors.
774 querytree_list = pg_parse_and_rewrite(prosrc,
777 check_sql_fn_retval(proc->prorettype, functyptype, querytree_list);
780 querytree_list = pg_parse_query(prosrc);
783 ReleaseSysCache(tuple);