Add support for user-defined I/O conversion casts.
[PostgreSQL.git] / src / backend / commands / functioncmds.c
blob5e8e788186f93eca676da081baad25d04e812834
1 /*-------------------------------------------------------------------------
3 * functioncmds.c
5 * Routines for CREATE and DROP FUNCTION commands and CREATE and DROP
6 * CAST commands.
8 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
12 * IDENTIFICATION
13 * $PostgreSQL$
15 * DESCRIPTION
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.
22 * NOTES
23 * These things must be defined and committed in the following order:
24 * "create function":
25 * input/output, recv/send procedures
26 * "create type":
27 * type
28 * "create operator":
29 * operators
31 *-------------------------------------------------------------------------
33 #include "postgres.h"
35 #include "access/genam.h"
36 #include "access/heapam.h"
37 #include "access/sysattr.h"
38 #include "catalog/dependency.h"
39 #include "catalog/indexing.h"
40 #include "catalog/pg_aggregate.h"
41 #include "catalog/pg_cast.h"
42 #include "catalog/pg_language.h"
43 #include "catalog/pg_namespace.h"
44 #include "catalog/pg_proc.h"
45 #include "catalog/pg_proc_fn.h"
46 #include "catalog/pg_type.h"
47 #include "catalog/pg_type_fn.h"
48 #include "commands/defrem.h"
49 #include "commands/proclang.h"
50 #include "miscadmin.h"
51 #include "parser/parse_coerce.h"
52 #include "parser/parse_func.h"
53 #include "parser/parse_type.h"
54 #include "utils/acl.h"
55 #include "utils/builtins.h"
56 #include "utils/fmgroids.h"
57 #include "utils/guc.h"
58 #include "utils/lsyscache.h"
59 #include "utils/rel.h"
60 #include "utils/syscache.h"
61 #include "utils/tqual.h"
64 static void AlterFunctionOwner_internal(Relation rel, HeapTuple tup,
65 Oid newOwnerId);
69 * Examine the RETURNS clause of the CREATE FUNCTION statement
70 * and return information about it as *prorettype_p and *returnsSet.
72 * This is more complex than the average typename lookup because we want to
73 * allow a shell type to be used, or even created if the specified return type
74 * doesn't exist yet. (Without this, there's no way to define the I/O procs
75 * for a new type.) But SQL function creation won't cope, so error out if
76 * the target language is SQL. (We do this here, not in the SQL-function
77 * validator, so as not to produce a NOTICE and then an ERROR for the same
78 * condition.)
80 static void
81 compute_return_type(TypeName *returnType, Oid languageOid,
82 Oid *prorettype_p, bool *returnsSet_p)
84 Oid rettype;
85 Type typtup;
87 typtup = LookupTypeName(NULL, returnType, NULL);
89 if (typtup)
91 if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
93 if (languageOid == SQLlanguageId)
94 ereport(ERROR,
95 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
96 errmsg("SQL function cannot return shell type %s",
97 TypeNameToString(returnType))));
98 else
99 ereport(NOTICE,
100 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
101 errmsg("return type %s is only a shell",
102 TypeNameToString(returnType))));
104 rettype = typeTypeId(typtup);
105 ReleaseSysCache(typtup);
107 else
109 char *typnam = TypeNameToString(returnType);
110 Oid namespaceId;
111 AclResult aclresult;
112 char *typname;
115 * Only C-coded functions can be I/O functions. We enforce this
116 * restriction here mainly to prevent littering the catalogs with
117 * shell types due to simple typos in user-defined function
118 * definitions.
120 if (languageOid != INTERNALlanguageId &&
121 languageOid != ClanguageId)
122 ereport(ERROR,
123 (errcode(ERRCODE_UNDEFINED_OBJECT),
124 errmsg("type \"%s\" does not exist", typnam)));
126 /* Reject if there's typmod decoration, too */
127 if (returnType->typmods != NIL)
128 ereport(ERROR,
129 (errcode(ERRCODE_SYNTAX_ERROR),
130 errmsg("type modifier cannot be specified for shell type \"%s\"",
131 typnam)));
133 /* Otherwise, go ahead and make a shell type */
134 ereport(NOTICE,
135 (errcode(ERRCODE_UNDEFINED_OBJECT),
136 errmsg("type \"%s\" is not yet defined", typnam),
137 errdetail("Creating a shell type definition.")));
138 namespaceId = QualifiedNameGetCreationNamespace(returnType->names,
139 &typname);
140 aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
141 ACL_CREATE);
142 if (aclresult != ACLCHECK_OK)
143 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
144 get_namespace_name(namespaceId));
145 rettype = TypeShellMake(typname, namespaceId);
146 Assert(OidIsValid(rettype));
149 *prorettype_p = rettype;
150 *returnsSet_p = returnType->setof;
154 * Interpret the parameter list of the CREATE FUNCTION statement.
156 * Results are stored into output parameters. parameterTypes must always
157 * be created, but the other arrays are set to NULL if not needed.
158 * requiredResultType is set to InvalidOid if there are no OUT parameters,
159 * else it is set to the OID of the implied result type.
161 static void
162 examine_parameter_list(List *parameters, Oid languageOid,
163 oidvector **parameterTypes,
164 ArrayType **allParameterTypes,
165 ArrayType **parameterModes,
166 ArrayType **parameterNames,
167 Oid *requiredResultType)
169 int parameterCount = list_length(parameters);
170 Oid *inTypes;
171 int inCount = 0;
172 Datum *allTypes;
173 Datum *paramModes;
174 Datum *paramNames;
175 int outCount = 0;
176 int varCount = 0;
177 bool have_names = false;
178 ListCell *x;
179 int i;
181 *requiredResultType = InvalidOid; /* default result */
183 inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
184 allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
185 paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
186 paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
188 /* Scan the list and extract data into work arrays */
189 i = 0;
190 foreach(x, parameters)
192 FunctionParameter *fp = (FunctionParameter *) lfirst(x);
193 TypeName *t = fp->argType;
194 Oid toid;
195 Type typtup;
197 typtup = LookupTypeName(NULL, t, NULL);
198 if (typtup)
200 if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
202 /* As above, hard error if language is SQL */
203 if (languageOid == SQLlanguageId)
204 ereport(ERROR,
205 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
206 errmsg("SQL function cannot accept shell type %s",
207 TypeNameToString(t))));
208 else
209 ereport(NOTICE,
210 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
211 errmsg("argument type %s is only a shell",
212 TypeNameToString(t))));
214 toid = typeTypeId(typtup);
215 ReleaseSysCache(typtup);
217 else
219 ereport(ERROR,
220 (errcode(ERRCODE_UNDEFINED_OBJECT),
221 errmsg("type %s does not exist",
222 TypeNameToString(t))));
223 toid = InvalidOid; /* keep compiler quiet */
226 if (t->setof)
227 ereport(ERROR,
228 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
229 errmsg("functions cannot accept set arguments")));
231 /* handle input parameters */
232 if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
234 /* other input parameters can't follow a VARIADIC parameter */
235 if (varCount > 0)
236 ereport(ERROR,
237 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
238 errmsg("VARIADIC parameter must be the last input parameter")));
239 inTypes[inCount++] = toid;
242 /* handle output parameters */
243 if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
245 if (outCount == 0) /* save first output param's type */
246 *requiredResultType = toid;
247 outCount++;
250 if (fp->mode == FUNC_PARAM_VARIADIC)
252 varCount++;
253 /* validate variadic parameter type */
254 switch (toid)
256 case ANYARRAYOID:
257 case ANYOID:
258 /* okay */
259 break;
260 default:
261 if (!OidIsValid(get_element_type(toid)))
262 ereport(ERROR,
263 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
264 errmsg("VARIADIC parameter must be an array")));
265 break;
269 allTypes[i] = ObjectIdGetDatum(toid);
271 paramModes[i] = CharGetDatum(fp->mode);
273 if (fp->name && fp->name[0])
275 paramNames[i] = CStringGetTextDatum(fp->name);
276 have_names = true;
279 i++;
282 /* Now construct the proper outputs as needed */
283 *parameterTypes = buildoidvector(inTypes, inCount);
285 if (outCount > 0 || varCount > 0)
287 *allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,
288 sizeof(Oid), true, 'i');
289 *parameterModes = construct_array(paramModes, parameterCount, CHAROID,
290 1, true, 'c');
291 if (outCount > 1)
292 *requiredResultType = RECORDOID;
293 /* otherwise we set requiredResultType correctly above */
295 else
297 *allParameterTypes = NULL;
298 *parameterModes = NULL;
301 if (have_names)
303 for (i = 0; i < parameterCount; i++)
305 if (paramNames[i] == PointerGetDatum(NULL))
306 paramNames[i] = CStringGetTextDatum("");
308 *parameterNames = construct_array(paramNames, parameterCount, TEXTOID,
309 -1, false, 'i');
311 else
312 *parameterNames = NULL;
317 * Recognize one of the options that can be passed to both CREATE
318 * FUNCTION and ALTER FUNCTION and return it via one of the out
319 * parameters. Returns true if the passed option was recognized. If
320 * the out parameter we were going to assign to points to non-NULL,
321 * raise a duplicate-clause error. (We don't try to detect duplicate
322 * SET parameters though --- if you're redundant, the last one wins.)
324 static bool
325 compute_common_attribute(DefElem *defel,
326 DefElem **volatility_item,
327 DefElem **strict_item,
328 DefElem **security_item,
329 List **set_items,
330 DefElem **cost_item,
331 DefElem **rows_item)
333 if (strcmp(defel->defname, "volatility") == 0)
335 if (*volatility_item)
336 goto duplicate_error;
338 *volatility_item = defel;
340 else if (strcmp(defel->defname, "strict") == 0)
342 if (*strict_item)
343 goto duplicate_error;
345 *strict_item = defel;
347 else if (strcmp(defel->defname, "security") == 0)
349 if (*security_item)
350 goto duplicate_error;
352 *security_item = defel;
354 else if (strcmp(defel->defname, "set") == 0)
356 *set_items = lappend(*set_items, defel->arg);
358 else if (strcmp(defel->defname, "cost") == 0)
360 if (*cost_item)
361 goto duplicate_error;
363 *cost_item = defel;
365 else if (strcmp(defel->defname, "rows") == 0)
367 if (*rows_item)
368 goto duplicate_error;
370 *rows_item = defel;
372 else
373 return false;
375 /* Recognized an option */
376 return true;
378 duplicate_error:
379 ereport(ERROR,
380 (errcode(ERRCODE_SYNTAX_ERROR),
381 errmsg("conflicting or redundant options")));
382 return false; /* keep compiler quiet */
385 static char
386 interpret_func_volatility(DefElem *defel)
388 char *str = strVal(defel->arg);
390 if (strcmp(str, "immutable") == 0)
391 return PROVOLATILE_IMMUTABLE;
392 else if (strcmp(str, "stable") == 0)
393 return PROVOLATILE_STABLE;
394 else if (strcmp(str, "volatile") == 0)
395 return PROVOLATILE_VOLATILE;
396 else
398 elog(ERROR, "invalid volatility \"%s\"", str);
399 return 0; /* keep compiler quiet */
404 * Update a proconfig value according to a list of VariableSetStmt items.
406 * The input and result may be NULL to signify a null entry.
408 static ArrayType *
409 update_proconfig_value(ArrayType *a, List *set_items)
411 ListCell *l;
413 foreach(l, set_items)
415 VariableSetStmt *sstmt = (VariableSetStmt *) lfirst(l);
417 Assert(IsA(sstmt, VariableSetStmt));
418 if (sstmt->kind == VAR_RESET_ALL)
419 a = NULL;
420 else
422 char *valuestr = ExtractSetVariableArgs(sstmt);
424 if (valuestr)
425 a = GUCArrayAdd(a, sstmt->name, valuestr);
426 else /* RESET */
427 a = GUCArrayDelete(a, sstmt->name);
431 return a;
436 * Dissect the list of options assembled in gram.y into function
437 * attributes.
439 static void
440 compute_attributes_sql_style(List *options,
441 List **as,
442 char **language,
443 char *volatility_p,
444 bool *strict_p,
445 bool *security_definer,
446 ArrayType **proconfig,
447 float4 *procost,
448 float4 *prorows)
450 ListCell *option;
451 DefElem *as_item = NULL;
452 DefElem *language_item = NULL;
453 DefElem *volatility_item = NULL;
454 DefElem *strict_item = NULL;
455 DefElem *security_item = NULL;
456 List *set_items = NIL;
457 DefElem *cost_item = NULL;
458 DefElem *rows_item = NULL;
460 foreach(option, options)
462 DefElem *defel = (DefElem *) lfirst(option);
464 if (strcmp(defel->defname, "as") == 0)
466 if (as_item)
467 ereport(ERROR,
468 (errcode(ERRCODE_SYNTAX_ERROR),
469 errmsg("conflicting or redundant options")));
470 as_item = defel;
472 else if (strcmp(defel->defname, "language") == 0)
474 if (language_item)
475 ereport(ERROR,
476 (errcode(ERRCODE_SYNTAX_ERROR),
477 errmsg("conflicting or redundant options")));
478 language_item = defel;
480 else if (compute_common_attribute(defel,
481 &volatility_item,
482 &strict_item,
483 &security_item,
484 &set_items,
485 &cost_item,
486 &rows_item))
488 /* recognized common option */
489 continue;
491 else
492 elog(ERROR, "option \"%s\" not recognized",
493 defel->defname);
496 /* process required items */
497 if (as_item)
498 *as = (List *) as_item->arg;
499 else
501 ereport(ERROR,
502 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
503 errmsg("no function body specified")));
504 *as = NIL; /* keep compiler quiet */
507 if (language_item)
508 *language = strVal(language_item->arg);
509 else
511 ereport(ERROR,
512 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
513 errmsg("no language specified")));
514 *language = NULL; /* keep compiler quiet */
517 /* process optional items */
518 if (volatility_item)
519 *volatility_p = interpret_func_volatility(volatility_item);
520 if (strict_item)
521 *strict_p = intVal(strict_item->arg);
522 if (security_item)
523 *security_definer = intVal(security_item->arg);
524 if (set_items)
525 *proconfig = update_proconfig_value(NULL, set_items);
526 if (cost_item)
528 *procost = defGetNumeric(cost_item);
529 if (*procost <= 0)
530 ereport(ERROR,
531 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
532 errmsg("COST must be positive")));
534 if (rows_item)
536 *prorows = defGetNumeric(rows_item);
537 if (*prorows <= 0)
538 ereport(ERROR,
539 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
540 errmsg("ROWS must be positive")));
545 /*-------------
546 * Interpret the parameters *parameters and return their contents via
547 * *isStrict_p and *volatility_p.
549 * These parameters supply optional information about a function.
550 * All have defaults if not specified. Parameters:
552 * * isStrict means the function should not be called when any NULL
553 * inputs are present; instead a NULL result value should be assumed.
555 * * volatility tells the optimizer whether the function's result can
556 * be assumed to be repeatable over multiple evaluations.
557 *------------
559 static void
560 compute_attributes_with_style(List *parameters, bool *isStrict_p, char *volatility_p)
562 ListCell *pl;
564 foreach(pl, parameters)
566 DefElem *param = (DefElem *) lfirst(pl);
568 if (pg_strcasecmp(param->defname, "isstrict") == 0)
569 *isStrict_p = defGetBoolean(param);
570 else if (pg_strcasecmp(param->defname, "iscachable") == 0)
572 /* obsolete spelling of isImmutable */
573 if (defGetBoolean(param))
574 *volatility_p = PROVOLATILE_IMMUTABLE;
576 else
577 ereport(WARNING,
578 (errcode(ERRCODE_SYNTAX_ERROR),
579 errmsg("unrecognized function attribute \"%s\" ignored",
580 param->defname)));
586 * For a dynamically linked C language object, the form of the clause is
588 * AS <object file name> [, <link symbol name> ]
590 * In all other cases
592 * AS <object reference, or sql code>
594 static void
595 interpret_AS_clause(Oid languageOid, const char *languageName,
596 char *funcname, List *as,
597 char **prosrc_str_p, char **probin_str_p)
599 Assert(as != NIL);
601 if (languageOid == ClanguageId)
604 * For "C" language, store the file name in probin and, when given,
605 * the link symbol name in prosrc. If link symbol is omitted,
606 * substitute procedure name. We also allow link symbol to be
607 * specified as "-", since that was the habit in PG versions before
608 * 8.4, and there might be dump files out there that don't translate
609 * that back to "omitted".
611 *probin_str_p = strVal(linitial(as));
612 if (list_length(as) == 1)
613 *prosrc_str_p = funcname;
614 else
616 *prosrc_str_p = strVal(lsecond(as));
617 if (strcmp(*prosrc_str_p, "-") == 0)
618 *prosrc_str_p = funcname;
621 else
623 /* Everything else wants the given string in prosrc. */
624 *prosrc_str_p = strVal(linitial(as));
625 *probin_str_p = NULL;
627 if (list_length(as) != 1)
628 ereport(ERROR,
629 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
630 errmsg("only one AS item needed for language \"%s\"",
631 languageName)));
633 if (languageOid == INTERNALlanguageId)
636 * In PostgreSQL versions before 6.5, the SQL name of the created
637 * function could not be different from the internal name, and
638 * "prosrc" wasn't used. So there is code out there that does
639 * CREATE FUNCTION xyz AS '' LANGUAGE internal. To preserve some
640 * modicum of backwards compatibility, accept an empty "prosrc"
641 * value as meaning the supplied SQL function name.
643 if (strlen(*prosrc_str_p) == 0)
644 *prosrc_str_p = funcname;
652 * CreateFunction
653 * Execute a CREATE FUNCTION utility statement.
655 void
656 CreateFunction(CreateFunctionStmt *stmt)
658 char *probin_str;
659 char *prosrc_str;
660 Oid prorettype;
661 bool returnsSet;
662 char *language;
663 char *languageName;
664 Oid languageOid;
665 Oid languageValidator;
666 char *funcname;
667 Oid namespaceId;
668 AclResult aclresult;
669 oidvector *parameterTypes;
670 ArrayType *allParameterTypes;
671 ArrayType *parameterModes;
672 ArrayType *parameterNames;
673 Oid requiredResultType;
674 bool isStrict,
675 security;
676 char volatility;
677 ArrayType *proconfig;
678 float4 procost;
679 float4 prorows;
680 HeapTuple languageTuple;
681 Form_pg_language languageStruct;
682 List *as_clause;
684 /* Convert list of names to a name and namespace */
685 namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
686 &funcname);
688 /* Check we have creation rights in target namespace */
689 aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
690 if (aclresult != ACLCHECK_OK)
691 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
692 get_namespace_name(namespaceId));
694 /* default attributes */
695 isStrict = false;
696 security = false;
697 volatility = PROVOLATILE_VOLATILE;
698 proconfig = NULL;
699 procost = -1; /* indicates not set */
700 prorows = -1; /* indicates not set */
702 /* override attributes from explicit list */
703 compute_attributes_sql_style(stmt->options,
704 &as_clause, &language,
705 &volatility, &isStrict, &security,
706 &proconfig, &procost, &prorows);
708 /* Convert language name to canonical case */
709 languageName = case_translate_language_name(language);
711 /* Look up the language and validate permissions */
712 languageTuple = SearchSysCache(LANGNAME,
713 PointerGetDatum(languageName),
714 0, 0, 0);
715 if (!HeapTupleIsValid(languageTuple))
716 ereport(ERROR,
717 (errcode(ERRCODE_UNDEFINED_OBJECT),
718 errmsg("language \"%s\" does not exist", languageName),
719 (PLTemplateExists(languageName) ?
720 errhint("Use CREATE LANGUAGE to load the language into the database.") : 0)));
722 languageOid = HeapTupleGetOid(languageTuple);
723 languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
725 if (languageStruct->lanpltrusted)
727 /* if trusted language, need USAGE privilege */
728 AclResult aclresult;
730 aclresult = pg_language_aclcheck(languageOid, GetUserId(), ACL_USAGE);
731 if (aclresult != ACLCHECK_OK)
732 aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
733 NameStr(languageStruct->lanname));
735 else
737 /* if untrusted language, must be superuser */
738 if (!superuser())
739 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
740 NameStr(languageStruct->lanname));
743 languageValidator = languageStruct->lanvalidator;
745 ReleaseSysCache(languageTuple);
748 * Convert remaining parameters of CREATE to form wanted by
749 * ProcedureCreate.
751 examine_parameter_list(stmt->parameters, languageOid,
752 &parameterTypes,
753 &allParameterTypes,
754 &parameterModes,
755 &parameterNames,
756 &requiredResultType);
758 if (stmt->returnType)
760 /* explicit RETURNS clause */
761 compute_return_type(stmt->returnType, languageOid,
762 &prorettype, &returnsSet);
763 if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
764 ereport(ERROR,
765 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
766 errmsg("function result type must be %s because of OUT parameters",
767 format_type_be(requiredResultType))));
769 else if (OidIsValid(requiredResultType))
771 /* default RETURNS clause from OUT parameters */
772 prorettype = requiredResultType;
773 returnsSet = false;
775 else
777 ereport(ERROR,
778 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
779 errmsg("function result type must be specified")));
780 /* Alternative possibility: default to RETURNS VOID */
781 prorettype = VOIDOID;
782 returnsSet = false;
785 compute_attributes_with_style(stmt->withClause, &isStrict, &volatility);
787 interpret_AS_clause(languageOid, languageName, funcname, as_clause,
788 &prosrc_str, &probin_str);
791 * Set default values for COST and ROWS depending on other parameters;
792 * reject ROWS if it's not returnsSet. NB: pg_dump knows these default
793 * values, keep it in sync if you change them.
795 if (procost < 0)
797 /* SQL and PL-language functions are assumed more expensive */
798 if (languageOid == INTERNALlanguageId ||
799 languageOid == ClanguageId)
800 procost = 1;
801 else
802 procost = 100;
804 if (prorows < 0)
806 if (returnsSet)
807 prorows = 1000;
808 else
809 prorows = 0; /* dummy value if not returnsSet */
811 else if (!returnsSet)
812 ereport(ERROR,
813 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
814 errmsg("ROWS is not applicable when function does not return a set")));
817 * And now that we have all the parameters, and know we're permitted to do
818 * so, go ahead and create the function.
820 ProcedureCreate(funcname,
821 namespaceId,
822 stmt->replace,
823 returnsSet,
824 prorettype,
825 languageOid,
826 languageValidator,
827 prosrc_str, /* converted to text later */
828 probin_str, /* converted to text later */
829 false, /* not an aggregate */
830 security,
831 isStrict,
832 volatility,
833 parameterTypes,
834 PointerGetDatum(allParameterTypes),
835 PointerGetDatum(parameterModes),
836 PointerGetDatum(parameterNames),
837 PointerGetDatum(proconfig),
838 procost,
839 prorows);
844 * RemoveFunction
845 * Deletes a function.
847 void
848 RemoveFunction(RemoveFuncStmt *stmt)
850 List *functionName = stmt->name;
851 List *argTypes = stmt->args; /* list of TypeName nodes */
852 Oid funcOid;
853 HeapTuple tup;
854 ObjectAddress object;
857 * Find the function, do permissions and validity checks
859 funcOid = LookupFuncNameTypeNames(functionName, argTypes, stmt->missing_ok);
860 if (!OidIsValid(funcOid))
862 /* can only get here if stmt->missing_ok */
863 ereport(NOTICE,
864 (errmsg("function %s(%s) does not exist, skipping",
865 NameListToString(functionName),
866 TypeNameListToString(argTypes))));
867 return;
870 tup = SearchSysCache(PROCOID,
871 ObjectIdGetDatum(funcOid),
872 0, 0, 0);
873 if (!HeapTupleIsValid(tup)) /* should not happen */
874 elog(ERROR, "cache lookup failed for function %u", funcOid);
876 /* Permission check: must own func or its namespace */
877 if (!pg_proc_ownercheck(funcOid, GetUserId()) &&
878 !pg_namespace_ownercheck(((Form_pg_proc) GETSTRUCT(tup))->pronamespace,
879 GetUserId()))
880 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
881 NameListToString(functionName));
883 if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
884 ereport(ERROR,
885 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
886 errmsg("\"%s\" is an aggregate function",
887 NameListToString(functionName)),
888 errhint("Use DROP AGGREGATE to drop aggregate functions.")));
890 if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId)
892 /* "Helpful" NOTICE when removing a builtin function ... */
893 ereport(NOTICE,
894 (errcode(ERRCODE_WARNING),
895 errmsg("removing built-in function \"%s\"",
896 NameListToString(functionName))));
899 ReleaseSysCache(tup);
902 * Do the deletion
904 object.classId = ProcedureRelationId;
905 object.objectId = funcOid;
906 object.objectSubId = 0;
908 performDeletion(&object, stmt->behavior);
912 * Guts of function deletion.
914 * Note: this is also used for aggregate deletion, since the OIDs of
915 * both functions and aggregates point to pg_proc.
917 void
918 RemoveFunctionById(Oid funcOid)
920 Relation relation;
921 HeapTuple tup;
922 bool isagg;
925 * Delete the pg_proc tuple.
927 relation = heap_open(ProcedureRelationId, RowExclusiveLock);
929 tup = SearchSysCache(PROCOID,
930 ObjectIdGetDatum(funcOid),
931 0, 0, 0);
932 if (!HeapTupleIsValid(tup)) /* should not happen */
933 elog(ERROR, "cache lookup failed for function %u", funcOid);
935 isagg = ((Form_pg_proc) GETSTRUCT(tup))->proisagg;
937 simple_heap_delete(relation, &tup->t_self);
939 ReleaseSysCache(tup);
941 heap_close(relation, RowExclusiveLock);
944 * If there's a pg_aggregate tuple, delete that too.
946 if (isagg)
948 relation = heap_open(AggregateRelationId, RowExclusiveLock);
950 tup = SearchSysCache(AGGFNOID,
951 ObjectIdGetDatum(funcOid),
952 0, 0, 0);
953 if (!HeapTupleIsValid(tup)) /* should not happen */
954 elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);
956 simple_heap_delete(relation, &tup->t_self);
958 ReleaseSysCache(tup);
960 heap_close(relation, RowExclusiveLock);
966 * Rename function
968 void
969 RenameFunction(List *name, List *argtypes, const char *newname)
971 Oid procOid;
972 Oid namespaceOid;
973 HeapTuple tup;
974 Form_pg_proc procForm;
975 Relation rel;
976 AclResult aclresult;
978 rel = heap_open(ProcedureRelationId, RowExclusiveLock);
980 procOid = LookupFuncNameTypeNames(name, argtypes, false);
982 tup = SearchSysCacheCopy(PROCOID,
983 ObjectIdGetDatum(procOid),
984 0, 0, 0);
985 if (!HeapTupleIsValid(tup)) /* should not happen */
986 elog(ERROR, "cache lookup failed for function %u", procOid);
987 procForm = (Form_pg_proc) GETSTRUCT(tup);
989 if (procForm->proisagg)
990 ereport(ERROR,
991 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
992 errmsg("\"%s\" is an aggregate function",
993 NameListToString(name)),
994 errhint("Use ALTER AGGREGATE to rename aggregate functions.")));
996 namespaceOid = procForm->pronamespace;
998 /* make sure the new name doesn't exist */
999 if (SearchSysCacheExists(PROCNAMEARGSNSP,
1000 CStringGetDatum(newname),
1001 PointerGetDatum(&procForm->proargtypes),
1002 ObjectIdGetDatum(namespaceOid),
1005 ereport(ERROR,
1006 (errcode(ERRCODE_DUPLICATE_FUNCTION),
1007 errmsg("function %s already exists in schema \"%s\"",
1008 funcname_signature_string(newname,
1009 procForm->pronargs,
1010 procForm->proargtypes.values),
1011 get_namespace_name(namespaceOid))));
1014 /* must be owner */
1015 if (!pg_proc_ownercheck(procOid, GetUserId()))
1016 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
1017 NameListToString(name));
1019 /* must have CREATE privilege on namespace */
1020 aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
1021 if (aclresult != ACLCHECK_OK)
1022 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1023 get_namespace_name(namespaceOid));
1025 /* rename */
1026 namestrcpy(&(procForm->proname), newname);
1027 simple_heap_update(rel, &tup->t_self, tup);
1028 CatalogUpdateIndexes(rel, tup);
1030 heap_close(rel, NoLock);
1031 heap_freetuple(tup);
1035 * Change function owner by name and args
1037 void
1038 AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
1040 Relation rel;
1041 Oid procOid;
1042 HeapTuple tup;
1044 rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1046 procOid = LookupFuncNameTypeNames(name, argtypes, false);
1048 tup = SearchSysCache(PROCOID,
1049 ObjectIdGetDatum(procOid),
1050 0, 0, 0);
1051 if (!HeapTupleIsValid(tup)) /* should not happen */
1052 elog(ERROR, "cache lookup failed for function %u", procOid);
1054 if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
1055 ereport(ERROR,
1056 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1057 errmsg("\"%s\" is an aggregate function",
1058 NameListToString(name)),
1059 errhint("Use ALTER AGGREGATE to change owner of aggregate functions.")));
1061 AlterFunctionOwner_internal(rel, tup, newOwnerId);
1063 heap_close(rel, NoLock);
1067 * Change function owner by Oid
1069 void
1070 AlterFunctionOwner_oid(Oid procOid, Oid newOwnerId)
1072 Relation rel;
1073 HeapTuple tup;
1075 rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1077 tup = SearchSysCache(PROCOID,
1078 ObjectIdGetDatum(procOid),
1079 0, 0, 0);
1080 if (!HeapTupleIsValid(tup)) /* should not happen */
1081 elog(ERROR, "cache lookup failed for function %u", procOid);
1082 AlterFunctionOwner_internal(rel, tup, newOwnerId);
1084 heap_close(rel, NoLock);
1087 static void
1088 AlterFunctionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
1090 Form_pg_proc procForm;
1091 AclResult aclresult;
1092 Oid procOid;
1094 Assert(RelationGetRelid(rel) == ProcedureRelationId);
1095 Assert(tup->t_tableOid == ProcedureRelationId);
1097 procForm = (Form_pg_proc) GETSTRUCT(tup);
1098 procOid = HeapTupleGetOid(tup);
1101 * If the new owner is the same as the existing owner, consider the
1102 * command to have succeeded. This is for dump restoration purposes.
1104 if (procForm->proowner != newOwnerId)
1106 Datum repl_val[Natts_pg_proc];
1107 char repl_null[Natts_pg_proc];
1108 char repl_repl[Natts_pg_proc];
1109 Acl *newAcl;
1110 Datum aclDatum;
1111 bool isNull;
1112 HeapTuple newtuple;
1114 /* Superusers can always do it */
1115 if (!superuser())
1117 /* Otherwise, must be owner of the existing object */
1118 if (!pg_proc_ownercheck(procOid, GetUserId()))
1119 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
1120 NameStr(procForm->proname));
1122 /* Must be able to become new owner */
1123 check_is_member_of_role(GetUserId(), newOwnerId);
1125 /* New owner must have CREATE privilege on namespace */
1126 aclresult = pg_namespace_aclcheck(procForm->pronamespace,
1127 newOwnerId,
1128 ACL_CREATE);
1129 if (aclresult != ACLCHECK_OK)
1130 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1131 get_namespace_name(procForm->pronamespace));
1134 memset(repl_null, ' ', sizeof(repl_null));
1135 memset(repl_repl, ' ', sizeof(repl_repl));
1137 repl_repl[Anum_pg_proc_proowner - 1] = 'r';
1138 repl_val[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(newOwnerId);
1141 * Determine the modified ACL for the new owner. This is only
1142 * necessary when the ACL is non-null.
1144 aclDatum = SysCacheGetAttr(PROCOID, tup,
1145 Anum_pg_proc_proacl,
1146 &isNull);
1147 if (!isNull)
1149 newAcl = aclnewowner(DatumGetAclP(aclDatum),
1150 procForm->proowner, newOwnerId);
1151 repl_repl[Anum_pg_proc_proacl - 1] = 'r';
1152 repl_val[Anum_pg_proc_proacl - 1] = PointerGetDatum(newAcl);
1155 newtuple = heap_modifytuple(tup, RelationGetDescr(rel), repl_val,
1156 repl_null, repl_repl);
1158 simple_heap_update(rel, &newtuple->t_self, newtuple);
1159 CatalogUpdateIndexes(rel, newtuple);
1161 heap_freetuple(newtuple);
1163 /* Update owner dependency reference */
1164 changeDependencyOnOwner(ProcedureRelationId, procOid, newOwnerId);
1167 ReleaseSysCache(tup);
1171 * Implements the ALTER FUNCTION utility command (except for the
1172 * RENAME and OWNER clauses, which are handled as part of the generic
1173 * ALTER framework).
1175 void
1176 AlterFunction(AlterFunctionStmt *stmt)
1178 HeapTuple tup;
1179 Oid funcOid;
1180 Form_pg_proc procForm;
1181 Relation rel;
1182 ListCell *l;
1183 DefElem *volatility_item = NULL;
1184 DefElem *strict_item = NULL;
1185 DefElem *security_def_item = NULL;
1186 List *set_items = NIL;
1187 DefElem *cost_item = NULL;
1188 DefElem *rows_item = NULL;
1190 rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1192 funcOid = LookupFuncNameTypeNames(stmt->func->funcname,
1193 stmt->func->funcargs,
1194 false);
1196 tup = SearchSysCacheCopy(PROCOID,
1197 ObjectIdGetDatum(funcOid),
1198 0, 0, 0);
1199 if (!HeapTupleIsValid(tup)) /* should not happen */
1200 elog(ERROR, "cache lookup failed for function %u", funcOid);
1202 procForm = (Form_pg_proc) GETSTRUCT(tup);
1204 /* Permission check: must own function */
1205 if (!pg_proc_ownercheck(funcOid, GetUserId()))
1206 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
1207 NameListToString(stmt->func->funcname));
1209 if (procForm->proisagg)
1210 ereport(ERROR,
1211 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1212 errmsg("\"%s\" is an aggregate function",
1213 NameListToString(stmt->func->funcname))));
1215 /* Examine requested actions. */
1216 foreach(l, stmt->actions)
1218 DefElem *defel = (DefElem *) lfirst(l);
1220 if (compute_common_attribute(defel,
1221 &volatility_item,
1222 &strict_item,
1223 &security_def_item,
1224 &set_items,
1225 &cost_item,
1226 &rows_item) == false)
1227 elog(ERROR, "option \"%s\" not recognized", defel->defname);
1230 if (volatility_item)
1231 procForm->provolatile = interpret_func_volatility(volatility_item);
1232 if (strict_item)
1233 procForm->proisstrict = intVal(strict_item->arg);
1234 if (security_def_item)
1235 procForm->prosecdef = intVal(security_def_item->arg);
1236 if (cost_item)
1238 procForm->procost = defGetNumeric(cost_item);
1239 if (procForm->procost <= 0)
1240 ereport(ERROR,
1241 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1242 errmsg("COST must be positive")));
1244 if (rows_item)
1246 procForm->prorows = defGetNumeric(rows_item);
1247 if (procForm->prorows <= 0)
1248 ereport(ERROR,
1249 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1250 errmsg("ROWS must be positive")));
1251 if (!procForm->proretset)
1252 ereport(ERROR,
1253 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1254 errmsg("ROWS is not applicable when function does not return a set")));
1256 if (set_items)
1258 Datum datum;
1259 bool isnull;
1260 ArrayType *a;
1261 Datum repl_val[Natts_pg_proc];
1262 char repl_null[Natts_pg_proc];
1263 char repl_repl[Natts_pg_proc];
1265 /* extract existing proconfig setting */
1266 datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull);
1267 a = isnull ? NULL : DatumGetArrayTypeP(datum);
1269 /* update according to each SET or RESET item, left to right */
1270 a = update_proconfig_value(a, set_items);
1272 /* update the tuple */
1273 memset(repl_repl, ' ', sizeof(repl_repl));
1274 repl_repl[Anum_pg_proc_proconfig - 1] = 'r';
1276 if (a == NULL)
1278 repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
1279 repl_null[Anum_pg_proc_proconfig - 1] = 'n';
1281 else
1283 repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a);
1284 repl_null[Anum_pg_proc_proconfig - 1] = ' ';
1287 tup = heap_modifytuple(tup, RelationGetDescr(rel),
1288 repl_val, repl_null, repl_repl);
1291 /* Do the update */
1292 simple_heap_update(rel, &tup->t_self, tup);
1293 CatalogUpdateIndexes(rel, tup);
1295 heap_close(rel, NoLock);
1296 heap_freetuple(tup);
1300 * SetFunctionReturnType - change declared return type of a function
1302 * This is presently only used for adjusting legacy functions that return
1303 * OPAQUE to return whatever we find their correct definition should be.
1304 * The caller should emit a suitable warning explaining what we did.
1306 void
1307 SetFunctionReturnType(Oid funcOid, Oid newRetType)
1309 Relation pg_proc_rel;
1310 HeapTuple tup;
1311 Form_pg_proc procForm;
1313 pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1315 tup = SearchSysCacheCopy(PROCOID,
1316 ObjectIdGetDatum(funcOid),
1317 0, 0, 0);
1318 if (!HeapTupleIsValid(tup)) /* should not happen */
1319 elog(ERROR, "cache lookup failed for function %u", funcOid);
1320 procForm = (Form_pg_proc) GETSTRUCT(tup);
1322 if (procForm->prorettype != OPAQUEOID) /* caller messed up */
1323 elog(ERROR, "function %u doesn't return OPAQUE", funcOid);
1325 /* okay to overwrite copied tuple */
1326 procForm->prorettype = newRetType;
1328 /* update the catalog and its indexes */
1329 simple_heap_update(pg_proc_rel, &tup->t_self, tup);
1331 CatalogUpdateIndexes(pg_proc_rel, tup);
1333 heap_close(pg_proc_rel, RowExclusiveLock);
1338 * SetFunctionArgType - change declared argument type of a function
1340 * As above, but change an argument's type.
1342 void
1343 SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType)
1345 Relation pg_proc_rel;
1346 HeapTuple tup;
1347 Form_pg_proc procForm;
1349 pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1351 tup = SearchSysCacheCopy(PROCOID,
1352 ObjectIdGetDatum(funcOid),
1353 0, 0, 0);
1354 if (!HeapTupleIsValid(tup)) /* should not happen */
1355 elog(ERROR, "cache lookup failed for function %u", funcOid);
1356 procForm = (Form_pg_proc) GETSTRUCT(tup);
1358 if (argIndex < 0 || argIndex >= procForm->pronargs ||
1359 procForm->proargtypes.values[argIndex] != OPAQUEOID)
1360 elog(ERROR, "function %u doesn't take OPAQUE", funcOid);
1362 /* okay to overwrite copied tuple */
1363 procForm->proargtypes.values[argIndex] = newArgType;
1365 /* update the catalog and its indexes */
1366 simple_heap_update(pg_proc_rel, &tup->t_self, tup);
1368 CatalogUpdateIndexes(pg_proc_rel, tup);
1370 heap_close(pg_proc_rel, RowExclusiveLock);
1376 * CREATE CAST
1378 void
1379 CreateCast(CreateCastStmt *stmt)
1381 Oid sourcetypeid;
1382 Oid targettypeid;
1383 Oid funcid;
1384 int nargs;
1385 char castcontext;
1386 char castmethod;
1387 Relation relation;
1388 HeapTuple tuple;
1389 Datum values[Natts_pg_cast];
1390 char nulls[Natts_pg_cast];
1391 ObjectAddress myself,
1392 referenced;
1394 sourcetypeid = typenameTypeId(NULL, stmt->sourcetype, NULL);
1395 targettypeid = typenameTypeId(NULL, stmt->targettype, NULL);
1397 /* No pseudo-types allowed */
1398 if (get_typtype(sourcetypeid) == TYPTYPE_PSEUDO)
1399 ereport(ERROR,
1400 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1401 errmsg("source data type %s is a pseudo-type",
1402 TypeNameToString(stmt->sourcetype))));
1404 if (get_typtype(targettypeid) == TYPTYPE_PSEUDO)
1405 ereport(ERROR,
1406 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1407 errmsg("target data type %s is a pseudo-type",
1408 TypeNameToString(stmt->targettype))));
1410 /* Permission check */
1411 if (!pg_type_ownercheck(sourcetypeid, GetUserId())
1412 && !pg_type_ownercheck(targettypeid, GetUserId()))
1413 ereport(ERROR,
1414 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1415 errmsg("must be owner of type %s or type %s",
1416 format_type_be(sourcetypeid),
1417 format_type_be(targettypeid))));
1419 /* Detemine the cast method */
1420 if (stmt->func != NULL)
1421 castmethod = COERCION_METHOD_FUNCTION;
1422 else if(stmt->inout)
1423 castmethod = COERCION_METHOD_INOUT;
1424 else
1425 castmethod = COERCION_METHOD_BINARY;
1427 if (castmethod == COERCION_METHOD_FUNCTION)
1429 Form_pg_proc procstruct;
1431 funcid = LookupFuncNameTypeNames(stmt->func->funcname,
1432 stmt->func->funcargs,
1433 false);
1435 tuple = SearchSysCache(PROCOID,
1436 ObjectIdGetDatum(funcid),
1437 0, 0, 0);
1438 if (!HeapTupleIsValid(tuple))
1439 elog(ERROR, "cache lookup failed for function %u", funcid);
1441 procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1442 nargs = procstruct->pronargs;
1443 if (nargs < 1 || nargs > 3)
1444 ereport(ERROR,
1445 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1446 errmsg("cast function must take one to three arguments")));
1447 if (!IsBinaryCoercible(sourcetypeid, procstruct->proargtypes.values[0]))
1448 ereport(ERROR,
1449 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1450 errmsg("argument of cast function must match or be binary-coercible from source data type")));
1451 if (nargs > 1 && procstruct->proargtypes.values[1] != INT4OID)
1452 ereport(ERROR,
1453 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1454 errmsg("second argument of cast function must be type integer")));
1455 if (nargs > 2 && procstruct->proargtypes.values[2] != BOOLOID)
1456 ereport(ERROR,
1457 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1458 errmsg("third argument of cast function must be type boolean")));
1459 if (!IsBinaryCoercible(procstruct->prorettype, targettypeid))
1460 ereport(ERROR,
1461 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1462 errmsg("return data type of cast function must match or be binary-coercible to target data type")));
1465 * Restricting the volatility of a cast function may or may not be a
1466 * good idea in the abstract, but it definitely breaks many old
1467 * user-defined types. Disable this check --- tgl 2/1/03
1469 #ifdef NOT_USED
1470 if (procstruct->provolatile == PROVOLATILE_VOLATILE)
1471 ereport(ERROR,
1472 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1473 errmsg("cast function must not be volatile")));
1474 #endif
1475 if (procstruct->proisagg)
1476 ereport(ERROR,
1477 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1478 errmsg("cast function must not be an aggregate function")));
1479 if (procstruct->proretset)
1480 ereport(ERROR,
1481 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1482 errmsg("cast function must not return a set")));
1484 ReleaseSysCache(tuple);
1486 else
1488 funcid = InvalidOid;
1489 nargs = 0;
1492 if (castmethod == COERCION_METHOD_BINARY)
1494 int16 typ1len;
1495 int16 typ2len;
1496 bool typ1byval;
1497 bool typ2byval;
1498 char typ1align;
1499 char typ2align;
1502 * Must be superuser to create binary-compatible casts, since
1503 * erroneous casts can easily crash the backend.
1505 if (!superuser())
1506 ereport(ERROR,
1507 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1508 errmsg("must be superuser to create a cast WITHOUT FUNCTION")));
1511 * Also, insist that the types match as to size, alignment, and
1512 * pass-by-value attributes; this provides at least a crude check that
1513 * they have similar representations. A pair of types that fail this
1514 * test should certainly not be equated.
1516 get_typlenbyvalalign(sourcetypeid, &typ1len, &typ1byval, &typ1align);
1517 get_typlenbyvalalign(targettypeid, &typ2len, &typ2byval, &typ2align);
1518 if (typ1len != typ2len ||
1519 typ1byval != typ2byval ||
1520 typ1align != typ2align)
1521 ereport(ERROR,
1522 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1523 errmsg("source and target data types are not physically compatible")));
1527 * Allow source and target types to be same only for length coercion
1528 * functions. We assume a multi-arg function does length coercion.
1530 if (sourcetypeid == targettypeid && nargs < 2)
1531 ereport(ERROR,
1532 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1533 errmsg("source data type and target data type are the same")));
1535 /* convert CoercionContext enum to char value for castcontext */
1536 switch (stmt->context)
1538 case COERCION_IMPLICIT:
1539 castcontext = COERCION_CODE_IMPLICIT;
1540 break;
1541 case COERCION_ASSIGNMENT:
1542 castcontext = COERCION_CODE_ASSIGNMENT;
1543 break;
1544 case COERCION_EXPLICIT:
1545 castcontext = COERCION_CODE_EXPLICIT;
1546 break;
1547 default:
1548 elog(ERROR, "unrecognized CoercionContext: %d", stmt->context);
1549 castcontext = 0; /* keep compiler quiet */
1550 break;
1553 relation = heap_open(CastRelationId, RowExclusiveLock);
1556 * Check for duplicate. This is just to give a friendly error message,
1557 * the unique index would catch it anyway (so no need to sweat about race
1558 * conditions).
1560 tuple = SearchSysCache(CASTSOURCETARGET,
1561 ObjectIdGetDatum(sourcetypeid),
1562 ObjectIdGetDatum(targettypeid),
1563 0, 0);
1564 if (HeapTupleIsValid(tuple))
1565 ereport(ERROR,
1566 (errcode(ERRCODE_DUPLICATE_OBJECT),
1567 errmsg("cast from type %s to type %s already exists",
1568 format_type_be(sourcetypeid),
1569 format_type_be(targettypeid))));
1571 /* ready to go */
1572 values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
1573 values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid);
1574 values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid);
1575 values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext);
1576 values[Anum_pg_cast_castmethod - 1] = CharGetDatum(castmethod);
1578 MemSet(nulls, ' ', Natts_pg_cast);
1580 tuple = heap_formtuple(RelationGetDescr(relation), values, nulls);
1582 simple_heap_insert(relation, tuple);
1584 CatalogUpdateIndexes(relation, tuple);
1586 /* make dependency entries */
1587 myself.classId = CastRelationId;
1588 myself.objectId = HeapTupleGetOid(tuple);
1589 myself.objectSubId = 0;
1591 /* dependency on source type */
1592 referenced.classId = TypeRelationId;
1593 referenced.objectId = sourcetypeid;
1594 referenced.objectSubId = 0;
1595 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1597 /* dependency on target type */
1598 referenced.classId = TypeRelationId;
1599 referenced.objectId = targettypeid;
1600 referenced.objectSubId = 0;
1601 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1603 /* dependency on function */
1604 if (OidIsValid(funcid))
1606 referenced.classId = ProcedureRelationId;
1607 referenced.objectId = funcid;
1608 referenced.objectSubId = 0;
1609 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1612 heap_freetuple(tuple);
1614 heap_close(relation, RowExclusiveLock);
1620 * DROP CAST
1622 void
1623 DropCast(DropCastStmt *stmt)
1625 Oid sourcetypeid;
1626 Oid targettypeid;
1627 HeapTuple tuple;
1628 ObjectAddress object;
1630 /* when dropping a cast, the types must exist even if you use IF EXISTS */
1631 sourcetypeid = typenameTypeId(NULL, stmt->sourcetype, NULL);
1632 targettypeid = typenameTypeId(NULL, stmt->targettype, NULL);
1634 tuple = SearchSysCache(CASTSOURCETARGET,
1635 ObjectIdGetDatum(sourcetypeid),
1636 ObjectIdGetDatum(targettypeid),
1637 0, 0);
1638 if (!HeapTupleIsValid(tuple))
1640 if (!stmt->missing_ok)
1641 ereport(ERROR,
1642 (errcode(ERRCODE_UNDEFINED_OBJECT),
1643 errmsg("cast from type %s to type %s does not exist",
1644 format_type_be(sourcetypeid),
1645 format_type_be(targettypeid))));
1646 else
1647 ereport(NOTICE,
1648 (errmsg("cast from type %s to type %s does not exist, skipping",
1649 format_type_be(sourcetypeid),
1650 format_type_be(targettypeid))));
1652 return;
1655 /* Permission check */
1656 if (!pg_type_ownercheck(sourcetypeid, GetUserId())
1657 && !pg_type_ownercheck(targettypeid, GetUserId()))
1658 ereport(ERROR,
1659 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1660 errmsg("must be owner of type %s or type %s",
1661 format_type_be(sourcetypeid),
1662 format_type_be(targettypeid))));
1665 * Do the deletion
1667 object.classId = CastRelationId;
1668 object.objectId = HeapTupleGetOid(tuple);
1669 object.objectSubId = 0;
1671 ReleaseSysCache(tuple);
1673 performDeletion(&object, stmt->behavior);
1677 void
1678 DropCastById(Oid castOid)
1680 Relation relation;
1681 ScanKeyData scankey;
1682 SysScanDesc scan;
1683 HeapTuple tuple;
1685 relation = heap_open(CastRelationId, RowExclusiveLock);
1687 ScanKeyInit(&scankey,
1688 ObjectIdAttributeNumber,
1689 BTEqualStrategyNumber, F_OIDEQ,
1690 ObjectIdGetDatum(castOid));
1691 scan = systable_beginscan(relation, CastOidIndexId, true,
1692 SnapshotNow, 1, &scankey);
1694 tuple = systable_getnext(scan);
1695 if (!HeapTupleIsValid(tuple))
1696 elog(ERROR, "could not find tuple for cast %u", castOid);
1697 simple_heap_delete(relation, &tuple->t_self);
1699 systable_endscan(scan);
1700 heap_close(relation, RowExclusiveLock);
1704 * Execute ALTER FUNCTION/AGGREGATE SET SCHEMA
1706 * These commands are identical except for the lookup procedure, so share code.
1708 void
1709 AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
1710 const char *newschema)
1712 Oid procOid;
1713 Oid oldNspOid;
1714 Oid nspOid;
1715 HeapTuple tup;
1716 Relation procRel;
1717 Form_pg_proc proc;
1719 procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
1721 /* get function OID */
1722 if (isagg)
1723 procOid = LookupAggNameTypeNames(name, argtypes, false);
1724 else
1725 procOid = LookupFuncNameTypeNames(name, argtypes, false);
1727 /* check permissions on function */
1728 if (!pg_proc_ownercheck(procOid, GetUserId()))
1729 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
1730 NameListToString(name));
1732 tup = SearchSysCacheCopy(PROCOID,
1733 ObjectIdGetDatum(procOid),
1734 0, 0, 0);
1735 if (!HeapTupleIsValid(tup))
1736 elog(ERROR, "cache lookup failed for function %u", procOid);
1737 proc = (Form_pg_proc) GETSTRUCT(tup);
1739 oldNspOid = proc->pronamespace;
1741 /* get schema OID and check its permissions */
1742 nspOid = LookupCreationNamespace(newschema);
1744 if (oldNspOid == nspOid)
1745 ereport(ERROR,
1746 (errcode(ERRCODE_DUPLICATE_FUNCTION),
1747 errmsg("function \"%s\" is already in schema \"%s\"",
1748 NameListToString(name),
1749 newschema)));
1751 /* disallow renaming into or out of temp schemas */
1752 if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
1753 ereport(ERROR,
1754 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1755 errmsg("cannot move objects into or out of temporary schemas")));
1757 /* same for TOAST schema */
1758 if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
1759 ereport(ERROR,
1760 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1761 errmsg("cannot move objects into or out of TOAST schema")));
1763 /* check for duplicate name (more friendly than unique-index failure) */
1764 if (SearchSysCacheExists(PROCNAMEARGSNSP,
1765 CStringGetDatum(NameStr(proc->proname)),
1766 PointerGetDatum(&proc->proargtypes),
1767 ObjectIdGetDatum(nspOid),
1769 ereport(ERROR,
1770 (errcode(ERRCODE_DUPLICATE_FUNCTION),
1771 errmsg("function \"%s\" already exists in schema \"%s\"",
1772 NameStr(proc->proname),
1773 newschema)));
1775 /* OK, modify the pg_proc row */
1777 /* tup is a copy, so we can scribble directly on it */
1778 proc->pronamespace = nspOid;
1780 simple_heap_update(procRel, &tup->t_self, tup);
1781 CatalogUpdateIndexes(procRel, tup);
1783 /* Update dependency on schema */
1784 if (changeDependencyFor(ProcedureRelationId, procOid,
1785 NamespaceRelationId, oldNspOid, nspOid) != 1)
1786 elog(ERROR, "failed to change schema dependency for function \"%s\"",
1787 NameListToString(name));
1789 heap_freetuple(tup);
1791 heap_close(procRel, RowExclusiveLock);