]> granicus.if.org Git - postgresql/blob - src/backend/commands/functioncmds.c
Minor correction: cause ALTER ROLE role ROLE rolenames to behave
[postgresql] / src / backend / commands / functioncmds.c
1 /*-------------------------------------------------------------------------
2  *
3  * functioncmds.c
4  *
5  *        Routines for CREATE and DROP FUNCTION commands and CREATE and DROP
6  *        CAST commands.
7  *
8  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  *
12  * IDENTIFICATION
13  *        $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.64 2005/07/14 21:46:29 tgl Exp $
14  *
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.
21  *
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
30  *
31  *-------------------------------------------------------------------------
32  */
33 #include "postgres.h"
34
35 #include "access/genam.h"
36 #include "access/heapam.h"
37 #include "catalog/dependency.h"
38 #include "catalog/indexing.h"
39 #include "catalog/namespace.h"
40 #include "catalog/pg_aggregate.h"
41 #include "catalog/pg_cast.h"
42 #include "catalog/pg_language.h"
43 #include "catalog/pg_proc.h"
44 #include "catalog/pg_type.h"
45 #include "commands/defrem.h"
46 #include "miscadmin.h"
47 #include "optimizer/cost.h"
48 #include "parser/parse_func.h"
49 #include "parser/parse_type.h"
50 #include "utils/acl.h"
51 #include "utils/builtins.h"
52 #include "utils/fmgroids.h"
53 #include "utils/lsyscache.h"
54 #include "utils/syscache.h"
55
56
57 /*
58  *       Examine the RETURNS clause of the CREATE FUNCTION statement
59  *       and return information about it as *prorettype_p and *returnsSet.
60  *
61  * This is more complex than the average typename lookup because we want to
62  * allow a shell type to be used, or even created if the specified return type
63  * doesn't exist yet.  (Without this, there's no way to define the I/O procs
64  * for a new type.)  But SQL function creation won't cope, so error out if
65  * the target language is SQL.  (We do this here, not in the SQL-function
66  * validator, so as not to produce a NOTICE and then an ERROR for the same
67  * condition.)
68  */
69 static void
70 compute_return_type(TypeName *returnType, Oid languageOid,
71                                         Oid *prorettype_p, bool *returnsSet_p)
72 {
73         Oid                     rettype;
74
75         rettype = LookupTypeName(returnType);
76
77         if (OidIsValid(rettype))
78         {
79                 if (!get_typisdefined(rettype))
80                 {
81                         if (languageOid == SQLlanguageId)
82                                 ereport(ERROR,
83                                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
84                                            errmsg("SQL function cannot return shell type %s",
85                                                           TypeNameToString(returnType))));
86                         else
87                                 ereport(NOTICE,
88                                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
89                                                  errmsg("return type %s is only a shell",
90                                                                 TypeNameToString(returnType))));
91                 }
92         }
93         else
94         {
95                 char       *typnam = TypeNameToString(returnType);
96                 Oid                     namespaceId;
97                 AclResult       aclresult;
98                 char       *typname;
99
100                 /*
101                  * Only C-coded functions can be I/O functions.  We enforce this
102                  * restriction here mainly to prevent littering the catalogs with
103                  * shell types due to simple typos in user-defined function
104                  * definitions.
105                  */
106                 if (languageOid != INTERNALlanguageId &&
107                         languageOid != ClanguageId)
108                         ereport(ERROR,
109                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
110                                          errmsg("type \"%s\" does not exist", typnam)));
111
112                 /* Otherwise, go ahead and make a shell type */
113                 ereport(NOTICE,
114                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
115                                  errmsg("type \"%s\" is not yet defined", typnam),
116                                  errdetail("Creating a shell type definition.")));
117                 namespaceId = QualifiedNameGetCreationNamespace(returnType->names,
118                                                                                                                 &typname);
119                 aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
120                                                                                   ACL_CREATE);
121                 if (aclresult != ACLCHECK_OK)
122                         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
123                                                    get_namespace_name(namespaceId));
124                 rettype = TypeShellMake(typname, namespaceId);
125                 Assert(OidIsValid(rettype));
126         }
127
128         *prorettype_p = rettype;
129         *returnsSet_p = returnType->setof;
130 }
131
132 /*
133  * Interpret the parameter list of the CREATE FUNCTION statement.
134  *
135  * Results are stored into output parameters.  parameterTypes must always
136  * be created, but the other arrays are set to NULL if not needed.
137  * requiredResultType is set to InvalidOid if there are no OUT parameters,
138  * else it is set to the OID of the implied result type.
139  */
140 static void
141 examine_parameter_list(List *parameters, Oid languageOid,
142                                            oidvector **parameterTypes,
143                                            ArrayType **allParameterTypes,
144                                            ArrayType **parameterModes,
145                                            ArrayType **parameterNames,
146                                            Oid *requiredResultType)
147 {
148         int                     parameterCount = list_length(parameters);
149         Oid                *inTypes;
150         int                     inCount = 0;
151         Datum      *allTypes;
152         Datum      *paramModes;
153         Datum      *paramNames;
154         int                     outCount = 0;
155         bool            have_names = false;
156         ListCell   *x;
157         int                     i;
158
159         inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
160         allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
161         paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
162         paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
163
164         /* Scan the list and extract data into work arrays */
165         i = 0;
166         foreach(x, parameters)
167         {
168                 FunctionParameter *fp = (FunctionParameter *) lfirst(x);
169                 TypeName   *t = fp->argType;
170                 Oid                     toid;
171
172                 toid = LookupTypeName(t);
173                 if (OidIsValid(toid))
174                 {
175                         if (!get_typisdefined(toid))
176                         {
177                                 /* As above, hard error if language is SQL */
178                                 if (languageOid == SQLlanguageId)
179                                         ereport(ERROR,
180                                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
181                                            errmsg("SQL function cannot accept shell type %s",
182                                                           TypeNameToString(t))));
183                                 else
184                                         ereport(NOTICE,
185                                                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
186                                                          errmsg("argument type %s is only a shell",
187                                                                         TypeNameToString(t))));
188                         }
189                 }
190                 else
191                 {
192                         ereport(ERROR,
193                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
194                                          errmsg("type %s does not exist",
195                                                         TypeNameToString(t))));
196                 }
197
198                 if (t->setof)
199                         ereport(ERROR,
200                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
201                                          errmsg("functions cannot accept set arguments")));
202
203                 if (fp->mode != FUNC_PARAM_OUT)
204                         inTypes[inCount++] = toid;
205
206                 if (fp->mode != FUNC_PARAM_IN)
207                 {
208                         if (outCount == 0)      /* save first OUT param's type */
209                                 *requiredResultType = toid;
210                         outCount++;
211                 }
212
213                 allTypes[i] = ObjectIdGetDatum(toid);
214
215                 paramModes[i] = CharGetDatum(fp->mode);
216
217                 if (fp->name && fp->name[0])
218                 {
219                         paramNames[i] = DirectFunctionCall1(textin,
220                                                                                                 CStringGetDatum(fp->name));
221                         have_names = true;
222                 }
223
224                 i++;
225         }
226
227         /* Now construct the proper outputs as needed */
228         *parameterTypes = buildoidvector(inTypes, inCount);
229
230         if (outCount > 0)
231         {
232                 *allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,
233                                                                                          sizeof(Oid), true, 'i');
234                 *parameterModes = construct_array(paramModes, parameterCount, CHAROID,
235                                                                                   1, true, 'c');
236                 if (outCount > 1)
237                         *requiredResultType = RECORDOID;
238                 /* otherwise we set requiredResultType correctly above */
239         }
240         else
241         {
242                 *allParameterTypes = NULL;
243                 *parameterModes = NULL;
244                 *requiredResultType = InvalidOid;
245         }
246
247         if (have_names)
248         {
249                 for (i = 0; i < parameterCount; i++)
250                 {
251                         if (paramNames[i] == PointerGetDatum(NULL))
252                                 paramNames[i] = DirectFunctionCall1(textin,
253                                                                                                         CStringGetDatum(""));
254                 }
255                 *parameterNames = construct_array(paramNames, parameterCount, TEXTOID,
256                                                                                   -1, false, 'i');
257         }
258         else
259                 *parameterNames = NULL;
260 }
261
262
263 /*
264  * Recognize one of the options that can be passed to both CREATE
265  * FUNCTION and ALTER FUNCTION and return it via one of the out
266  * parameters. Returns true if the passed option was recognized. If
267  * the out parameter we were going to assign to points to non-NULL,
268  * raise a duplicate error.
269  */
270 static bool
271 compute_common_attribute(DefElem *defel,
272                                                  DefElem **volatility_item,
273                                                  DefElem **strict_item,
274                                                  DefElem **security_item)
275 {
276         if (strcmp(defel->defname, "volatility") == 0)
277         {
278                 if (*volatility_item)
279                         goto duplicate_error;
280
281                 *volatility_item = defel;
282         }
283         else if (strcmp(defel->defname, "strict") == 0)
284         {
285                 if (*strict_item)
286                         goto duplicate_error;
287
288                 *strict_item = defel;
289         }
290         else if (strcmp(defel->defname, "security") == 0)
291         {
292                 if (*security_item)
293                         goto duplicate_error;
294
295                 *security_item = defel;
296         }
297         else
298                 return false;
299
300         /* Recognized an option */
301         return true;
302
303 duplicate_error:
304         ereport(ERROR,
305                         (errcode(ERRCODE_SYNTAX_ERROR),
306                          errmsg("conflicting or redundant options")));
307         return false; /* keep compiler quiet */
308 }
309
310 static char
311 interpret_func_volatility(DefElem *defel)
312 {
313         char *str = strVal(defel->arg);
314
315         if (strcmp(str, "immutable") == 0)
316                 return PROVOLATILE_IMMUTABLE;
317         else if (strcmp(str, "stable") == 0)
318                 return PROVOLATILE_STABLE;
319         else if (strcmp(str, "volatile") == 0)
320                 return PROVOLATILE_VOLATILE;
321         else
322         {
323                 elog(ERROR, "invalid volatility \"%s\"", str);
324                 return 0; /* keep compiler quiet */
325         }
326 }
327
328 /*
329  * Dissect the list of options assembled in gram.y into function
330  * attributes.
331  */
332 static void
333 compute_attributes_sql_style(List *options,
334                                                          List **as,
335                                                          char **language,
336                                                          char *volatility_p,
337                                                          bool *strict_p,
338                                                          bool *security_definer)
339 {
340         ListCell   *option;
341         DefElem    *as_item = NULL;
342         DefElem    *language_item = NULL;
343         DefElem    *volatility_item = NULL;
344         DefElem    *strict_item = NULL;
345         DefElem    *security_item = NULL;
346
347         foreach(option, options)
348         {
349                 DefElem    *defel = (DefElem *) lfirst(option);
350
351                 if (strcmp(defel->defname, "as") == 0)
352                 {
353                         if (as_item)
354                                 ereport(ERROR,
355                                                 (errcode(ERRCODE_SYNTAX_ERROR),
356                                                  errmsg("conflicting or redundant options")));
357                         as_item = defel;
358                 }
359                 else if (strcmp(defel->defname, "language") == 0)
360                 {
361                         if (language_item)
362                                 ereport(ERROR,
363                                                 (errcode(ERRCODE_SYNTAX_ERROR),
364                                                  errmsg("conflicting or redundant options")));
365                         language_item = defel;
366                 }
367                 else if (compute_common_attribute(defel,
368                                                                                   &volatility_item,
369                                                                                   &strict_item,
370                                                                                   &security_item))
371                 {
372                         /* recognized common option */
373                         continue;
374                 }
375                 else
376                         elog(ERROR, "option \"%s\" not recognized",
377                                  defel->defname);
378         }
379
380         /* process required items */
381         if (as_item)
382                 *as = (List *) as_item->arg;
383         else
384                 ereport(ERROR,
385                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
386                                  errmsg("no function body specified")));
387
388         if (language_item)
389                 *language = strVal(language_item->arg);
390         else
391                 ereport(ERROR,
392                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
393                                  errmsg("no language specified")));
394
395         /* process optional items */
396         if (volatility_item)
397                 *volatility_p = interpret_func_volatility(volatility_item);
398         if (strict_item)
399                 *strict_p = intVal(strict_item->arg);
400         if (security_item)
401                 *security_definer = intVal(security_item->arg);
402 }
403
404
405 /*-------------
406  *       Interpret the parameters *parameters and return their contents via
407  *       *isStrict_p and *volatility_p.
408  *
409  *      These parameters supply optional information about a function.
410  *      All have defaults if not specified. Parameters:
411  *
412  *       * isStrict means the function should not be called when any NULL
413  *         inputs are present; instead a NULL result value should be assumed.
414  *
415  *       * volatility tells the optimizer whether the function's result can
416  *         be assumed to be repeatable over multiple evaluations.
417  *------------
418  */
419 static void
420 compute_attributes_with_style(List *parameters, bool *isStrict_p, char *volatility_p)
421 {
422         ListCell   *pl;
423
424         foreach(pl, parameters)
425         {
426                 DefElem    *param = (DefElem *) lfirst(pl);
427
428                 if (pg_strcasecmp(param->defname, "isstrict") == 0)
429                         *isStrict_p = defGetBoolean(param);
430                 else if (pg_strcasecmp(param->defname, "iscachable") == 0)
431                 {
432                         /* obsolete spelling of isImmutable */
433                         if (defGetBoolean(param))
434                                 *volatility_p = PROVOLATILE_IMMUTABLE;
435                 }
436                 else
437                         ereport(WARNING,
438                                         (errcode(ERRCODE_SYNTAX_ERROR),
439                                  errmsg("unrecognized function attribute \"%s\" ignored",
440                                                 param->defname)));
441         }
442 }
443
444
445 /*
446  * For a dynamically linked C language object, the form of the clause is
447  *
448  *         AS <object file name> [, <link symbol name> ]
449  *
450  * In all other cases
451  *
452  *         AS <object reference, or sql code>
453  */
454 static void
455 interpret_AS_clause(Oid languageOid, const char *languageName, List *as,
456                                         char **prosrc_str_p, char **probin_str_p)
457 {
458         Assert(as != NIL);
459
460         if (languageOid == ClanguageId)
461         {
462                 /*
463                  * For "C" language, store the file name in probin and, when
464                  * given, the link symbol name in prosrc.
465                  */
466                 *probin_str_p = strVal(linitial(as));
467                 if (list_length(as) == 1)
468                         *prosrc_str_p = "-";
469                 else
470                         *prosrc_str_p = strVal(lsecond(as));
471         }
472         else
473         {
474                 /* Everything else wants the given string in prosrc. */
475                 *prosrc_str_p = strVal(linitial(as));
476                 *probin_str_p = "-";
477
478                 if (list_length(as) != 1)
479                         ereport(ERROR,
480                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
481                                          errmsg("only one AS item needed for language \"%s\"",
482                                                         languageName)));
483         }
484 }
485
486
487
488 /*
489  * CreateFunction
490  *       Execute a CREATE FUNCTION utility statement.
491  */
492 void
493 CreateFunction(CreateFunctionStmt *stmt)
494 {
495         char       *probin_str;
496         char       *prosrc_str;
497         Oid                     prorettype;
498         bool            returnsSet;
499         char       *language;
500         char       *languageName;
501         Oid                     languageOid;
502         Oid                     languageValidator;
503         char       *funcname;
504         Oid                     namespaceId;
505         AclResult       aclresult;
506         oidvector  *parameterTypes;
507         ArrayType  *allParameterTypes;
508         ArrayType  *parameterModes;
509         ArrayType  *parameterNames;
510         Oid                     requiredResultType;
511         bool            isStrict,
512                                 security;
513         char            volatility;
514         HeapTuple       languageTuple;
515         Form_pg_language languageStruct;
516         List       *as_clause;
517
518         /* Convert list of names to a name and namespace */
519         namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
520                                                                                                         &funcname);
521
522         /* Check we have creation rights in target namespace */
523         aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
524         if (aclresult != ACLCHECK_OK)
525                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
526                                            get_namespace_name(namespaceId));
527
528         /* default attributes */
529         isStrict = false;
530         security = false;
531         volatility = PROVOLATILE_VOLATILE;
532
533         /* override attributes from explicit list */
534         compute_attributes_sql_style(stmt->options,
535                            &as_clause, &language, &volatility, &isStrict, &security);
536
537         /* Convert language name to canonical case */
538         languageName = case_translate_language_name(language);
539
540         /* Look up the language and validate permissions */
541         languageTuple = SearchSysCache(LANGNAME,
542                                                                    PointerGetDatum(languageName),
543                                                                    0, 0, 0);
544         if (!HeapTupleIsValid(languageTuple))
545                 /* Add any new languages to this list to invoke the hint. */
546                 ereport(ERROR,
547                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
548                                  errmsg("language \"%s\" does not exist", languageName),
549                                  (strcmp(languageName, "plperl") == 0 ||
550                                   strcmp(languageName, "plperlu") == 0 ||
551                                   strcmp(languageName, "plpgsql") == 0 ||
552                                   strcmp(languageName, "plpythonu") == 0 ||
553                                   strcmp(languageName, "pltcl") == 0 ||
554                                   strcmp(languageName, "pltclu") == 0) ?
555                                  errhint("You need to use \"createlang\" to load the language into the database.") : 0));
556
557         languageOid = HeapTupleGetOid(languageTuple);
558         languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
559
560         if (languageStruct->lanpltrusted)
561         {
562                 /* if trusted language, need USAGE privilege */
563                 AclResult       aclresult;
564
565                 aclresult = pg_language_aclcheck(languageOid, GetUserId(), ACL_USAGE);
566                 if (aclresult != ACLCHECK_OK)
567                         aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
568                                                    NameStr(languageStruct->lanname));
569         }
570         else
571         {
572                 /* if untrusted language, must be superuser */
573                 if (!superuser())
574                         aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
575                                                    NameStr(languageStruct->lanname));
576         }
577
578         languageValidator = languageStruct->lanvalidator;
579
580         ReleaseSysCache(languageTuple);
581
582         /*
583          * Convert remaining parameters of CREATE to form wanted by
584          * ProcedureCreate.
585          */
586         examine_parameter_list(stmt->parameters, languageOid,
587                                                    &parameterTypes,
588                                                    &allParameterTypes,
589                                                    &parameterModes,
590                                                    &parameterNames,
591                                                    &requiredResultType);
592
593         if (stmt->returnType)
594         {
595                 /* explicit RETURNS clause */
596                 compute_return_type(stmt->returnType, languageOid,
597                                                         &prorettype, &returnsSet);
598                 if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
599                         ereport(ERROR,
600                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
601                                          errmsg("function result type must be %s because of OUT parameters",
602                                                         format_type_be(requiredResultType))));
603         }
604         else if (OidIsValid(requiredResultType))
605         {
606                 /* default RETURNS clause from OUT parameters */
607                 prorettype = requiredResultType;
608                 returnsSet = false;
609         }
610         else
611         {
612                 ereport(ERROR,
613                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
614                                  errmsg("function result type must be specified")));
615                 /* Alternative possibility: default to RETURNS VOID */
616                 prorettype = VOIDOID;
617                 returnsSet = false;
618         }
619
620         compute_attributes_with_style(stmt->withClause, &isStrict, &volatility);
621
622         interpret_AS_clause(languageOid, languageName, as_clause,
623                                                 &prosrc_str, &probin_str);
624
625         if (languageOid == INTERNALlanguageId)
626         {
627                 /*
628                  * In PostgreSQL versions before 6.5, the SQL name of the created
629                  * function could not be different from the internal name, and
630                  * "prosrc" wasn't used.  So there is code out there that does
631                  * CREATE FUNCTION xyz AS '' LANGUAGE 'internal'. To preserve some
632                  * modicum of backwards compatibility, accept an empty "prosrc"
633                  * value as meaning the supplied SQL function name.
634                  */
635                 if (strlen(prosrc_str) == 0)
636                         prosrc_str = funcname;
637         }
638
639         if (languageOid == ClanguageId)
640         {
641                 /* If link symbol is specified as "-", substitute procedure name */
642                 if (strcmp(prosrc_str, "-") == 0)
643                         prosrc_str = funcname;
644         }
645
646         /*
647          * And now that we have all the parameters, and know we're permitted
648          * to do so, go ahead and create the function.
649          */
650         ProcedureCreate(funcname,
651                                         namespaceId,
652                                         stmt->replace,
653                                         returnsSet,
654                                         prorettype,
655                                         languageOid,
656                                         languageValidator,
657                                         prosrc_str, /* converted to text later */
658                                         probin_str, /* converted to text later */
659                                         false,          /* not an aggregate */
660                                         security,
661                                         isStrict,
662                                         volatility,
663                                         parameterTypes,
664                                         PointerGetDatum(allParameterTypes),
665                                         PointerGetDatum(parameterModes),
666                                         PointerGetDatum(parameterNames));
667 }
668
669
670 /*
671  * RemoveFunction
672  *              Deletes a function.
673  */
674 void
675 RemoveFunction(RemoveFuncStmt *stmt)
676 {
677         List       *functionName = stmt->funcname;
678         List       *argTypes = stmt->args;      /* list of TypeName nodes */
679         Oid                     funcOid;
680         HeapTuple       tup;
681         ObjectAddress object;
682
683         /*
684          * Find the function, do permissions and validity checks
685          */
686         funcOid = LookupFuncNameTypeNames(functionName, argTypes, false);
687
688         tup = SearchSysCache(PROCOID,
689                                                  ObjectIdGetDatum(funcOid),
690                                                  0, 0, 0);
691         if (!HeapTupleIsValid(tup)) /* should not happen */
692                 elog(ERROR, "cache lookup failed for function %u", funcOid);
693
694         /* Permission check: must own func or its namespace */
695         if (!pg_proc_ownercheck(funcOid, GetUserId()) &&
696                 !pg_namespace_ownercheck(((Form_pg_proc) GETSTRUCT(tup))->pronamespace,
697                                                                  GetUserId()))
698                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
699                                            NameListToString(functionName));
700
701         if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
702                 ereport(ERROR,
703                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
704                                  errmsg("\"%s\" is an aggregate function",
705                                                 NameListToString(functionName)),
706                         errhint("Use DROP AGGREGATE to drop aggregate functions.")));
707
708         if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId)
709         {
710                 /* "Helpful" NOTICE when removing a builtin function ... */
711                 ereport(NOTICE,
712                                 (errcode(ERRCODE_WARNING),
713                                  errmsg("removing built-in function \"%s\"",
714                                                 NameListToString(functionName))));
715         }
716
717         ReleaseSysCache(tup);
718
719         /*
720          * Do the deletion
721          */
722         object.classId = ProcedureRelationId;
723         object.objectId = funcOid;
724         object.objectSubId = 0;
725
726         performDeletion(&object, stmt->behavior);
727 }
728
729 /*
730  * Guts of function deletion.
731  *
732  * Note: this is also used for aggregate deletion, since the OIDs of
733  * both functions and aggregates point to pg_proc.
734  */
735 void
736 RemoveFunctionById(Oid funcOid)
737 {
738         Relation        relation;
739         HeapTuple       tup;
740         bool            isagg;
741
742         /*
743          * Delete the pg_proc tuple.
744          */
745         relation = heap_open(ProcedureRelationId, RowExclusiveLock);
746
747         tup = SearchSysCache(PROCOID,
748                                                  ObjectIdGetDatum(funcOid),
749                                                  0, 0, 0);
750         if (!HeapTupleIsValid(tup)) /* should not happen */
751                 elog(ERROR, "cache lookup failed for function %u", funcOid);
752
753         isagg = ((Form_pg_proc) GETSTRUCT(tup))->proisagg;
754
755         simple_heap_delete(relation, &tup->t_self);
756
757         ReleaseSysCache(tup);
758
759         heap_close(relation, RowExclusiveLock);
760
761         /*
762          * If there's a pg_aggregate tuple, delete that too.
763          */
764         if (isagg)
765         {
766                 relation = heap_open(AggregateRelationId, RowExclusiveLock);
767
768                 tup = SearchSysCache(AGGFNOID,
769                                                          ObjectIdGetDatum(funcOid),
770                                                          0, 0, 0);
771                 if (!HeapTupleIsValid(tup))             /* should not happen */
772                         elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);
773
774                 simple_heap_delete(relation, &tup->t_self);
775
776                 ReleaseSysCache(tup);
777
778                 heap_close(relation, RowExclusiveLock);
779         }
780 }
781
782
783 /*
784  * Rename function
785  */
786 void
787 RenameFunction(List *name, List *argtypes, const char *newname)
788 {
789         Oid                     procOid;
790         Oid                     namespaceOid;
791         HeapTuple       tup;
792         Form_pg_proc procForm;
793         Relation        rel;
794         AclResult       aclresult;
795
796         rel = heap_open(ProcedureRelationId, RowExclusiveLock);
797
798         procOid = LookupFuncNameTypeNames(name, argtypes, false);
799
800         tup = SearchSysCacheCopy(PROCOID,
801                                                          ObjectIdGetDatum(procOid),
802                                                          0, 0, 0);
803         if (!HeapTupleIsValid(tup)) /* should not happen */
804                 elog(ERROR, "cache lookup failed for function %u", procOid);
805         procForm = (Form_pg_proc) GETSTRUCT(tup);
806
807         if (procForm->proisagg)
808                 ereport(ERROR,
809                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
810                                  errmsg("\"%s\" is an aggregate function",
811                                                 NameListToString(name)),
812                  errhint("Use ALTER AGGREGATE to rename aggregate functions.")));
813
814         namespaceOid = procForm->pronamespace;
815
816         /* make sure the new name doesn't exist */
817         if (SearchSysCacheExists(PROCNAMEARGSNSP,
818                                                          CStringGetDatum(newname),
819                                                          PointerGetDatum(&procForm->proargtypes),
820                                                          ObjectIdGetDatum(namespaceOid),
821                                                          0))
822         {
823                 ereport(ERROR,
824                                 (errcode(ERRCODE_DUPLICATE_FUNCTION),
825                                  errmsg("function %s already exists in schema \"%s\"",
826                                                 funcname_signature_string(newname,
827                                                                                                   procForm->pronargs,
828                                                                                                   procForm->proargtypes.values),
829                                                 get_namespace_name(namespaceOid))));
830         }
831
832         /* must be owner */
833         if (!pg_proc_ownercheck(procOid, GetUserId()))
834                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
835                                            NameListToString(name));
836
837         /* must have CREATE privilege on namespace */
838         aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
839         if (aclresult != ACLCHECK_OK)
840                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
841                                            get_namespace_name(namespaceOid));
842
843         /* rename */
844         namestrcpy(&(procForm->proname), newname);
845         simple_heap_update(rel, &tup->t_self, tup);
846         CatalogUpdateIndexes(rel, tup);
847
848         heap_close(rel, NoLock);
849         heap_freetuple(tup);
850 }
851
852 /*
853  * Change function owner
854  */
855 void
856 AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
857 {
858         Oid                     procOid;
859         HeapTuple       tup;
860         Form_pg_proc procForm;
861         Relation        rel;
862         AclResult       aclresult;
863
864         rel = heap_open(ProcedureRelationId, RowExclusiveLock);
865
866         procOid = LookupFuncNameTypeNames(name, argtypes, false);
867
868         tup = SearchSysCache(PROCOID,
869                                                  ObjectIdGetDatum(procOid),
870                                                  0, 0, 0);
871         if (!HeapTupleIsValid(tup)) /* should not happen */
872                 elog(ERROR, "cache lookup failed for function %u", procOid);
873         procForm = (Form_pg_proc) GETSTRUCT(tup);
874
875         if (procForm->proisagg)
876                 ereport(ERROR,
877                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
878                                  errmsg("\"%s\" is an aggregate function",
879                                                 NameListToString(name)),
880                                  errhint("Use ALTER AGGREGATE to change owner of aggregate functions.")));
881
882         /*
883          * If the new owner is the same as the existing owner, consider the
884          * command to have succeeded.  This is for dump restoration purposes.
885          */
886         if (procForm->proowner != newOwnerId)
887         {
888                 Datum           repl_val[Natts_pg_proc];
889                 char            repl_null[Natts_pg_proc];
890                 char            repl_repl[Natts_pg_proc];
891                 Acl                *newAcl;
892                 Datum           aclDatum;
893                 bool            isNull;
894                 HeapTuple       newtuple;
895
896                 /* Otherwise, must be owner of the existing object */
897                 if (!pg_proc_ownercheck(procOid,GetUserId()))
898                         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
899                                                    NameListToString(name));
900
901                 /* Must be able to become new owner */
902                 check_is_member_of_role(GetUserId(), newOwnerId);
903
904                 /* New owner must have CREATE privilege on namespace */
905                 aclresult = pg_namespace_aclcheck(procForm->pronamespace, newOwnerId,
906                                                                                   ACL_CREATE);
907                 if (aclresult != ACLCHECK_OK)
908                         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
909                                         get_namespace_name(procForm->pronamespace));
910
911                 memset(repl_null, ' ', sizeof(repl_null));
912                 memset(repl_repl, ' ', sizeof(repl_repl));
913
914                 repl_repl[Anum_pg_proc_proowner - 1] = 'r';
915                 repl_val[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(newOwnerId);
916
917                 /*
918                  * Determine the modified ACL for the new owner.  This is only
919                  * necessary when the ACL is non-null.
920                  */
921                 aclDatum = SysCacheGetAttr(PROCOID, tup,
922                                                                    Anum_pg_proc_proacl,
923                                                                    &isNull);
924                 if (!isNull)
925                 {
926                         newAcl = aclnewowner(DatumGetAclP(aclDatum),
927                                                                  procForm->proowner, newOwnerId);
928                         repl_repl[Anum_pg_proc_proacl - 1] = 'r';
929                         repl_val[Anum_pg_proc_proacl - 1] = PointerGetDatum(newAcl);
930                 }
931
932                 newtuple = heap_modifytuple(tup, RelationGetDescr(rel), repl_val, repl_null, repl_repl);
933
934                 simple_heap_update(rel, &newtuple->t_self, newtuple);
935                 CatalogUpdateIndexes(rel, newtuple);
936
937                 heap_freetuple(newtuple);
938
939                 /* Update owner dependency reference */
940                 changeDependencyOnOwner(ProcedureRelationId, procOid, newOwnerId);
941         }
942
943         ReleaseSysCache(tup);
944         heap_close(rel, NoLock);
945 }
946
947 /*
948  * Implements the ALTER FUNCTION utility command (except for the
949  * RENAME and OWNER clauses, which are handled as part of the generic
950  * ALTER framework).
951  */
952 void
953 AlterFunction(AlterFunctionStmt *stmt)
954 {
955         HeapTuple tup;
956         Oid funcOid;
957         Form_pg_proc procForm;
958         Relation rel;
959         ListCell *l;
960         DefElem *volatility_item = NULL;
961         DefElem *strict_item = NULL;
962         DefElem *security_def_item = NULL;
963
964         rel = heap_open(ProcedureRelationId, RowExclusiveLock);
965
966         funcOid = LookupFuncNameTypeNames(stmt->func->funcname,
967                                                                           stmt->func->funcargs,
968                                                                           false);
969
970         tup = SearchSysCacheCopy(PROCOID,
971                                                          ObjectIdGetDatum(funcOid),
972                                                          0, 0, 0);
973         if (!HeapTupleIsValid(tup)) /* should not happen */
974                 elog(ERROR, "cache lookup failed for function %u", funcOid);
975
976         procForm = (Form_pg_proc) GETSTRUCT(tup);
977
978         /* Permission check: must own function */
979         if (!pg_proc_ownercheck(funcOid, GetUserId()))
980                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
981                                            NameListToString(stmt->func->funcname));
982
983         if (procForm->proisagg)
984                 ereport(ERROR,
985                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
986                                  errmsg("\"%s\" is an aggregate function",
987                                                 NameListToString(stmt->func->funcname))));
988
989         /* Examine requested actions. */
990         foreach (l, stmt->actions)
991         {
992                 DefElem *defel = (DefElem *) lfirst(l);
993
994                 if (compute_common_attribute(defel,
995                                                                          &volatility_item,
996                                                                          &strict_item,
997                                                                          &security_def_item) == false)
998                         elog(ERROR, "option \"%s\" not recognized", defel->defname);
999         }
1000
1001         if (volatility_item)
1002                 procForm->provolatile = interpret_func_volatility(volatility_item);
1003         if (strict_item)
1004                 procForm->proisstrict = intVal(strict_item->arg);
1005         if (security_def_item)
1006                 procForm->prosecdef = intVal(security_def_item->arg);
1007
1008         /* Do the update */
1009         simple_heap_update(rel, &tup->t_self, tup);
1010         CatalogUpdateIndexes(rel, tup);
1011
1012         heap_close(rel, NoLock);
1013         heap_freetuple(tup);
1014 }
1015
1016 /*
1017  * SetFunctionReturnType - change declared return type of a function
1018  *
1019  * This is presently only used for adjusting legacy functions that return
1020  * OPAQUE to return whatever we find their correct definition should be.
1021  * The caller should emit a suitable warning explaining what we did.
1022  */
1023 void
1024 SetFunctionReturnType(Oid funcOid, Oid newRetType)
1025 {
1026         Relation        pg_proc_rel;
1027         HeapTuple       tup;
1028         Form_pg_proc procForm;
1029
1030         pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1031
1032         tup = SearchSysCacheCopy(PROCOID,
1033                                                          ObjectIdGetDatum(funcOid),
1034                                                          0, 0, 0);
1035         if (!HeapTupleIsValid(tup)) /* should not happen */
1036                 elog(ERROR, "cache lookup failed for function %u", funcOid);
1037         procForm = (Form_pg_proc) GETSTRUCT(tup);
1038
1039         if (procForm->prorettype != OPAQUEOID)          /* caller messed up */
1040                 elog(ERROR, "function %u doesn't return OPAQUE", funcOid);
1041
1042         /* okay to overwrite copied tuple */
1043         procForm->prorettype = newRetType;
1044
1045         /* update the catalog and its indexes */
1046         simple_heap_update(pg_proc_rel, &tup->t_self, tup);
1047
1048         CatalogUpdateIndexes(pg_proc_rel, tup);
1049
1050         heap_close(pg_proc_rel, RowExclusiveLock);
1051 }
1052
1053
1054 /*
1055  * SetFunctionArgType - change declared argument type of a function
1056  *
1057  * As above, but change an argument's type.
1058  */
1059 void
1060 SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType)
1061 {
1062         Relation        pg_proc_rel;
1063         HeapTuple       tup;
1064         Form_pg_proc procForm;
1065
1066         pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1067
1068         tup = SearchSysCacheCopy(PROCOID,
1069                                                          ObjectIdGetDatum(funcOid),
1070                                                          0, 0, 0);
1071         if (!HeapTupleIsValid(tup)) /* should not happen */
1072                 elog(ERROR, "cache lookup failed for function %u", funcOid);
1073         procForm = (Form_pg_proc) GETSTRUCT(tup);
1074
1075         if (argIndex < 0 || argIndex >= procForm->pronargs ||
1076                 procForm->proargtypes.values[argIndex] != OPAQUEOID)
1077                 elog(ERROR, "function %u doesn't take OPAQUE", funcOid);
1078
1079         /* okay to overwrite copied tuple */
1080         procForm->proargtypes.values[argIndex] = newArgType;
1081
1082         /* update the catalog and its indexes */
1083         simple_heap_update(pg_proc_rel, &tup->t_self, tup);
1084
1085         CatalogUpdateIndexes(pg_proc_rel, tup);
1086
1087         heap_close(pg_proc_rel, RowExclusiveLock);
1088 }
1089
1090
1091
1092 /*
1093  * CREATE CAST
1094  */
1095 void
1096 CreateCast(CreateCastStmt *stmt)
1097 {
1098         Oid                     sourcetypeid;
1099         Oid                     targettypeid;
1100         Oid                     funcid;
1101         int                     nargs;
1102         char            castcontext;
1103         Relation        relation;
1104         HeapTuple       tuple;
1105         Datum           values[Natts_pg_cast];
1106         char            nulls[Natts_pg_cast];
1107         ObjectAddress myself,
1108                                 referenced;
1109
1110         sourcetypeid = LookupTypeName(stmt->sourcetype);
1111         if (!OidIsValid(sourcetypeid))
1112                 ereport(ERROR,
1113                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1114                                  errmsg("source data type %s does not exist",
1115                                                 TypeNameToString(stmt->sourcetype))));
1116
1117         targettypeid = LookupTypeName(stmt->targettype);
1118         if (!OidIsValid(targettypeid))
1119                 ereport(ERROR,
1120                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1121                                  errmsg("target data type %s does not exist",
1122                                                 TypeNameToString(stmt->targettype))));
1123
1124         /* No shells, no pseudo-types allowed */
1125         if (!get_typisdefined(sourcetypeid))
1126                 ereport(ERROR,
1127                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1128                                  errmsg("source data type %s is only a shell",
1129                                                 TypeNameToString(stmt->sourcetype))));
1130
1131         if (!get_typisdefined(targettypeid))
1132                 ereport(ERROR,
1133                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1134                                  errmsg("target data type %s is only a shell",
1135                                                 TypeNameToString(stmt->targettype))));
1136
1137         if (get_typtype(sourcetypeid) == 'p')
1138                 ereport(ERROR,
1139                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1140                                  errmsg("source data type %s is a pseudo-type",
1141                                                 TypeNameToString(stmt->sourcetype))));
1142
1143         if (get_typtype(targettypeid) == 'p')
1144                 ereport(ERROR,
1145                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1146                                  errmsg("target data type %s is a pseudo-type",
1147                                                 TypeNameToString(stmt->targettype))));
1148
1149         /* Permission check */
1150         if (!pg_type_ownercheck(sourcetypeid, GetUserId())
1151                 && !pg_type_ownercheck(targettypeid, GetUserId()))
1152                 ereport(ERROR,
1153                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1154                                  errmsg("must be owner of type %s or type %s",
1155                                                 TypeNameToString(stmt->sourcetype),
1156                                                 TypeNameToString(stmt->targettype))));
1157
1158         if (stmt->func != NULL)
1159         {
1160                 Form_pg_proc procstruct;
1161
1162                 funcid = LookupFuncNameTypeNames(stmt->func->funcname,
1163                                                                                  stmt->func->funcargs,
1164                                                                                  false);
1165
1166                 tuple = SearchSysCache(PROCOID,
1167                                                            ObjectIdGetDatum(funcid),
1168                                                            0, 0, 0);
1169                 if (!HeapTupleIsValid(tuple))
1170                         elog(ERROR, "cache lookup failed for function %u", funcid);
1171
1172                 procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1173                 nargs = procstruct->pronargs;
1174                 if (nargs < 1 || nargs > 3)
1175                         ereport(ERROR,
1176                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1177                           errmsg("cast function must take one to three arguments")));
1178                 if (procstruct->proargtypes.values[0] != sourcetypeid)
1179                         ereport(ERROR,
1180                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1181                                          errmsg("argument of cast function must match source data type")));
1182                 if (nargs > 1 && procstruct->proargtypes.values[1] != INT4OID)
1183                         ereport(ERROR,
1184                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1185                                          errmsg("second argument of cast function must be type integer")));
1186                 if (nargs > 2 && procstruct->proargtypes.values[2] != BOOLOID)
1187                         ereport(ERROR,
1188                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1189                                          errmsg("third argument of cast function must be type boolean")));
1190                 if (procstruct->prorettype != targettypeid)
1191                         ereport(ERROR,
1192                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1193                                          errmsg("return data type of cast function must match target data type")));
1194
1195                 /*
1196                  * Restricting the volatility of a cast function may or may not be
1197                  * a good idea in the abstract, but it definitely breaks many old
1198                  * user-defined types.  Disable this check --- tgl 2/1/03
1199                  */
1200 #ifdef NOT_USED
1201                 if (procstruct->provolatile == PROVOLATILE_VOLATILE)
1202                         ereport(ERROR,
1203                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1204                                          errmsg("cast function must not be volatile")));
1205 #endif
1206                 if (procstruct->proisagg)
1207                         ereport(ERROR,
1208                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1209                          errmsg("cast function must not be an aggregate function")));
1210                 if (procstruct->proretset)
1211                         ereport(ERROR,
1212                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1213                                          errmsg("cast function must not return a set")));
1214
1215                 ReleaseSysCache(tuple);
1216         }
1217         else
1218         {
1219                 int16           typ1len;
1220                 int16           typ2len;
1221                 bool            typ1byval;
1222                 bool            typ2byval;
1223                 char            typ1align;
1224                 char            typ2align;
1225
1226                 /* indicates binary coercibility */
1227                 funcid = InvalidOid;
1228                 nargs = 0;
1229
1230                 /*
1231                  * Must be superuser to create binary-compatible casts, since
1232                  * erroneous casts can easily crash the backend.
1233                  */
1234                 if (!superuser())
1235                         ereport(ERROR,
1236                                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1237                                          errmsg("must be superuser to create a cast WITHOUT FUNCTION")));
1238
1239                 /*
1240                  * Also, insist that the types match as to size, alignment, and
1241                  * pass-by-value attributes; this provides at least a crude check
1242                  * that they have similar representations.      A pair of types that
1243                  * fail this test should certainly not be equated.
1244                  */
1245                 get_typlenbyvalalign(sourcetypeid, &typ1len, &typ1byval, &typ1align);
1246                 get_typlenbyvalalign(targettypeid, &typ2len, &typ2byval, &typ2align);
1247                 if (typ1len != typ2len ||
1248                         typ1byval != typ2byval ||
1249                         typ1align != typ2align)
1250                         ereport(ERROR,
1251                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1252                                          errmsg("source and target data types are not physically compatible")));
1253         }
1254
1255         /*
1256          * Allow source and target types to be same only for length coercion
1257          * functions.  We assume a multi-arg function does length coercion.
1258          */
1259         if (sourcetypeid == targettypeid && nargs < 2)
1260                 ereport(ERROR,
1261                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1262                   errmsg("source data type and target data type are the same")));
1263
1264         /* convert CoercionContext enum to char value for castcontext */
1265         switch (stmt->context)
1266         {
1267                 case COERCION_IMPLICIT:
1268                         castcontext = COERCION_CODE_IMPLICIT;
1269                         break;
1270                 case COERCION_ASSIGNMENT:
1271                         castcontext = COERCION_CODE_ASSIGNMENT;
1272                         break;
1273                 case COERCION_EXPLICIT:
1274                         castcontext = COERCION_CODE_EXPLICIT;
1275                         break;
1276                 default:
1277                         elog(ERROR, "unrecognized CoercionContext: %d", stmt->context);
1278                         castcontext = 0;        /* keep compiler quiet */
1279                         break;
1280         }
1281
1282         relation = heap_open(CastRelationId, RowExclusiveLock);
1283
1284         /*
1285          * Check for duplicate.  This is just to give a friendly error
1286          * message, the unique index would catch it anyway (so no need to
1287          * sweat about race conditions).
1288          */
1289         tuple = SearchSysCache(CASTSOURCETARGET,
1290                                                    ObjectIdGetDatum(sourcetypeid),
1291                                                    ObjectIdGetDatum(targettypeid),
1292                                                    0, 0);
1293         if (HeapTupleIsValid(tuple))
1294                 ereport(ERROR,
1295                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
1296                                  errmsg("cast from type %s to type %s already exists",
1297                                                 TypeNameToString(stmt->sourcetype),
1298                                                 TypeNameToString(stmt->targettype))));
1299
1300         /* ready to go */
1301         values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
1302         values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid);
1303         values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid);
1304         values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext);
1305
1306         MemSet(nulls, ' ', Natts_pg_cast);
1307
1308         tuple = heap_formtuple(RelationGetDescr(relation), values, nulls);
1309
1310         simple_heap_insert(relation, tuple);
1311
1312         CatalogUpdateIndexes(relation, tuple);
1313
1314         /* make dependency entries */
1315         myself.classId = CastRelationId;
1316         myself.objectId = HeapTupleGetOid(tuple);
1317         myself.objectSubId = 0;
1318
1319         /* dependency on source type */
1320         referenced.classId = TypeRelationId;
1321         referenced.objectId = sourcetypeid;
1322         referenced.objectSubId = 0;
1323         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1324
1325         /* dependency on target type */
1326         referenced.classId = TypeRelationId;
1327         referenced.objectId = targettypeid;
1328         referenced.objectSubId = 0;
1329         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1330
1331         /* dependency on function */
1332         if (OidIsValid(funcid))
1333         {
1334                 referenced.classId = ProcedureRelationId;
1335                 referenced.objectId = funcid;
1336                 referenced.objectSubId = 0;
1337                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1338         }
1339
1340         heap_freetuple(tuple);
1341
1342         heap_close(relation, RowExclusiveLock);
1343 }
1344
1345
1346
1347 /*
1348  * DROP CAST
1349  */
1350 void
1351 DropCast(DropCastStmt *stmt)
1352 {
1353         Oid                     sourcetypeid;
1354         Oid                     targettypeid;
1355         HeapTuple       tuple;
1356         ObjectAddress object;
1357
1358         sourcetypeid = LookupTypeName(stmt->sourcetype);
1359         if (!OidIsValid(sourcetypeid))
1360                 ereport(ERROR,
1361                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1362                                  errmsg("source data type %s does not exist",
1363                                                 TypeNameToString(stmt->sourcetype))));
1364
1365         targettypeid = LookupTypeName(stmt->targettype);
1366         if (!OidIsValid(targettypeid))
1367                 ereport(ERROR,
1368                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1369                                  errmsg("target data type %s does not exist",
1370                                                 TypeNameToString(stmt->targettype))));
1371
1372         tuple = SearchSysCache(CASTSOURCETARGET,
1373                                                    ObjectIdGetDatum(sourcetypeid),
1374                                                    ObjectIdGetDatum(targettypeid),
1375                                                    0, 0);
1376         if (!HeapTupleIsValid(tuple))
1377                 ereport(ERROR,
1378                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1379                                  errmsg("cast from type %s to type %s does not exist",
1380                                                 TypeNameToString(stmt->sourcetype),
1381                                                 TypeNameToString(stmt->targettype))));
1382
1383         /* Permission check */
1384         if (!pg_type_ownercheck(sourcetypeid, GetUserId())
1385                 && !pg_type_ownercheck(targettypeid, GetUserId()))
1386                 ereport(ERROR,
1387                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1388                                  errmsg("must be owner of type %s or type %s",
1389                                                 TypeNameToString(stmt->sourcetype),
1390                                                 TypeNameToString(stmt->targettype))));
1391
1392         /*
1393          * Do the deletion
1394          */
1395         object.classId = CastRelationId;
1396         object.objectId = HeapTupleGetOid(tuple);
1397         object.objectSubId = 0;
1398
1399         ReleaseSysCache(tuple);
1400
1401         performDeletion(&object, stmt->behavior);
1402 }
1403
1404
1405 void
1406 DropCastById(Oid castOid)
1407 {
1408         Relation        relation;
1409         ScanKeyData scankey;
1410         SysScanDesc scan;
1411         HeapTuple       tuple;
1412
1413         relation = heap_open(CastRelationId, RowExclusiveLock);
1414
1415         ScanKeyInit(&scankey,
1416                                 ObjectIdAttributeNumber,
1417                                 BTEqualStrategyNumber, F_OIDEQ,
1418                                 ObjectIdGetDatum(castOid));
1419         scan = systable_beginscan(relation, CastOidIndexId, true,
1420                                                           SnapshotNow, 1, &scankey);
1421
1422         tuple = systable_getnext(scan);
1423         if (!HeapTupleIsValid(tuple))
1424                 elog(ERROR, "could not find tuple for cast %u", castOid);
1425         simple_heap_delete(relation, &tuple->t_self);
1426
1427         systable_endscan(scan);
1428         heap_close(relation, RowExclusiveLock);
1429 }