1 /*-------------------------------------------------------------------------
5 * Routines for CREATE and DROP FUNCTION commands and CREATE and DROP
8 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
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 "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
,
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
81 compute_return_type(TypeName
*returnType
, Oid languageOid
,
82 Oid
*prorettype_p
, bool *returnsSet_p
)
87 typtup
= LookupTypeName(NULL
, returnType
, NULL
);
91 if (!((Form_pg_type
) GETSTRUCT(typtup
))->typisdefined
)
93 if (languageOid
== SQLlanguageId
)
95 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION
),
96 errmsg("SQL function cannot return shell type %s",
97 TypeNameToString(returnType
))));
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
);
109 char *typnam
= TypeNameToString(returnType
);
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
120 if (languageOid
!= INTERNALlanguageId
&&
121 languageOid
!= ClanguageId
)
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
)
129 (errcode(ERRCODE_SYNTAX_ERROR
),
130 errmsg("type modifier cannot be specified for shell type \"%s\"",
133 /* Otherwise, go ahead and make a shell type */
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
,
140 aclresult
= pg_namespace_aclcheck(namespaceId
, GetUserId(),
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.
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
);
177 bool have_names
= false;
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 */
190 foreach(x
, parameters
)
192 FunctionParameter
*fp
= (FunctionParameter
*) lfirst(x
);
193 TypeName
*t
= fp
->argType
;
197 typtup
= LookupTypeName(NULL
, t
, NULL
);
200 if (!((Form_pg_type
) GETSTRUCT(typtup
))->typisdefined
)
202 /* As above, hard error if language is SQL */
203 if (languageOid
== SQLlanguageId
)
205 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION
),
206 errmsg("SQL function cannot accept shell type %s",
207 TypeNameToString(t
))));
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
);
220 (errcode(ERRCODE_UNDEFINED_OBJECT
),
221 errmsg("type %s does not exist",
222 TypeNameToString(t
))));
223 toid
= InvalidOid
; /* keep compiler quiet */
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 */
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
;
250 if (fp
->mode
== FUNC_PARAM_VARIADIC
)
253 /* validate variadic parameter type */
261 if (!OidIsValid(get_element_type(toid
)))
263 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION
),
264 errmsg("VARIADIC parameter must be an array")));
269 allTypes
[i
] = ObjectIdGetDatum(toid
);
271 paramModes
[i
] = CharGetDatum(fp
->mode
);
273 if (fp
->name
&& fp
->name
[0])
275 paramNames
[i
] = CStringGetTextDatum(fp
->name
);
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
,
292 *requiredResultType
= RECORDOID
;
293 /* otherwise we set requiredResultType correctly above */
297 *allParameterTypes
= NULL
;
298 *parameterModes
= NULL
;
303 for (i
= 0; i
< parameterCount
; i
++)
305 if (paramNames
[i
] == PointerGetDatum(NULL
))
306 paramNames
[i
] = CStringGetTextDatum("");
308 *parameterNames
= construct_array(paramNames
, parameterCount
, TEXTOID
,
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.)
325 compute_common_attribute(DefElem
*defel
,
326 DefElem
**volatility_item
,
327 DefElem
**strict_item
,
328 DefElem
**security_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)
343 goto duplicate_error
;
345 *strict_item
= defel
;
347 else if (strcmp(defel
->defname
, "security") == 0)
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)
361 goto duplicate_error
;
365 else if (strcmp(defel
->defname
, "rows") == 0)
368 goto duplicate_error
;
375 /* Recognized an option */
380 (errcode(ERRCODE_SYNTAX_ERROR
),
381 errmsg("conflicting or redundant options")));
382 return false; /* keep compiler quiet */
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
;
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.
409 update_proconfig_value(ArrayType
*a
, List
*set_items
)
413 foreach(l
, set_items
)
415 VariableSetStmt
*sstmt
= (VariableSetStmt
*) lfirst(l
);
417 Assert(IsA(sstmt
, VariableSetStmt
));
418 if (sstmt
->kind
== VAR_RESET_ALL
)
422 char *valuestr
= ExtractSetVariableArgs(sstmt
);
425 a
= GUCArrayAdd(a
, sstmt
->name
, valuestr
);
427 a
= GUCArrayDelete(a
, sstmt
->name
);
436 * Dissect the list of options assembled in gram.y into function
440 compute_attributes_sql_style(List
*options
,
445 bool *security_definer
,
446 ArrayType
**proconfig
,
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)
468 (errcode(ERRCODE_SYNTAX_ERROR
),
469 errmsg("conflicting or redundant options")));
472 else if (strcmp(defel
->defname
, "language") == 0)
476 (errcode(ERRCODE_SYNTAX_ERROR
),
477 errmsg("conflicting or redundant options")));
478 language_item
= defel
;
480 else if (compute_common_attribute(defel
,
488 /* recognized common option */
492 elog(ERROR
, "option \"%s\" not recognized",
496 /* process required items */
498 *as
= (List
*) as_item
->arg
;
502 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION
),
503 errmsg("no function body specified")));
504 *as
= NIL
; /* keep compiler quiet */
508 *language
= strVal(language_item
->arg
);
512 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION
),
513 errmsg("no language specified")));
514 *language
= NULL
; /* keep compiler quiet */
517 /* process optional items */
519 *volatility_p
= interpret_func_volatility(volatility_item
);
521 *strict_p
= intVal(strict_item
->arg
);
523 *security_definer
= intVal(security_item
->arg
);
525 *proconfig
= update_proconfig_value(NULL
, set_items
);
528 *procost
= defGetNumeric(cost_item
);
531 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
532 errmsg("COST must be positive")));
536 *prorows
= defGetNumeric(rows_item
);
539 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
540 errmsg("ROWS must be positive")));
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.
560 compute_attributes_with_style(List
*parameters
, bool *isStrict_p
, char *volatility_p
)
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
;
578 (errcode(ERRCODE_SYNTAX_ERROR
),
579 errmsg("unrecognized function attribute \"%s\" ignored",
586 * For a dynamically linked C language object, the form of the clause is
588 * AS <object file name> [, <link symbol name> ]
592 * AS <object reference, or sql code>
595 interpret_AS_clause(Oid languageOid
, const char *languageName
,
596 char *funcname
, List
*as
,
597 char **prosrc_str_p
, char **probin_str_p
)
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
;
616 *prosrc_str_p
= strVal(lsecond(as
));
617 if (strcmp(*prosrc_str_p
, "-") == 0)
618 *prosrc_str_p
= funcname
;
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)
629 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION
),
630 errmsg("only one AS item needed for language \"%s\"",
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
;
653 * Execute a CREATE FUNCTION utility statement.
656 CreateFunction(CreateFunctionStmt
*stmt
)
665 Oid languageValidator
;
669 oidvector
*parameterTypes
;
670 ArrayType
*allParameterTypes
;
671 ArrayType
*parameterModes
;
672 ArrayType
*parameterNames
;
673 Oid requiredResultType
;
677 ArrayType
*proconfig
;
680 HeapTuple languageTuple
;
681 Form_pg_language languageStruct
;
684 /* Convert list of names to a name and namespace */
685 namespaceId
= QualifiedNameGetCreationNamespace(stmt
->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 */
697 volatility
= PROVOLATILE_VOLATILE
;
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
),
715 if (!HeapTupleIsValid(languageTuple
))
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 */
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
));
737 /* if untrusted language, must be 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
751 examine_parameter_list(stmt
->parameters
, languageOid
,
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
)
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
;
778 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION
),
779 errmsg("function result type must be specified")));
780 /* Alternative possibility: default to RETURNS VOID */
781 prorettype
= VOIDOID
;
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.
797 /* SQL and PL-language functions are assumed more expensive */
798 if (languageOid
== INTERNALlanguageId
||
799 languageOid
== ClanguageId
)
809 prorows
= 0; /* dummy value if not returnsSet */
811 else if (!returnsSet
)
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
,
827 prosrc_str
, /* converted to text later */
828 probin_str
, /* converted to text later */
829 false, /* not an aggregate */
834 PointerGetDatum(allParameterTypes
),
835 PointerGetDatum(parameterModes
),
836 PointerGetDatum(parameterNames
),
837 PointerGetDatum(proconfig
),
845 * Deletes a function.
848 RemoveFunction(RemoveFuncStmt
*stmt
)
850 List
*functionName
= stmt
->name
;
851 List
*argTypes
= stmt
->args
; /* list of TypeName nodes */
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 */
864 (errmsg("function %s(%s) does not exist, skipping",
865 NameListToString(functionName
),
866 TypeNameListToString(argTypes
))));
870 tup
= SearchSysCache(PROCOID
,
871 ObjectIdGetDatum(funcOid
),
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
,
880 aclcheck_error(ACLCHECK_NOT_OWNER
, ACL_KIND_PROC
,
881 NameListToString(functionName
));
883 if (((Form_pg_proc
) GETSTRUCT(tup
))->proisagg
)
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 ... */
894 (errcode(ERRCODE_WARNING
),
895 errmsg("removing built-in function \"%s\"",
896 NameListToString(functionName
))));
899 ReleaseSysCache(tup
);
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.
918 RemoveFunctionById(Oid funcOid
)
925 * Delete the pg_proc tuple.
927 relation
= heap_open(ProcedureRelationId
, RowExclusiveLock
);
929 tup
= SearchSysCache(PROCOID
,
930 ObjectIdGetDatum(funcOid
),
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.
948 relation
= heap_open(AggregateRelationId
, RowExclusiveLock
);
950 tup
= SearchSysCache(AGGFNOID
,
951 ObjectIdGetDatum(funcOid
),
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
);
969 RenameFunction(List
*name
, List
*argtypes
, const char *newname
)
974 Form_pg_proc procForm
;
978 rel
= heap_open(ProcedureRelationId
, RowExclusiveLock
);
980 procOid
= LookupFuncNameTypeNames(name
, argtypes
, false);
982 tup
= SearchSysCacheCopy(PROCOID
,
983 ObjectIdGetDatum(procOid
),
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
)
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
),
1006 (errcode(ERRCODE_DUPLICATE_FUNCTION
),
1007 errmsg("function %s already exists in schema \"%s\"",
1008 funcname_signature_string(newname
,
1010 procForm
->proargtypes
.values
),
1011 get_namespace_name(namespaceOid
))));
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
));
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
1038 AlterFunctionOwner(List
*name
, List
*argtypes
, Oid newOwnerId
)
1044 rel
= heap_open(ProcedureRelationId
, RowExclusiveLock
);
1046 procOid
= LookupFuncNameTypeNames(name
, argtypes
, false);
1048 tup
= SearchSysCache(PROCOID
,
1049 ObjectIdGetDatum(procOid
),
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
)
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
1070 AlterFunctionOwner_oid(Oid procOid
, Oid newOwnerId
)
1075 rel
= heap_open(ProcedureRelationId
, RowExclusiveLock
);
1077 tup
= SearchSysCache(PROCOID
,
1078 ObjectIdGetDatum(procOid
),
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
);
1088 AlterFunctionOwner_internal(Relation rel
, HeapTuple tup
, Oid newOwnerId
)
1090 Form_pg_proc procForm
;
1091 AclResult aclresult
;
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
];
1114 /* Superusers can always do it */
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
,
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
,
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
1176 AlterFunction(AlterFunctionStmt
*stmt
)
1180 Form_pg_proc procForm
;
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
,
1196 tup
= SearchSysCacheCopy(PROCOID
,
1197 ObjectIdGetDatum(funcOid
),
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
)
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
,
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
);
1233 procForm
->proisstrict
= intVal(strict_item
->arg
);
1234 if (security_def_item
)
1235 procForm
->prosecdef
= intVal(security_def_item
->arg
);
1238 procForm
->procost
= defGetNumeric(cost_item
);
1239 if (procForm
->procost
<= 0)
1241 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1242 errmsg("COST must be positive")));
1246 procForm
->prorows
= defGetNumeric(rows_item
);
1247 if (procForm
->prorows
<= 0)
1249 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1250 errmsg("ROWS must be positive")));
1251 if (!procForm
->proretset
)
1253 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1254 errmsg("ROWS is not applicable when function does not return a set")));
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';
1278 repl_val
[Anum_pg_proc_proconfig
- 1] = (Datum
) 0;
1279 repl_null
[Anum_pg_proc_proconfig
- 1] = 'n';
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
);
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.
1307 SetFunctionReturnType(Oid funcOid
, Oid newRetType
)
1309 Relation pg_proc_rel
;
1311 Form_pg_proc procForm
;
1313 pg_proc_rel
= heap_open(ProcedureRelationId
, RowExclusiveLock
);
1315 tup
= SearchSysCacheCopy(PROCOID
,
1316 ObjectIdGetDatum(funcOid
),
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.
1343 SetFunctionArgType(Oid funcOid
, int argIndex
, Oid newArgType
)
1345 Relation pg_proc_rel
;
1347 Form_pg_proc procForm
;
1349 pg_proc_rel
= heap_open(ProcedureRelationId
, RowExclusiveLock
);
1351 tup
= SearchSysCacheCopy(PROCOID
,
1352 ObjectIdGetDatum(funcOid
),
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
);
1379 CreateCast(CreateCastStmt
*stmt
)
1389 Datum values
[Natts_pg_cast
];
1390 char nulls
[Natts_pg_cast
];
1391 ObjectAddress myself
,
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
)
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
)
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()))
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
;
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
,
1435 tuple
= SearchSysCache(PROCOID
,
1436 ObjectIdGetDatum(funcid
),
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)
1445 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
1446 errmsg("cast function must take one to three arguments")));
1447 if (!IsBinaryCoercible(sourcetypeid
, procstruct
->proargtypes
.values
[0]))
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
)
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
)
1457 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
1458 errmsg("third argument of cast function must be type boolean")));
1459 if (!IsBinaryCoercible(procstruct
->prorettype
, targettypeid
))
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
1470 if (procstruct
->provolatile
== PROVOLATILE_VOLATILE
)
1472 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
1473 errmsg("cast function must not be volatile")));
1475 if (procstruct
->proisagg
)
1477 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
1478 errmsg("cast function must not be an aggregate function")));
1479 if (procstruct
->proretset
)
1481 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
1482 errmsg("cast function must not return a set")));
1484 ReleaseSysCache(tuple
);
1488 funcid
= InvalidOid
;
1492 if (castmethod
== COERCION_METHOD_BINARY
)
1502 * Must be superuser to create binary-compatible casts, since
1503 * erroneous casts can easily crash the backend.
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
)
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)
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
;
1541 case COERCION_ASSIGNMENT
:
1542 castcontext
= COERCION_CODE_ASSIGNMENT
;
1544 case COERCION_EXPLICIT
:
1545 castcontext
= COERCION_CODE_EXPLICIT
;
1548 elog(ERROR
, "unrecognized CoercionContext: %d", stmt
->context
);
1549 castcontext
= 0; /* keep compiler quiet */
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
1560 tuple
= SearchSysCache(CASTSOURCETARGET
,
1561 ObjectIdGetDatum(sourcetypeid
),
1562 ObjectIdGetDatum(targettypeid
),
1564 if (HeapTupleIsValid(tuple
))
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
))));
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
);
1623 DropCast(DropCastStmt
*stmt
)
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
),
1638 if (!HeapTupleIsValid(tuple
))
1640 if (!stmt
->missing_ok
)
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
))));
1648 (errmsg("cast from type %s to type %s does not exist, skipping",
1649 format_type_be(sourcetypeid
),
1650 format_type_be(targettypeid
))));
1655 /* Permission check */
1656 if (!pg_type_ownercheck(sourcetypeid
, GetUserId())
1657 && !pg_type_ownercheck(targettypeid
, GetUserId()))
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
))));
1667 object
.classId
= CastRelationId
;
1668 object
.objectId
= HeapTupleGetOid(tuple
);
1669 object
.objectSubId
= 0;
1671 ReleaseSysCache(tuple
);
1673 performDeletion(&object
, stmt
->behavior
);
1678 DropCastById(Oid castOid
)
1681 ScanKeyData scankey
;
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.
1709 AlterFunctionNamespace(List
*name
, List
*argtypes
, bool isagg
,
1710 const char *newschema
)
1719 procRel
= heap_open(ProcedureRelationId
, RowExclusiveLock
);
1721 /* get function OID */
1723 procOid
= LookupAggNameTypeNames(name
, argtypes
, false);
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
),
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
)
1746 (errcode(ERRCODE_DUPLICATE_FUNCTION
),
1747 errmsg("function \"%s\" is already in schema \"%s\"",
1748 NameListToString(name
),
1751 /* disallow renaming into or out of temp schemas */
1752 if (isAnyTempNamespace(nspOid
) || isAnyTempNamespace(oldNspOid
))
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
)
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
),
1770 (errcode(ERRCODE_DUPLICATE_FUNCTION
),
1771 errmsg("function \"%s\" already exists in schema \"%s\"",
1772 NameStr(proc
->proname
),
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
);