1 /*-------------------------------------------------------------------------
5 * Routines for CREATE and DROP FUNCTION commands and CREATE and DROP
8 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.64 2005/07/14 21:46:29 tgl Exp $
16 * These routines take the parse tree and pick out the
17 * appropriate arguments/flags, and pass the results to the
18 * corresponding "FooDefine" routines (in src/catalog) that do
19 * the actual catalog-munging. These routines also verify permission
20 * of the user to execute the command.
23 * These things must be defined and committed in the following order:
25 * input/output, recv/send procedures
31 *-------------------------------------------------------------------------
35 #include "access/genam.h"
36 #include "access/heapam.h"
37 #include "catalog/dependency.h"
38 #include "catalog/indexing.h"
39 #include "catalog/namespace.h"
40 #include "catalog/pg_aggregate.h"
41 #include "catalog/pg_cast.h"
42 #include "catalog/pg_language.h"
43 #include "catalog/pg_proc.h"
44 #include "catalog/pg_type.h"
45 #include "commands/defrem.h"
46 #include "miscadmin.h"
47 #include "optimizer/cost.h"
48 #include "parser/parse_func.h"
49 #include "parser/parse_type.h"
50 #include "utils/acl.h"
51 #include "utils/builtins.h"
52 #include "utils/fmgroids.h"
53 #include "utils/lsyscache.h"
54 #include "utils/syscache.h"
58 * Examine the RETURNS clause of the CREATE FUNCTION statement
59 * and return information about it as *prorettype_p and *returnsSet.
61 * This is more complex than the average typename lookup because we want to
62 * allow a shell type to be used, or even created if the specified return type
63 * doesn't exist yet. (Without this, there's no way to define the I/O procs
64 * for a new type.) But SQL function creation won't cope, so error out if
65 * the target language is SQL. (We do this here, not in the SQL-function
66 * validator, so as not to produce a NOTICE and then an ERROR for the same
70 compute_return_type(TypeName *returnType, Oid languageOid,
71 Oid *prorettype_p, bool *returnsSet_p)
75 rettype = LookupTypeName(returnType);
77 if (OidIsValid(rettype))
79 if (!get_typisdefined(rettype))
81 if (languageOid == SQLlanguageId)
83 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
84 errmsg("SQL function cannot return shell type %s",
85 TypeNameToString(returnType))));
88 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
89 errmsg("return type %s is only a shell",
90 TypeNameToString(returnType))));
95 char *typnam = TypeNameToString(returnType);
101 * Only C-coded functions can be I/O functions. We enforce this
102 * restriction here mainly to prevent littering the catalogs with
103 * shell types due to simple typos in user-defined function
106 if (languageOid != INTERNALlanguageId &&
107 languageOid != ClanguageId)
109 (errcode(ERRCODE_UNDEFINED_OBJECT),
110 errmsg("type \"%s\" does not exist", typnam)));
112 /* Otherwise, go ahead and make a shell type */
114 (errcode(ERRCODE_UNDEFINED_OBJECT),
115 errmsg("type \"%s\" is not yet defined", typnam),
116 errdetail("Creating a shell type definition.")));
117 namespaceId = QualifiedNameGetCreationNamespace(returnType->names,
119 aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
121 if (aclresult != ACLCHECK_OK)
122 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
123 get_namespace_name(namespaceId));
124 rettype = TypeShellMake(typname, namespaceId);
125 Assert(OidIsValid(rettype));
128 *prorettype_p = rettype;
129 *returnsSet_p = returnType->setof;
133 * Interpret the parameter list of the CREATE FUNCTION statement.
135 * Results are stored into output parameters. parameterTypes must always
136 * be created, but the other arrays are set to NULL if not needed.
137 * requiredResultType is set to InvalidOid if there are no OUT parameters,
138 * else it is set to the OID of the implied result type.
141 examine_parameter_list(List *parameters, Oid languageOid,
142 oidvector **parameterTypes,
143 ArrayType **allParameterTypes,
144 ArrayType **parameterModes,
145 ArrayType **parameterNames,
146 Oid *requiredResultType)
148 int parameterCount = list_length(parameters);
155 bool have_names = false;
159 inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
160 allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
161 paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
162 paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
164 /* Scan the list and extract data into work arrays */
166 foreach(x, parameters)
168 FunctionParameter *fp = (FunctionParameter *) lfirst(x);
169 TypeName *t = fp->argType;
172 toid = LookupTypeName(t);
173 if (OidIsValid(toid))
175 if (!get_typisdefined(toid))
177 /* As above, hard error if language is SQL */
178 if (languageOid == SQLlanguageId)
180 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
181 errmsg("SQL function cannot accept shell type %s",
182 TypeNameToString(t))));
185 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
186 errmsg("argument type %s is only a shell",
187 TypeNameToString(t))));
193 (errcode(ERRCODE_UNDEFINED_OBJECT),
194 errmsg("type %s does not exist",
195 TypeNameToString(t))));
200 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
201 errmsg("functions cannot accept set arguments")));
203 if (fp->mode != FUNC_PARAM_OUT)
204 inTypes[inCount++] = toid;
206 if (fp->mode != FUNC_PARAM_IN)
208 if (outCount == 0) /* save first OUT param's type */
209 *requiredResultType = toid;
213 allTypes[i] = ObjectIdGetDatum(toid);
215 paramModes[i] = CharGetDatum(fp->mode);
217 if (fp->name && fp->name[0])
219 paramNames[i] = DirectFunctionCall1(textin,
220 CStringGetDatum(fp->name));
227 /* Now construct the proper outputs as needed */
228 *parameterTypes = buildoidvector(inTypes, inCount);
232 *allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,
233 sizeof(Oid), true, 'i');
234 *parameterModes = construct_array(paramModes, parameterCount, CHAROID,
237 *requiredResultType = RECORDOID;
238 /* otherwise we set requiredResultType correctly above */
242 *allParameterTypes = NULL;
243 *parameterModes = NULL;
244 *requiredResultType = InvalidOid;
249 for (i = 0; i < parameterCount; i++)
251 if (paramNames[i] == PointerGetDatum(NULL))
252 paramNames[i] = DirectFunctionCall1(textin,
253 CStringGetDatum(""));
255 *parameterNames = construct_array(paramNames, parameterCount, TEXTOID,
259 *parameterNames = NULL;
264 * Recognize one of the options that can be passed to both CREATE
265 * FUNCTION and ALTER FUNCTION and return it via one of the out
266 * parameters. Returns true if the passed option was recognized. If
267 * the out parameter we were going to assign to points to non-NULL,
268 * raise a duplicate error.
271 compute_common_attribute(DefElem *defel,
272 DefElem **volatility_item,
273 DefElem **strict_item,
274 DefElem **security_item)
276 if (strcmp(defel->defname, "volatility") == 0)
278 if (*volatility_item)
279 goto duplicate_error;
281 *volatility_item = defel;
283 else if (strcmp(defel->defname, "strict") == 0)
286 goto duplicate_error;
288 *strict_item = defel;
290 else if (strcmp(defel->defname, "security") == 0)
293 goto duplicate_error;
295 *security_item = defel;
300 /* Recognized an option */
305 (errcode(ERRCODE_SYNTAX_ERROR),
306 errmsg("conflicting or redundant options")));
307 return false; /* keep compiler quiet */
311 interpret_func_volatility(DefElem *defel)
313 char *str = strVal(defel->arg);
315 if (strcmp(str, "immutable") == 0)
316 return PROVOLATILE_IMMUTABLE;
317 else if (strcmp(str, "stable") == 0)
318 return PROVOLATILE_STABLE;
319 else if (strcmp(str, "volatile") == 0)
320 return PROVOLATILE_VOLATILE;
323 elog(ERROR, "invalid volatility \"%s\"", str);
324 return 0; /* keep compiler quiet */
329 * Dissect the list of options assembled in gram.y into function
333 compute_attributes_sql_style(List *options,
338 bool *security_definer)
341 DefElem *as_item = NULL;
342 DefElem *language_item = NULL;
343 DefElem *volatility_item = NULL;
344 DefElem *strict_item = NULL;
345 DefElem *security_item = NULL;
347 foreach(option, options)
349 DefElem *defel = (DefElem *) lfirst(option);
351 if (strcmp(defel->defname, "as") == 0)
355 (errcode(ERRCODE_SYNTAX_ERROR),
356 errmsg("conflicting or redundant options")));
359 else if (strcmp(defel->defname, "language") == 0)
363 (errcode(ERRCODE_SYNTAX_ERROR),
364 errmsg("conflicting or redundant options")));
365 language_item = defel;
367 else if (compute_common_attribute(defel,
372 /* recognized common option */
376 elog(ERROR, "option \"%s\" not recognized",
380 /* process required items */
382 *as = (List *) as_item->arg;
385 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
386 errmsg("no function body specified")));
389 *language = strVal(language_item->arg);
392 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
393 errmsg("no language specified")));
395 /* process optional items */
397 *volatility_p = interpret_func_volatility(volatility_item);
399 *strict_p = intVal(strict_item->arg);
401 *security_definer = intVal(security_item->arg);
406 * Interpret the parameters *parameters and return their contents via
407 * *isStrict_p and *volatility_p.
409 * These parameters supply optional information about a function.
410 * All have defaults if not specified. Parameters:
412 * * isStrict means the function should not be called when any NULL
413 * inputs are present; instead a NULL result value should be assumed.
415 * * volatility tells the optimizer whether the function's result can
416 * be assumed to be repeatable over multiple evaluations.
420 compute_attributes_with_style(List *parameters, bool *isStrict_p, char *volatility_p)
424 foreach(pl, parameters)
426 DefElem *param = (DefElem *) lfirst(pl);
428 if (pg_strcasecmp(param->defname, "isstrict") == 0)
429 *isStrict_p = defGetBoolean(param);
430 else if (pg_strcasecmp(param->defname, "iscachable") == 0)
432 /* obsolete spelling of isImmutable */
433 if (defGetBoolean(param))
434 *volatility_p = PROVOLATILE_IMMUTABLE;
438 (errcode(ERRCODE_SYNTAX_ERROR),
439 errmsg("unrecognized function attribute \"%s\" ignored",
446 * For a dynamically linked C language object, the form of the clause is
448 * AS <object file name> [, <link symbol name> ]
452 * AS <object reference, or sql code>
455 interpret_AS_clause(Oid languageOid, const char *languageName, List *as,
456 char **prosrc_str_p, char **probin_str_p)
460 if (languageOid == ClanguageId)
463 * For "C" language, store the file name in probin and, when
464 * given, the link symbol name in prosrc.
466 *probin_str_p = strVal(linitial(as));
467 if (list_length(as) == 1)
470 *prosrc_str_p = strVal(lsecond(as));
474 /* Everything else wants the given string in prosrc. */
475 *prosrc_str_p = strVal(linitial(as));
478 if (list_length(as) != 1)
480 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
481 errmsg("only one AS item needed for language \"%s\"",
490 * Execute a CREATE FUNCTION utility statement.
493 CreateFunction(CreateFunctionStmt *stmt)
502 Oid languageValidator;
506 oidvector *parameterTypes;
507 ArrayType *allParameterTypes;
508 ArrayType *parameterModes;
509 ArrayType *parameterNames;
510 Oid requiredResultType;
514 HeapTuple languageTuple;
515 Form_pg_language languageStruct;
518 /* Convert list of names to a name and namespace */
519 namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
522 /* Check we have creation rights in target namespace */
523 aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
524 if (aclresult != ACLCHECK_OK)
525 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
526 get_namespace_name(namespaceId));
528 /* default attributes */
531 volatility = PROVOLATILE_VOLATILE;
533 /* override attributes from explicit list */
534 compute_attributes_sql_style(stmt->options,
535 &as_clause, &language, &volatility, &isStrict, &security);
537 /* Convert language name to canonical case */
538 languageName = case_translate_language_name(language);
540 /* Look up the language and validate permissions */
541 languageTuple = SearchSysCache(LANGNAME,
542 PointerGetDatum(languageName),
544 if (!HeapTupleIsValid(languageTuple))
545 /* Add any new languages to this list to invoke the hint. */
547 (errcode(ERRCODE_UNDEFINED_OBJECT),
548 errmsg("language \"%s\" does not exist", languageName),
549 (strcmp(languageName, "plperl") == 0 ||
550 strcmp(languageName, "plperlu") == 0 ||
551 strcmp(languageName, "plpgsql") == 0 ||
552 strcmp(languageName, "plpythonu") == 0 ||
553 strcmp(languageName, "pltcl") == 0 ||
554 strcmp(languageName, "pltclu") == 0) ?
555 errhint("You need to use \"createlang\" to load the language into the database.") : 0));
557 languageOid = HeapTupleGetOid(languageTuple);
558 languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
560 if (languageStruct->lanpltrusted)
562 /* if trusted language, need USAGE privilege */
565 aclresult = pg_language_aclcheck(languageOid, GetUserId(), ACL_USAGE);
566 if (aclresult != ACLCHECK_OK)
567 aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
568 NameStr(languageStruct->lanname));
572 /* if untrusted language, must be superuser */
574 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
575 NameStr(languageStruct->lanname));
578 languageValidator = languageStruct->lanvalidator;
580 ReleaseSysCache(languageTuple);
583 * Convert remaining parameters of CREATE to form wanted by
586 examine_parameter_list(stmt->parameters, languageOid,
591 &requiredResultType);
593 if (stmt->returnType)
595 /* explicit RETURNS clause */
596 compute_return_type(stmt->returnType, languageOid,
597 &prorettype, &returnsSet);
598 if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
600 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
601 errmsg("function result type must be %s because of OUT parameters",
602 format_type_be(requiredResultType))));
604 else if (OidIsValid(requiredResultType))
606 /* default RETURNS clause from OUT parameters */
607 prorettype = requiredResultType;
613 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
614 errmsg("function result type must be specified")));
615 /* Alternative possibility: default to RETURNS VOID */
616 prorettype = VOIDOID;
620 compute_attributes_with_style(stmt->withClause, &isStrict, &volatility);
622 interpret_AS_clause(languageOid, languageName, as_clause,
623 &prosrc_str, &probin_str);
625 if (languageOid == INTERNALlanguageId)
628 * In PostgreSQL versions before 6.5, the SQL name of the created
629 * function could not be different from the internal name, and
630 * "prosrc" wasn't used. So there is code out there that does
631 * CREATE FUNCTION xyz AS '' LANGUAGE 'internal'. To preserve some
632 * modicum of backwards compatibility, accept an empty "prosrc"
633 * value as meaning the supplied SQL function name.
635 if (strlen(prosrc_str) == 0)
636 prosrc_str = funcname;
639 if (languageOid == ClanguageId)
641 /* If link symbol is specified as "-", substitute procedure name */
642 if (strcmp(prosrc_str, "-") == 0)
643 prosrc_str = funcname;
647 * And now that we have all the parameters, and know we're permitted
648 * to do so, go ahead and create the function.
650 ProcedureCreate(funcname,
657 prosrc_str, /* converted to text later */
658 probin_str, /* converted to text later */
659 false, /* not an aggregate */
664 PointerGetDatum(allParameterTypes),
665 PointerGetDatum(parameterModes),
666 PointerGetDatum(parameterNames));
672 * Deletes a function.
675 RemoveFunction(RemoveFuncStmt *stmt)
677 List *functionName = stmt->funcname;
678 List *argTypes = stmt->args; /* list of TypeName nodes */
681 ObjectAddress object;
684 * Find the function, do permissions and validity checks
686 funcOid = LookupFuncNameTypeNames(functionName, argTypes, false);
688 tup = SearchSysCache(PROCOID,
689 ObjectIdGetDatum(funcOid),
691 if (!HeapTupleIsValid(tup)) /* should not happen */
692 elog(ERROR, "cache lookup failed for function %u", funcOid);
694 /* Permission check: must own func or its namespace */
695 if (!pg_proc_ownercheck(funcOid, GetUserId()) &&
696 !pg_namespace_ownercheck(((Form_pg_proc) GETSTRUCT(tup))->pronamespace,
698 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
699 NameListToString(functionName));
701 if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
703 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
704 errmsg("\"%s\" is an aggregate function",
705 NameListToString(functionName)),
706 errhint("Use DROP AGGREGATE to drop aggregate functions.")));
708 if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId)
710 /* "Helpful" NOTICE when removing a builtin function ... */
712 (errcode(ERRCODE_WARNING),
713 errmsg("removing built-in function \"%s\"",
714 NameListToString(functionName))));
717 ReleaseSysCache(tup);
722 object.classId = ProcedureRelationId;
723 object.objectId = funcOid;
724 object.objectSubId = 0;
726 performDeletion(&object, stmt->behavior);
730 * Guts of function deletion.
732 * Note: this is also used for aggregate deletion, since the OIDs of
733 * both functions and aggregates point to pg_proc.
736 RemoveFunctionById(Oid funcOid)
743 * Delete the pg_proc tuple.
745 relation = heap_open(ProcedureRelationId, RowExclusiveLock);
747 tup = SearchSysCache(PROCOID,
748 ObjectIdGetDatum(funcOid),
750 if (!HeapTupleIsValid(tup)) /* should not happen */
751 elog(ERROR, "cache lookup failed for function %u", funcOid);
753 isagg = ((Form_pg_proc) GETSTRUCT(tup))->proisagg;
755 simple_heap_delete(relation, &tup->t_self);
757 ReleaseSysCache(tup);
759 heap_close(relation, RowExclusiveLock);
762 * If there's a pg_aggregate tuple, delete that too.
766 relation = heap_open(AggregateRelationId, RowExclusiveLock);
768 tup = SearchSysCache(AGGFNOID,
769 ObjectIdGetDatum(funcOid),
771 if (!HeapTupleIsValid(tup)) /* should not happen */
772 elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);
774 simple_heap_delete(relation, &tup->t_self);
776 ReleaseSysCache(tup);
778 heap_close(relation, RowExclusiveLock);
787 RenameFunction(List *name, List *argtypes, const char *newname)
792 Form_pg_proc procForm;
796 rel = heap_open(ProcedureRelationId, RowExclusiveLock);
798 procOid = LookupFuncNameTypeNames(name, argtypes, false);
800 tup = SearchSysCacheCopy(PROCOID,
801 ObjectIdGetDatum(procOid),
803 if (!HeapTupleIsValid(tup)) /* should not happen */
804 elog(ERROR, "cache lookup failed for function %u", procOid);
805 procForm = (Form_pg_proc) GETSTRUCT(tup);
807 if (procForm->proisagg)
809 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
810 errmsg("\"%s\" is an aggregate function",
811 NameListToString(name)),
812 errhint("Use ALTER AGGREGATE to rename aggregate functions.")));
814 namespaceOid = procForm->pronamespace;
816 /* make sure the new name doesn't exist */
817 if (SearchSysCacheExists(PROCNAMEARGSNSP,
818 CStringGetDatum(newname),
819 PointerGetDatum(&procForm->proargtypes),
820 ObjectIdGetDatum(namespaceOid),
824 (errcode(ERRCODE_DUPLICATE_FUNCTION),
825 errmsg("function %s already exists in schema \"%s\"",
826 funcname_signature_string(newname,
828 procForm->proargtypes.values),
829 get_namespace_name(namespaceOid))));
833 if (!pg_proc_ownercheck(procOid, GetUserId()))
834 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
835 NameListToString(name));
837 /* must have CREATE privilege on namespace */
838 aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
839 if (aclresult != ACLCHECK_OK)
840 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
841 get_namespace_name(namespaceOid));
844 namestrcpy(&(procForm->proname), newname);
845 simple_heap_update(rel, &tup->t_self, tup);
846 CatalogUpdateIndexes(rel, tup);
848 heap_close(rel, NoLock);
853 * Change function owner
856 AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
860 Form_pg_proc procForm;
864 rel = heap_open(ProcedureRelationId, RowExclusiveLock);
866 procOid = LookupFuncNameTypeNames(name, argtypes, false);
868 tup = SearchSysCache(PROCOID,
869 ObjectIdGetDatum(procOid),
871 if (!HeapTupleIsValid(tup)) /* should not happen */
872 elog(ERROR, "cache lookup failed for function %u", procOid);
873 procForm = (Form_pg_proc) GETSTRUCT(tup);
875 if (procForm->proisagg)
877 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
878 errmsg("\"%s\" is an aggregate function",
879 NameListToString(name)),
880 errhint("Use ALTER AGGREGATE to change owner of aggregate functions.")));
883 * If the new owner is the same as the existing owner, consider the
884 * command to have succeeded. This is for dump restoration purposes.
886 if (procForm->proowner != newOwnerId)
888 Datum repl_val[Natts_pg_proc];
889 char repl_null[Natts_pg_proc];
890 char repl_repl[Natts_pg_proc];
896 /* Otherwise, must be owner of the existing object */
897 if (!pg_proc_ownercheck(procOid,GetUserId()))
898 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
899 NameListToString(name));
901 /* Must be able to become new owner */
902 check_is_member_of_role(GetUserId(), newOwnerId);
904 /* New owner must have CREATE privilege on namespace */
905 aclresult = pg_namespace_aclcheck(procForm->pronamespace, newOwnerId,
907 if (aclresult != ACLCHECK_OK)
908 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
909 get_namespace_name(procForm->pronamespace));
911 memset(repl_null, ' ', sizeof(repl_null));
912 memset(repl_repl, ' ', sizeof(repl_repl));
914 repl_repl[Anum_pg_proc_proowner - 1] = 'r';
915 repl_val[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(newOwnerId);
918 * Determine the modified ACL for the new owner. This is only
919 * necessary when the ACL is non-null.
921 aclDatum = SysCacheGetAttr(PROCOID, tup,
926 newAcl = aclnewowner(DatumGetAclP(aclDatum),
927 procForm->proowner, newOwnerId);
928 repl_repl[Anum_pg_proc_proacl - 1] = 'r';
929 repl_val[Anum_pg_proc_proacl - 1] = PointerGetDatum(newAcl);
932 newtuple = heap_modifytuple(tup, RelationGetDescr(rel), repl_val, repl_null, repl_repl);
934 simple_heap_update(rel, &newtuple->t_self, newtuple);
935 CatalogUpdateIndexes(rel, newtuple);
937 heap_freetuple(newtuple);
939 /* Update owner dependency reference */
940 changeDependencyOnOwner(ProcedureRelationId, procOid, newOwnerId);
943 ReleaseSysCache(tup);
944 heap_close(rel, NoLock);
948 * Implements the ALTER FUNCTION utility command (except for the
949 * RENAME and OWNER clauses, which are handled as part of the generic
953 AlterFunction(AlterFunctionStmt *stmt)
957 Form_pg_proc procForm;
960 DefElem *volatility_item = NULL;
961 DefElem *strict_item = NULL;
962 DefElem *security_def_item = NULL;
964 rel = heap_open(ProcedureRelationId, RowExclusiveLock);
966 funcOid = LookupFuncNameTypeNames(stmt->func->funcname,
967 stmt->func->funcargs,
970 tup = SearchSysCacheCopy(PROCOID,
971 ObjectIdGetDatum(funcOid),
973 if (!HeapTupleIsValid(tup)) /* should not happen */
974 elog(ERROR, "cache lookup failed for function %u", funcOid);
976 procForm = (Form_pg_proc) GETSTRUCT(tup);
978 /* Permission check: must own function */
979 if (!pg_proc_ownercheck(funcOid, GetUserId()))
980 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
981 NameListToString(stmt->func->funcname));
983 if (procForm->proisagg)
985 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
986 errmsg("\"%s\" is an aggregate function",
987 NameListToString(stmt->func->funcname))));
989 /* Examine requested actions. */
990 foreach (l, stmt->actions)
992 DefElem *defel = (DefElem *) lfirst(l);
994 if (compute_common_attribute(defel,
997 &security_def_item) == false)
998 elog(ERROR, "option \"%s\" not recognized", defel->defname);
1001 if (volatility_item)
1002 procForm->provolatile = interpret_func_volatility(volatility_item);
1004 procForm->proisstrict = intVal(strict_item->arg);
1005 if (security_def_item)
1006 procForm->prosecdef = intVal(security_def_item->arg);
1009 simple_heap_update(rel, &tup->t_self, tup);
1010 CatalogUpdateIndexes(rel, tup);
1012 heap_close(rel, NoLock);
1013 heap_freetuple(tup);
1017 * SetFunctionReturnType - change declared return type of a function
1019 * This is presently only used for adjusting legacy functions that return
1020 * OPAQUE to return whatever we find their correct definition should be.
1021 * The caller should emit a suitable warning explaining what we did.
1024 SetFunctionReturnType(Oid funcOid, Oid newRetType)
1026 Relation pg_proc_rel;
1028 Form_pg_proc procForm;
1030 pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1032 tup = SearchSysCacheCopy(PROCOID,
1033 ObjectIdGetDatum(funcOid),
1035 if (!HeapTupleIsValid(tup)) /* should not happen */
1036 elog(ERROR, "cache lookup failed for function %u", funcOid);
1037 procForm = (Form_pg_proc) GETSTRUCT(tup);
1039 if (procForm->prorettype != OPAQUEOID) /* caller messed up */
1040 elog(ERROR, "function %u doesn't return OPAQUE", funcOid);
1042 /* okay to overwrite copied tuple */
1043 procForm->prorettype = newRetType;
1045 /* update the catalog and its indexes */
1046 simple_heap_update(pg_proc_rel, &tup->t_self, tup);
1048 CatalogUpdateIndexes(pg_proc_rel, tup);
1050 heap_close(pg_proc_rel, RowExclusiveLock);
1055 * SetFunctionArgType - change declared argument type of a function
1057 * As above, but change an argument's type.
1060 SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType)
1062 Relation pg_proc_rel;
1064 Form_pg_proc procForm;
1066 pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1068 tup = SearchSysCacheCopy(PROCOID,
1069 ObjectIdGetDatum(funcOid),
1071 if (!HeapTupleIsValid(tup)) /* should not happen */
1072 elog(ERROR, "cache lookup failed for function %u", funcOid);
1073 procForm = (Form_pg_proc) GETSTRUCT(tup);
1075 if (argIndex < 0 || argIndex >= procForm->pronargs ||
1076 procForm->proargtypes.values[argIndex] != OPAQUEOID)
1077 elog(ERROR, "function %u doesn't take OPAQUE", funcOid);
1079 /* okay to overwrite copied tuple */
1080 procForm->proargtypes.values[argIndex] = newArgType;
1082 /* update the catalog and its indexes */
1083 simple_heap_update(pg_proc_rel, &tup->t_self, tup);
1085 CatalogUpdateIndexes(pg_proc_rel, tup);
1087 heap_close(pg_proc_rel, RowExclusiveLock);
1096 CreateCast(CreateCastStmt *stmt)
1105 Datum values[Natts_pg_cast];
1106 char nulls[Natts_pg_cast];
1107 ObjectAddress myself,
1110 sourcetypeid = LookupTypeName(stmt->sourcetype);
1111 if (!OidIsValid(sourcetypeid))
1113 (errcode(ERRCODE_UNDEFINED_OBJECT),
1114 errmsg("source data type %s does not exist",
1115 TypeNameToString(stmt->sourcetype))));
1117 targettypeid = LookupTypeName(stmt->targettype);
1118 if (!OidIsValid(targettypeid))
1120 (errcode(ERRCODE_UNDEFINED_OBJECT),
1121 errmsg("target data type %s does not exist",
1122 TypeNameToString(stmt->targettype))));
1124 /* No shells, no pseudo-types allowed */
1125 if (!get_typisdefined(sourcetypeid))
1127 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1128 errmsg("source data type %s is only a shell",
1129 TypeNameToString(stmt->sourcetype))));
1131 if (!get_typisdefined(targettypeid))
1133 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1134 errmsg("target data type %s is only a shell",
1135 TypeNameToString(stmt->targettype))));
1137 if (get_typtype(sourcetypeid) == 'p')
1139 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1140 errmsg("source data type %s is a pseudo-type",
1141 TypeNameToString(stmt->sourcetype))));
1143 if (get_typtype(targettypeid) == 'p')
1145 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1146 errmsg("target data type %s is a pseudo-type",
1147 TypeNameToString(stmt->targettype))));
1149 /* Permission check */
1150 if (!pg_type_ownercheck(sourcetypeid, GetUserId())
1151 && !pg_type_ownercheck(targettypeid, GetUserId()))
1153 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1154 errmsg("must be owner of type %s or type %s",
1155 TypeNameToString(stmt->sourcetype),
1156 TypeNameToString(stmt->targettype))));
1158 if (stmt->func != NULL)
1160 Form_pg_proc procstruct;
1162 funcid = LookupFuncNameTypeNames(stmt->func->funcname,
1163 stmt->func->funcargs,
1166 tuple = SearchSysCache(PROCOID,
1167 ObjectIdGetDatum(funcid),
1169 if (!HeapTupleIsValid(tuple))
1170 elog(ERROR, "cache lookup failed for function %u", funcid);
1172 procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1173 nargs = procstruct->pronargs;
1174 if (nargs < 1 || nargs > 3)
1176 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1177 errmsg("cast function must take one to three arguments")));
1178 if (procstruct->proargtypes.values[0] != sourcetypeid)
1180 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1181 errmsg("argument of cast function must match source data type")));
1182 if (nargs > 1 && procstruct->proargtypes.values[1] != INT4OID)
1184 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1185 errmsg("second argument of cast function must be type integer")));
1186 if (nargs > 2 && procstruct->proargtypes.values[2] != BOOLOID)
1188 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1189 errmsg("third argument of cast function must be type boolean")));
1190 if (procstruct->prorettype != targettypeid)
1192 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1193 errmsg("return data type of cast function must match target data type")));
1196 * Restricting the volatility of a cast function may or may not be
1197 * a good idea in the abstract, but it definitely breaks many old
1198 * user-defined types. Disable this check --- tgl 2/1/03
1201 if (procstruct->provolatile == PROVOLATILE_VOLATILE)
1203 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1204 errmsg("cast function must not be volatile")));
1206 if (procstruct->proisagg)
1208 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1209 errmsg("cast function must not be an aggregate function")));
1210 if (procstruct->proretset)
1212 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1213 errmsg("cast function must not return a set")));
1215 ReleaseSysCache(tuple);
1226 /* indicates binary coercibility */
1227 funcid = InvalidOid;
1231 * Must be superuser to create binary-compatible casts, since
1232 * erroneous casts can easily crash the backend.
1236 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1237 errmsg("must be superuser to create a cast WITHOUT FUNCTION")));
1240 * Also, insist that the types match as to size, alignment, and
1241 * pass-by-value attributes; this provides at least a crude check
1242 * that they have similar representations. A pair of types that
1243 * fail this test should certainly not be equated.
1245 get_typlenbyvalalign(sourcetypeid, &typ1len, &typ1byval, &typ1align);
1246 get_typlenbyvalalign(targettypeid, &typ2len, &typ2byval, &typ2align);
1247 if (typ1len != typ2len ||
1248 typ1byval != typ2byval ||
1249 typ1align != typ2align)
1251 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1252 errmsg("source and target data types are not physically compatible")));
1256 * Allow source and target types to be same only for length coercion
1257 * functions. We assume a multi-arg function does length coercion.
1259 if (sourcetypeid == targettypeid && nargs < 2)
1261 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1262 errmsg("source data type and target data type are the same")));
1264 /* convert CoercionContext enum to char value for castcontext */
1265 switch (stmt->context)
1267 case COERCION_IMPLICIT:
1268 castcontext = COERCION_CODE_IMPLICIT;
1270 case COERCION_ASSIGNMENT:
1271 castcontext = COERCION_CODE_ASSIGNMENT;
1273 case COERCION_EXPLICIT:
1274 castcontext = COERCION_CODE_EXPLICIT;
1277 elog(ERROR, "unrecognized CoercionContext: %d", stmt->context);
1278 castcontext = 0; /* keep compiler quiet */
1282 relation = heap_open(CastRelationId, RowExclusiveLock);
1285 * Check for duplicate. This is just to give a friendly error
1286 * message, the unique index would catch it anyway (so no need to
1287 * sweat about race conditions).
1289 tuple = SearchSysCache(CASTSOURCETARGET,
1290 ObjectIdGetDatum(sourcetypeid),
1291 ObjectIdGetDatum(targettypeid),
1293 if (HeapTupleIsValid(tuple))
1295 (errcode(ERRCODE_DUPLICATE_OBJECT),
1296 errmsg("cast from type %s to type %s already exists",
1297 TypeNameToString(stmt->sourcetype),
1298 TypeNameToString(stmt->targettype))));
1301 values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
1302 values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid);
1303 values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid);
1304 values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext);
1306 MemSet(nulls, ' ', Natts_pg_cast);
1308 tuple = heap_formtuple(RelationGetDescr(relation), values, nulls);
1310 simple_heap_insert(relation, tuple);
1312 CatalogUpdateIndexes(relation, tuple);
1314 /* make dependency entries */
1315 myself.classId = CastRelationId;
1316 myself.objectId = HeapTupleGetOid(tuple);
1317 myself.objectSubId = 0;
1319 /* dependency on source type */
1320 referenced.classId = TypeRelationId;
1321 referenced.objectId = sourcetypeid;
1322 referenced.objectSubId = 0;
1323 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1325 /* dependency on target type */
1326 referenced.classId = TypeRelationId;
1327 referenced.objectId = targettypeid;
1328 referenced.objectSubId = 0;
1329 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1331 /* dependency on function */
1332 if (OidIsValid(funcid))
1334 referenced.classId = ProcedureRelationId;
1335 referenced.objectId = funcid;
1336 referenced.objectSubId = 0;
1337 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1340 heap_freetuple(tuple);
1342 heap_close(relation, RowExclusiveLock);
1351 DropCast(DropCastStmt *stmt)
1356 ObjectAddress object;
1358 sourcetypeid = LookupTypeName(stmt->sourcetype);
1359 if (!OidIsValid(sourcetypeid))
1361 (errcode(ERRCODE_UNDEFINED_OBJECT),
1362 errmsg("source data type %s does not exist",
1363 TypeNameToString(stmt->sourcetype))));
1365 targettypeid = LookupTypeName(stmt->targettype);
1366 if (!OidIsValid(targettypeid))
1368 (errcode(ERRCODE_UNDEFINED_OBJECT),
1369 errmsg("target data type %s does not exist",
1370 TypeNameToString(stmt->targettype))));
1372 tuple = SearchSysCache(CASTSOURCETARGET,
1373 ObjectIdGetDatum(sourcetypeid),
1374 ObjectIdGetDatum(targettypeid),
1376 if (!HeapTupleIsValid(tuple))
1378 (errcode(ERRCODE_UNDEFINED_OBJECT),
1379 errmsg("cast from type %s to type %s does not exist",
1380 TypeNameToString(stmt->sourcetype),
1381 TypeNameToString(stmt->targettype))));
1383 /* Permission check */
1384 if (!pg_type_ownercheck(sourcetypeid, GetUserId())
1385 && !pg_type_ownercheck(targettypeid, GetUserId()))
1387 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1388 errmsg("must be owner of type %s or type %s",
1389 TypeNameToString(stmt->sourcetype),
1390 TypeNameToString(stmt->targettype))));
1395 object.classId = CastRelationId;
1396 object.objectId = HeapTupleGetOid(tuple);
1397 object.objectSubId = 0;
1399 ReleaseSysCache(tuple);
1401 performDeletion(&object, stmt->behavior);
1406 DropCastById(Oid castOid)
1409 ScanKeyData scankey;
1413 relation = heap_open(CastRelationId, RowExclusiveLock);
1415 ScanKeyInit(&scankey,
1416 ObjectIdAttributeNumber,
1417 BTEqualStrategyNumber, F_OIDEQ,
1418 ObjectIdGetDatum(castOid));
1419 scan = systable_beginscan(relation, CastOidIndexId, true,
1420 SnapshotNow, 1, &scankey);
1422 tuple = systable_getnext(scan);
1423 if (!HeapTupleIsValid(tuple))
1424 elog(ERROR, "could not find tuple for cast %u", castOid);
1425 simple_heap_delete(relation, &tuple->t_self);
1427 systable_endscan(scan);
1428 heap_close(relation, RowExclusiveLock);