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-2016, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
10 *
11 *
12 * IDENTIFICATION
13 * src/backend/commands/functioncmds.c
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 "access/htup_details.h"
38 #include "access/sysattr.h"
39 #include "catalog/dependency.h"
40 #include "catalog/indexing.h"
41 #include "catalog/objectaccess.h"
42 #include "catalog/pg_aggregate.h"
43 #include "catalog/pg_cast.h"
44 #include "catalog/pg_language.h"
45 #include "catalog/pg_namespace.h"
46 #include "catalog/pg_proc.h"
47 #include "catalog/pg_proc_fn.h"
48 #include "catalog/pg_transform.h"
49 #include "catalog/pg_type.h"
50 #include "catalog/pg_type_fn.h"
51 #include "commands/alter.h"
52 #include "commands/defrem.h"
53 #include "commands/proclang.h"
54 #include "miscadmin.h"
55 #include "optimizer/var.h"
56 #include "parser/parse_coerce.h"
57 #include "parser/parse_collate.h"
58 #include "parser/parse_expr.h"
59 #include "parser/parse_func.h"
60 #include "parser/parse_type.h"
61 #include "utils/acl.h"
62 #include "utils/builtins.h"
63 #include "utils/fmgroids.h"
64 #include "utils/guc.h"
65 #include "utils/lsyscache.h"
66 #include "utils/rel.h"
67 #include "utils/syscache.h"
68 #include "utils/tqual.h"
69
70 /*
71 * Examine the RETURNS clause of the CREATE FUNCTION statement
72 * and return information about it as *prorettype_p and *returnsSet.
73 *
74 * This is more complex than the average typename lookup because we want to
75 * allow a shell type to be used, or even created if the specified return type
76 * doesn't exist yet. (Without this, there's no way to define the I/O procs
77 * for a new type.) But SQL function creation won't cope, so error out if
78 * the target language is SQL. (We do this here, not in the SQL-function
79 * validator, so as not to produce a NOTICE and then an ERROR for the same
80 * condition.)
81 */
82 static void
compute_return_type(TypeName * returnType,Oid languageOid,Oid * prorettype_p,bool * returnsSet_p)83 compute_return_type(TypeName *returnType, Oid languageOid,
84 Oid *prorettype_p, bool *returnsSet_p)
85 {
86 Oid rettype;
87 Type typtup;
88 AclResult aclresult;
89
90 typtup = LookupTypeName(NULL, returnType, NULL, false);
91
92 if (typtup)
93 {
94 if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
95 {
96 if (languageOid == SQLlanguageId)
97 ereport(ERROR,
98 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
99 errmsg("SQL function cannot return shell type %s",
100 TypeNameToString(returnType))));
101 else
102 ereport(NOTICE,
103 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
104 errmsg("return type %s is only a shell",
105 TypeNameToString(returnType))));
106 }
107 rettype = typeTypeId(typtup);
108 ReleaseSysCache(typtup);
109 }
110 else
111 {
112 char *typnam = TypeNameToString(returnType);
113 Oid namespaceId;
114 AclResult aclresult;
115 char *typname;
116 ObjectAddress address;
117
118 /*
119 * Only C-coded functions can be I/O functions. We enforce this
120 * restriction here mainly to prevent littering the catalogs with
121 * shell types due to simple typos in user-defined function
122 * definitions.
123 */
124 if (languageOid != INTERNALlanguageId &&
125 languageOid != ClanguageId)
126 ereport(ERROR,
127 (errcode(ERRCODE_UNDEFINED_OBJECT),
128 errmsg("type \"%s\" does not exist", typnam)));
129
130 /* Reject if there's typmod decoration, too */
131 if (returnType->typmods != NIL)
132 ereport(ERROR,
133 (errcode(ERRCODE_SYNTAX_ERROR),
134 errmsg("type modifier cannot be specified for shell type \"%s\"",
135 typnam)));
136
137 /* Otherwise, go ahead and make a shell type */
138 ereport(NOTICE,
139 (errcode(ERRCODE_UNDEFINED_OBJECT),
140 errmsg("type \"%s\" is not yet defined", typnam),
141 errdetail("Creating a shell type definition.")));
142 namespaceId = QualifiedNameGetCreationNamespace(returnType->names,
143 &typname);
144 aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
145 ACL_CREATE);
146 if (aclresult != ACLCHECK_OK)
147 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
148 get_namespace_name(namespaceId));
149 address = TypeShellMake(typname, namespaceId, GetUserId());
150 rettype = address.objectId;
151 Assert(OidIsValid(rettype));
152 }
153
154 aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
155 if (aclresult != ACLCHECK_OK)
156 aclcheck_error_type(aclresult, rettype);
157
158 *prorettype_p = rettype;
159 *returnsSet_p = returnType->setof;
160 }
161
162 /*
163 * Interpret the function parameter list of a CREATE FUNCTION or
164 * CREATE AGGREGATE statement.
165 *
166 * Input parameters:
167 * parameters: list of FunctionParameter structs
168 * languageOid: OID of function language (InvalidOid if it's CREATE AGGREGATE)
169 * is_aggregate: needed only to determine error handling
170 * queryString: likewise, needed only for error handling
171 *
172 * Results are stored into output parameters. parameterTypes must always
173 * be created, but the other arrays are set to NULL if not needed.
174 * variadicArgType is set to the variadic array type if there's a VARIADIC
175 * parameter (there can be only one); or to InvalidOid if not.
176 * requiredResultType is set to InvalidOid if there are no OUT parameters,
177 * else it is set to the OID of the implied result type.
178 */
179 void
interpret_function_parameter_list(List * parameters,Oid languageOid,bool is_aggregate,const char * queryString,oidvector ** parameterTypes,ArrayType ** allParameterTypes,ArrayType ** parameterModes,ArrayType ** parameterNames,List ** parameterDefaults,Oid * variadicArgType,Oid * requiredResultType)180 interpret_function_parameter_list(List *parameters,
181 Oid languageOid,
182 bool is_aggregate,
183 const char *queryString,
184 oidvector **parameterTypes,
185 ArrayType **allParameterTypes,
186 ArrayType **parameterModes,
187 ArrayType **parameterNames,
188 List **parameterDefaults,
189 Oid *variadicArgType,
190 Oid *requiredResultType)
191 {
192 int parameterCount = list_length(parameters);
193 Oid *inTypes;
194 int inCount = 0;
195 Datum *allTypes;
196 Datum *paramModes;
197 Datum *paramNames;
198 int outCount = 0;
199 int varCount = 0;
200 bool have_names = false;
201 bool have_defaults = false;
202 ListCell *x;
203 int i;
204 ParseState *pstate;
205
206 *variadicArgType = InvalidOid; /* default result */
207 *requiredResultType = InvalidOid; /* default result */
208
209 inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
210 allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
211 paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
212 paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
213 *parameterDefaults = NIL;
214
215 /* may need a pstate for parse analysis of default exprs */
216 pstate = make_parsestate(NULL);
217 pstate->p_sourcetext = queryString;
218
219 /* Scan the list and extract data into work arrays */
220 i = 0;
221 foreach(x, parameters)
222 {
223 FunctionParameter *fp = (FunctionParameter *) lfirst(x);
224 TypeName *t = fp->argType;
225 bool isinput = false;
226 Oid toid;
227 Type typtup;
228 AclResult aclresult;
229
230 typtup = LookupTypeName(NULL, t, NULL, false);
231 if (typtup)
232 {
233 if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
234 {
235 /* As above, hard error if language is SQL */
236 if (languageOid == SQLlanguageId)
237 ereport(ERROR,
238 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
239 errmsg("SQL function cannot accept shell type %s",
240 TypeNameToString(t))));
241 /* We don't allow creating aggregates on shell types either */
242 else if (is_aggregate)
243 ereport(ERROR,
244 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
245 errmsg("aggregate cannot accept shell type %s",
246 TypeNameToString(t))));
247 else
248 ereport(NOTICE,
249 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
250 errmsg("argument type %s is only a shell",
251 TypeNameToString(t))));
252 }
253 toid = typeTypeId(typtup);
254 ReleaseSysCache(typtup);
255 }
256 else
257 {
258 ereport(ERROR,
259 (errcode(ERRCODE_UNDEFINED_OBJECT),
260 errmsg("type %s does not exist",
261 TypeNameToString(t))));
262 toid = InvalidOid; /* keep compiler quiet */
263 }
264
265 aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
266 if (aclresult != ACLCHECK_OK)
267 aclcheck_error_type(aclresult, toid);
268
269 if (t->setof)
270 {
271 if (is_aggregate)
272 ereport(ERROR,
273 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
274 errmsg("aggregates cannot accept set arguments")));
275 else
276 ereport(ERROR,
277 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
278 errmsg("functions cannot accept set arguments")));
279 }
280
281 /* handle input parameters */
282 if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
283 {
284 /* other input parameters can't follow a VARIADIC parameter */
285 if (varCount > 0)
286 ereport(ERROR,
287 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
288 errmsg("VARIADIC parameter must be the last input parameter")));
289 inTypes[inCount++] = toid;
290 isinput = true;
291 }
292
293 /* handle output parameters */
294 if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
295 {
296 if (outCount == 0) /* save first output param's type */
297 *requiredResultType = toid;
298 outCount++;
299 }
300
301 if (fp->mode == FUNC_PARAM_VARIADIC)
302 {
303 *variadicArgType = toid;
304 varCount++;
305 /* validate variadic parameter type */
306 switch (toid)
307 {
308 case ANYARRAYOID:
309 case ANYOID:
310 /* okay */
311 break;
312 default:
313 if (!OidIsValid(get_element_type(toid)))
314 ereport(ERROR,
315 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
316 errmsg("VARIADIC parameter must be an array")));
317 break;
318 }
319 }
320
321 allTypes[i] = ObjectIdGetDatum(toid);
322
323 paramModes[i] = CharGetDatum(fp->mode);
324
325 if (fp->name && fp->name[0])
326 {
327 ListCell *px;
328
329 /*
330 * As of Postgres 9.0 we disallow using the same name for two
331 * input or two output function parameters. Depending on the
332 * function's language, conflicting input and output names might
333 * be bad too, but we leave it to the PL to complain if so.
334 */
335 foreach(px, parameters)
336 {
337 FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
338
339 if (prevfp == fp)
340 break;
341 /* pure in doesn't conflict with pure out */
342 if ((fp->mode == FUNC_PARAM_IN ||
343 fp->mode == FUNC_PARAM_VARIADIC) &&
344 (prevfp->mode == FUNC_PARAM_OUT ||
345 prevfp->mode == FUNC_PARAM_TABLE))
346 continue;
347 if ((prevfp->mode == FUNC_PARAM_IN ||
348 prevfp->mode == FUNC_PARAM_VARIADIC) &&
349 (fp->mode == FUNC_PARAM_OUT ||
350 fp->mode == FUNC_PARAM_TABLE))
351 continue;
352 if (prevfp->name && prevfp->name[0] &&
353 strcmp(prevfp->name, fp->name) == 0)
354 ereport(ERROR,
355 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
356 errmsg("parameter name \"%s\" used more than once",
357 fp->name)));
358 }
359
360 paramNames[i] = CStringGetTextDatum(fp->name);
361 have_names = true;
362 }
363
364 if (fp->defexpr)
365 {
366 Node *def;
367
368 if (!isinput)
369 ereport(ERROR,
370 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
371 errmsg("only input parameters can have default values")));
372
373 def = transformExpr(pstate, fp->defexpr,
374 EXPR_KIND_FUNCTION_DEFAULT);
375 def = coerce_to_specific_type(pstate, def, toid, "DEFAULT");
376 assign_expr_collations(pstate, def);
377
378 /*
379 * Make sure no variables are referred to (this is probably dead
380 * code now that add_missing_from is history).
381 */
382 if (list_length(pstate->p_rtable) != 0 ||
383 contain_var_clause(def))
384 ereport(ERROR,
385 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
386 errmsg("cannot use table references in parameter default value")));
387
388 /*
389 * transformExpr() should have already rejected subqueries,
390 * aggregates, and window functions, based on the EXPR_KIND_ for a
391 * default expression.
392 *
393 * It can't return a set either --- but coerce_to_specific_type
394 * already checked that for us.
395 *
396 * Note: the point of these restrictions is to ensure that an
397 * expression that, on its face, hasn't got subplans, aggregates,
398 * etc cannot suddenly have them after function default arguments
399 * are inserted.
400 */
401
402 *parameterDefaults = lappend(*parameterDefaults, def);
403 have_defaults = true;
404 }
405 else
406 {
407 if (isinput && have_defaults)
408 ereport(ERROR,
409 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
410 errmsg("input parameters after one with a default value must also have defaults")));
411 }
412
413 i++;
414 }
415
416 free_parsestate(pstate);
417
418 /* Now construct the proper outputs as needed */
419 *parameterTypes = buildoidvector(inTypes, inCount);
420
421 if (outCount > 0 || varCount > 0)
422 {
423 *allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,
424 sizeof(Oid), true, 'i');
425 *parameterModes = construct_array(paramModes, parameterCount, CHAROID,
426 1, true, 'c');
427 if (outCount > 1)
428 *requiredResultType = RECORDOID;
429 /* otherwise we set requiredResultType correctly above */
430 }
431 else
432 {
433 *allParameterTypes = NULL;
434 *parameterModes = NULL;
435 }
436
437 if (have_names)
438 {
439 for (i = 0; i < parameterCount; i++)
440 {
441 if (paramNames[i] == PointerGetDatum(NULL))
442 paramNames[i] = CStringGetTextDatum("");
443 }
444 *parameterNames = construct_array(paramNames, parameterCount, TEXTOID,
445 -1, false, 'i');
446 }
447 else
448 *parameterNames = NULL;
449 }
450
451
452 /*
453 * Recognize one of the options that can be passed to both CREATE
454 * FUNCTION and ALTER FUNCTION and return it via one of the out
455 * parameters. Returns true if the passed option was recognized. If
456 * the out parameter we were going to assign to points to non-NULL,
457 * raise a duplicate-clause error. (We don't try to detect duplicate
458 * SET parameters though --- if you're redundant, the last one wins.)
459 */
460 static bool
compute_common_attribute(DefElem * defel,DefElem ** volatility_item,DefElem ** strict_item,DefElem ** security_item,DefElem ** leakproof_item,List ** set_items,DefElem ** cost_item,DefElem ** rows_item,DefElem ** parallel_item)461 compute_common_attribute(DefElem *defel,
462 DefElem **volatility_item,
463 DefElem **strict_item,
464 DefElem **security_item,
465 DefElem **leakproof_item,
466 List **set_items,
467 DefElem **cost_item,
468 DefElem **rows_item,
469 DefElem **parallel_item)
470 {
471 if (strcmp(defel->defname, "volatility") == 0)
472 {
473 if (*volatility_item)
474 goto duplicate_error;
475
476 *volatility_item = defel;
477 }
478 else if (strcmp(defel->defname, "strict") == 0)
479 {
480 if (*strict_item)
481 goto duplicate_error;
482
483 *strict_item = defel;
484 }
485 else if (strcmp(defel->defname, "security") == 0)
486 {
487 if (*security_item)
488 goto duplicate_error;
489
490 *security_item = defel;
491 }
492 else if (strcmp(defel->defname, "leakproof") == 0)
493 {
494 if (*leakproof_item)
495 goto duplicate_error;
496
497 *leakproof_item = defel;
498 }
499 else if (strcmp(defel->defname, "set") == 0)
500 {
501 *set_items = lappend(*set_items, defel->arg);
502 }
503 else if (strcmp(defel->defname, "cost") == 0)
504 {
505 if (*cost_item)
506 goto duplicate_error;
507
508 *cost_item = defel;
509 }
510 else if (strcmp(defel->defname, "rows") == 0)
511 {
512 if (*rows_item)
513 goto duplicate_error;
514
515 *rows_item = defel;
516 }
517 else if (strcmp(defel->defname, "parallel") == 0)
518 {
519 if (*parallel_item)
520 goto duplicate_error;
521
522 *parallel_item = defel;
523 }
524 else
525 return false;
526
527 /* Recognized an option */
528 return true;
529
530 duplicate_error:
531 ereport(ERROR,
532 (errcode(ERRCODE_SYNTAX_ERROR),
533 errmsg("conflicting or redundant options")));
534 return false; /* keep compiler quiet */
535 }
536
537 static char
interpret_func_volatility(DefElem * defel)538 interpret_func_volatility(DefElem *defel)
539 {
540 char *str = strVal(defel->arg);
541
542 if (strcmp(str, "immutable") == 0)
543 return PROVOLATILE_IMMUTABLE;
544 else if (strcmp(str, "stable") == 0)
545 return PROVOLATILE_STABLE;
546 else if (strcmp(str, "volatile") == 0)
547 return PROVOLATILE_VOLATILE;
548 else
549 {
550 elog(ERROR, "invalid volatility \"%s\"", str);
551 return 0; /* keep compiler quiet */
552 }
553 }
554
555 static char
interpret_func_parallel(DefElem * defel)556 interpret_func_parallel(DefElem *defel)
557 {
558 char *str = strVal(defel->arg);
559
560 if (strcmp(str, "safe") == 0)
561 return PROPARALLEL_SAFE;
562 else if (strcmp(str, "unsafe") == 0)
563 return PROPARALLEL_UNSAFE;
564 else if (strcmp(str, "restricted") == 0)
565 return PROPARALLEL_RESTRICTED;
566 else
567 {
568 ereport(ERROR,
569 (errcode(ERRCODE_SYNTAX_ERROR),
570 errmsg("parameter \"parallel\" must be SAFE, RESTRICTED, or UNSAFE")));
571 return PROPARALLEL_UNSAFE; /* keep compiler quiet */
572 }
573 }
574
575 /*
576 * Update a proconfig value according to a list of VariableSetStmt items.
577 *
578 * The input and result may be NULL to signify a null entry.
579 */
580 static ArrayType *
update_proconfig_value(ArrayType * a,List * set_items)581 update_proconfig_value(ArrayType *a, List *set_items)
582 {
583 ListCell *l;
584
585 foreach(l, set_items)
586 {
587 VariableSetStmt *sstmt = (VariableSetStmt *) lfirst(l);
588
589 Assert(IsA(sstmt, VariableSetStmt));
590 if (sstmt->kind == VAR_RESET_ALL)
591 a = NULL;
592 else
593 {
594 char *valuestr = ExtractSetVariableArgs(sstmt);
595
596 if (valuestr)
597 a = GUCArrayAdd(a, sstmt->name, valuestr);
598 else /* RESET */
599 a = GUCArrayDelete(a, sstmt->name);
600 }
601 }
602
603 return a;
604 }
605
606
607 /*
608 * Dissect the list of options assembled in gram.y into function
609 * attributes.
610 */
611 static void
compute_attributes_sql_style(List * options,List ** as,char ** language,Node ** transform,bool * windowfunc_p,char * volatility_p,bool * strict_p,bool * security_definer,bool * leakproof_p,ArrayType ** proconfig,float4 * procost,float4 * prorows,char * parallel_p)612 compute_attributes_sql_style(List *options,
613 List **as,
614 char **language,
615 Node **transform,
616 bool *windowfunc_p,
617 char *volatility_p,
618 bool *strict_p,
619 bool *security_definer,
620 bool *leakproof_p,
621 ArrayType **proconfig,
622 float4 *procost,
623 float4 *prorows,
624 char *parallel_p)
625 {
626 ListCell *option;
627 DefElem *as_item = NULL;
628 DefElem *language_item = NULL;
629 DefElem *transform_item = NULL;
630 DefElem *windowfunc_item = NULL;
631 DefElem *volatility_item = NULL;
632 DefElem *strict_item = NULL;
633 DefElem *security_item = NULL;
634 DefElem *leakproof_item = NULL;
635 List *set_items = NIL;
636 DefElem *cost_item = NULL;
637 DefElem *rows_item = NULL;
638 DefElem *parallel_item = NULL;
639
640 foreach(option, options)
641 {
642 DefElem *defel = (DefElem *) lfirst(option);
643
644 if (strcmp(defel->defname, "as") == 0)
645 {
646 if (as_item)
647 ereport(ERROR,
648 (errcode(ERRCODE_SYNTAX_ERROR),
649 errmsg("conflicting or redundant options")));
650 as_item = defel;
651 }
652 else if (strcmp(defel->defname, "language") == 0)
653 {
654 if (language_item)
655 ereport(ERROR,
656 (errcode(ERRCODE_SYNTAX_ERROR),
657 errmsg("conflicting or redundant options")));
658 language_item = defel;
659 }
660 else if (strcmp(defel->defname, "transform") == 0)
661 {
662 if (transform_item)
663 ereport(ERROR,
664 (errcode(ERRCODE_SYNTAX_ERROR),
665 errmsg("conflicting or redundant options")));
666 transform_item = defel;
667 }
668 else if (strcmp(defel->defname, "window") == 0)
669 {
670 if (windowfunc_item)
671 ereport(ERROR,
672 (errcode(ERRCODE_SYNTAX_ERROR),
673 errmsg("conflicting or redundant options")));
674 windowfunc_item = defel;
675 }
676 else if (compute_common_attribute(defel,
677 &volatility_item,
678 &strict_item,
679 &security_item,
680 &leakproof_item,
681 &set_items,
682 &cost_item,
683 &rows_item,
684 ¶llel_item))
685 {
686 /* recognized common option */
687 continue;
688 }
689 else
690 elog(ERROR, "option \"%s\" not recognized",
691 defel->defname);
692 }
693
694 /* process required items */
695 if (as_item)
696 *as = (List *) as_item->arg;
697 else
698 {
699 ereport(ERROR,
700 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
701 errmsg("no function body specified")));
702 *as = NIL; /* keep compiler quiet */
703 }
704
705 if (language_item)
706 *language = strVal(language_item->arg);
707 else
708 {
709 ereport(ERROR,
710 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
711 errmsg("no language specified")));
712 *language = NULL; /* keep compiler quiet */
713 }
714
715 /* process optional items */
716 if (transform_item)
717 *transform = transform_item->arg;
718 if (windowfunc_item)
719 *windowfunc_p = intVal(windowfunc_item->arg);
720 if (volatility_item)
721 *volatility_p = interpret_func_volatility(volatility_item);
722 if (strict_item)
723 *strict_p = intVal(strict_item->arg);
724 if (security_item)
725 *security_definer = intVal(security_item->arg);
726 if (leakproof_item)
727 *leakproof_p = intVal(leakproof_item->arg);
728 if (set_items)
729 *proconfig = update_proconfig_value(NULL, set_items);
730 if (cost_item)
731 {
732 *procost = defGetNumeric(cost_item);
733 if (*procost <= 0)
734 ereport(ERROR,
735 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
736 errmsg("COST must be positive")));
737 }
738 if (rows_item)
739 {
740 *prorows = defGetNumeric(rows_item);
741 if (*prorows <= 0)
742 ereport(ERROR,
743 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
744 errmsg("ROWS must be positive")));
745 }
746 if (parallel_item)
747 *parallel_p = interpret_func_parallel(parallel_item);
748 }
749
750
751 /*-------------
752 * Interpret the parameters *parameters and return their contents via
753 * *isStrict_p and *volatility_p.
754 *
755 * These parameters supply optional information about a function.
756 * All have defaults if not specified. Parameters:
757 *
758 * * isStrict means the function should not be called when any NULL
759 * inputs are present; instead a NULL result value should be assumed.
760 *
761 * * volatility tells the optimizer whether the function's result can
762 * be assumed to be repeatable over multiple evaluations.
763 *------------
764 */
765 static void
compute_attributes_with_style(List * parameters,bool * isStrict_p,char * volatility_p)766 compute_attributes_with_style(List *parameters, bool *isStrict_p, char *volatility_p)
767 {
768 ListCell *pl;
769
770 foreach(pl, parameters)
771 {
772 DefElem *param = (DefElem *) lfirst(pl);
773
774 if (pg_strcasecmp(param->defname, "isstrict") == 0)
775 *isStrict_p = defGetBoolean(param);
776 else if (pg_strcasecmp(param->defname, "iscachable") == 0)
777 {
778 /* obsolete spelling of isImmutable */
779 if (defGetBoolean(param))
780 *volatility_p = PROVOLATILE_IMMUTABLE;
781 }
782 else
783 ereport(WARNING,
784 (errcode(ERRCODE_SYNTAX_ERROR),
785 errmsg("unrecognized function attribute \"%s\" ignored",
786 param->defname)));
787 }
788 }
789
790
791 /*
792 * For a dynamically linked C language object, the form of the clause is
793 *
794 * AS <object file name> [, <link symbol name> ]
795 *
796 * In all other cases
797 *
798 * AS <object reference, or sql code>
799 */
800 static void
interpret_AS_clause(Oid languageOid,const char * languageName,char * funcname,List * as,char ** prosrc_str_p,char ** probin_str_p)801 interpret_AS_clause(Oid languageOid, const char *languageName,
802 char *funcname, List *as,
803 char **prosrc_str_p, char **probin_str_p)
804 {
805 Assert(as != NIL);
806
807 if (languageOid == ClanguageId)
808 {
809 /*
810 * For "C" language, store the file name in probin and, when given,
811 * the link symbol name in prosrc. If link symbol is omitted,
812 * substitute procedure name. We also allow link symbol to be
813 * specified as "-", since that was the habit in PG versions before
814 * 8.4, and there might be dump files out there that don't translate
815 * that back to "omitted".
816 */
817 *probin_str_p = strVal(linitial(as));
818 if (list_length(as) == 1)
819 *prosrc_str_p = funcname;
820 else
821 {
822 *prosrc_str_p = strVal(lsecond(as));
823 if (strcmp(*prosrc_str_p, "-") == 0)
824 *prosrc_str_p = funcname;
825 }
826 }
827 else
828 {
829 /* Everything else wants the given string in prosrc. */
830 *prosrc_str_p = strVal(linitial(as));
831 *probin_str_p = NULL;
832
833 if (list_length(as) != 1)
834 ereport(ERROR,
835 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
836 errmsg("only one AS item needed for language \"%s\"",
837 languageName)));
838
839 if (languageOid == INTERNALlanguageId)
840 {
841 /*
842 * In PostgreSQL versions before 6.5, the SQL name of the created
843 * function could not be different from the internal name, and
844 * "prosrc" wasn't used. So there is code out there that does
845 * CREATE FUNCTION xyz AS '' LANGUAGE internal. To preserve some
846 * modicum of backwards compatibility, accept an empty "prosrc"
847 * value as meaning the supplied SQL function name.
848 */
849 if (strlen(*prosrc_str_p) == 0)
850 *prosrc_str_p = funcname;
851 }
852 }
853 }
854
855
856 /*
857 * CreateFunction
858 * Execute a CREATE FUNCTION utility statement.
859 */
860 ObjectAddress
CreateFunction(CreateFunctionStmt * stmt,const char * queryString)861 CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
862 {
863 char *probin_str;
864 char *prosrc_str;
865 Oid prorettype;
866 bool returnsSet;
867 char *language;
868 Oid languageOid;
869 Oid languageValidator;
870 Node *transformDefElem = NULL;
871 char *funcname;
872 Oid namespaceId;
873 AclResult aclresult;
874 oidvector *parameterTypes;
875 ArrayType *allParameterTypes;
876 ArrayType *parameterModes;
877 ArrayType *parameterNames;
878 List *parameterDefaults;
879 Oid variadicArgType;
880 List *trftypes_list = NIL;
881 ArrayType *trftypes;
882 Oid requiredResultType;
883 bool isWindowFunc,
884 isStrict,
885 security,
886 isLeakProof;
887 char volatility;
888 ArrayType *proconfig;
889 float4 procost;
890 float4 prorows;
891 HeapTuple languageTuple;
892 Form_pg_language languageStruct;
893 List *as_clause;
894 char parallel;
895
896 /* Convert list of names to a name and namespace */
897 namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
898 &funcname);
899
900 /* Check we have creation rights in target namespace */
901 aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
902 if (aclresult != ACLCHECK_OK)
903 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
904 get_namespace_name(namespaceId));
905
906 /* default attributes */
907 isWindowFunc = false;
908 isStrict = false;
909 security = false;
910 isLeakProof = false;
911 volatility = PROVOLATILE_VOLATILE;
912 proconfig = NULL;
913 procost = -1; /* indicates not set */
914 prorows = -1; /* indicates not set */
915 parallel = PROPARALLEL_UNSAFE;
916
917 /* override attributes from explicit list */
918 compute_attributes_sql_style(stmt->options,
919 &as_clause, &language, &transformDefElem,
920 &isWindowFunc, &volatility,
921 &isStrict, &security, &isLeakProof,
922 &proconfig, &procost, &prorows, ¶llel);
923
924 /* Look up the language and validate permissions */
925 languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
926 if (!HeapTupleIsValid(languageTuple))
927 ereport(ERROR,
928 (errcode(ERRCODE_UNDEFINED_OBJECT),
929 errmsg("language \"%s\" does not exist", language),
930 (PLTemplateExists(language) ?
931 errhint("Use CREATE LANGUAGE to load the language into the database.") : 0)));
932
933 languageOid = HeapTupleGetOid(languageTuple);
934 languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
935
936 if (languageStruct->lanpltrusted)
937 {
938 /* if trusted language, need USAGE privilege */
939 AclResult aclresult;
940
941 aclresult = pg_language_aclcheck(languageOid, GetUserId(), ACL_USAGE);
942 if (aclresult != ACLCHECK_OK)
943 aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
944 NameStr(languageStruct->lanname));
945 }
946 else
947 {
948 /* if untrusted language, must be superuser */
949 if (!superuser())
950 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
951 NameStr(languageStruct->lanname));
952 }
953
954 languageValidator = languageStruct->lanvalidator;
955
956 ReleaseSysCache(languageTuple);
957
958 /*
959 * Only superuser is allowed to create leakproof functions because
960 * leakproof functions can see tuples which have not yet been filtered out
961 * by security barrier views or row level security policies.
962 */
963 if (isLeakProof && !superuser())
964 ereport(ERROR,
965 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
966 errmsg("only superuser can define a leakproof function")));
967
968 if (transformDefElem)
969 {
970 ListCell *lc;
971
972 Assert(IsA(transformDefElem, List));
973
974 foreach(lc, (List *) transformDefElem)
975 {
976 Oid typeid = typenameTypeId(NULL, lfirst(lc));
977 Oid elt = get_base_element_type(typeid);
978
979 typeid = elt ? elt : typeid;
980
981 get_transform_oid(typeid, languageOid, false);
982 trftypes_list = lappend_oid(trftypes_list, typeid);
983 }
984 }
985
986 /*
987 * Convert remaining parameters of CREATE to form wanted by
988 * ProcedureCreate.
989 */
990 interpret_function_parameter_list(stmt->parameters,
991 languageOid,
992 false, /* not an aggregate */
993 queryString,
994 ¶meterTypes,
995 &allParameterTypes,
996 ¶meterModes,
997 ¶meterNames,
998 ¶meterDefaults,
999 &variadicArgType,
1000 &requiredResultType);
1001
1002 if (stmt->returnType)
1003 {
1004 /* explicit RETURNS clause */
1005 compute_return_type(stmt->returnType, languageOid,
1006 &prorettype, &returnsSet);
1007 if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
1008 ereport(ERROR,
1009 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1010 errmsg("function result type must be %s because of OUT parameters",
1011 format_type_be(requiredResultType))));
1012 }
1013 else if (OidIsValid(requiredResultType))
1014 {
1015 /* default RETURNS clause from OUT parameters */
1016 prorettype = requiredResultType;
1017 returnsSet = false;
1018 }
1019 else
1020 {
1021 ereport(ERROR,
1022 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1023 errmsg("function result type must be specified")));
1024 /* Alternative possibility: default to RETURNS VOID */
1025 prorettype = VOIDOID;
1026 returnsSet = false;
1027 }
1028
1029 if (list_length(trftypes_list) > 0)
1030 {
1031 ListCell *lc;
1032 Datum *arr;
1033 int i;
1034
1035 arr = palloc(list_length(trftypes_list) * sizeof(Datum));
1036 i = 0;
1037 foreach(lc, trftypes_list)
1038 arr[i++] = ObjectIdGetDatum(lfirst_oid(lc));
1039 trftypes = construct_array(arr, list_length(trftypes_list),
1040 OIDOID, sizeof(Oid), true, 'i');
1041 }
1042 else
1043 {
1044 /* store SQL NULL instead of empty array */
1045 trftypes = NULL;
1046 }
1047
1048 compute_attributes_with_style(stmt->withClause, &isStrict, &volatility);
1049
1050 interpret_AS_clause(languageOid, language, funcname, as_clause,
1051 &prosrc_str, &probin_str);
1052
1053 /*
1054 * Set default values for COST and ROWS depending on other parameters;
1055 * reject ROWS if it's not returnsSet. NB: pg_dump knows these default
1056 * values, keep it in sync if you change them.
1057 */
1058 if (procost < 0)
1059 {
1060 /* SQL and PL-language functions are assumed more expensive */
1061 if (languageOid == INTERNALlanguageId ||
1062 languageOid == ClanguageId)
1063 procost = 1;
1064 else
1065 procost = 100;
1066 }
1067 if (prorows < 0)
1068 {
1069 if (returnsSet)
1070 prorows = 1000;
1071 else
1072 prorows = 0; /* dummy value if not returnsSet */
1073 }
1074 else if (!returnsSet)
1075 ereport(ERROR,
1076 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1077 errmsg("ROWS is not applicable when function does not return a set")));
1078
1079 /*
1080 * And now that we have all the parameters, and know we're permitted to do
1081 * so, go ahead and create the function.
1082 */
1083 return ProcedureCreate(funcname,
1084 namespaceId,
1085 stmt->replace,
1086 returnsSet,
1087 prorettype,
1088 GetUserId(),
1089 languageOid,
1090 languageValidator,
1091 prosrc_str, /* converted to text later */
1092 probin_str, /* converted to text later */
1093 false, /* not an aggregate */
1094 isWindowFunc,
1095 security,
1096 isLeakProof,
1097 isStrict,
1098 volatility,
1099 parallel,
1100 parameterTypes,
1101 PointerGetDatum(allParameterTypes),
1102 PointerGetDatum(parameterModes),
1103 PointerGetDatum(parameterNames),
1104 parameterDefaults,
1105 PointerGetDatum(trftypes),
1106 PointerGetDatum(proconfig),
1107 procost,
1108 prorows);
1109 }
1110
1111 /*
1112 * Guts of function deletion.
1113 *
1114 * Note: this is also used for aggregate deletion, since the OIDs of
1115 * both functions and aggregates point to pg_proc.
1116 */
1117 void
RemoveFunctionById(Oid funcOid)1118 RemoveFunctionById(Oid funcOid)
1119 {
1120 Relation relation;
1121 HeapTuple tup;
1122 bool isagg;
1123
1124 /*
1125 * Delete the pg_proc tuple.
1126 */
1127 relation = heap_open(ProcedureRelationId, RowExclusiveLock);
1128
1129 tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
1130 if (!HeapTupleIsValid(tup)) /* should not happen */
1131 elog(ERROR, "cache lookup failed for function %u", funcOid);
1132
1133 isagg = ((Form_pg_proc) GETSTRUCT(tup))->proisagg;
1134
1135 simple_heap_delete(relation, &tup->t_self);
1136
1137 ReleaseSysCache(tup);
1138
1139 heap_close(relation, RowExclusiveLock);
1140
1141 /*
1142 * If there's a pg_aggregate tuple, delete that too.
1143 */
1144 if (isagg)
1145 {
1146 relation = heap_open(AggregateRelationId, RowExclusiveLock);
1147
1148 tup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(funcOid));
1149 if (!HeapTupleIsValid(tup)) /* should not happen */
1150 elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);
1151
1152 simple_heap_delete(relation, &tup->t_self);
1153
1154 ReleaseSysCache(tup);
1155
1156 heap_close(relation, RowExclusiveLock);
1157 }
1158 }
1159
1160 /*
1161 * Implements the ALTER FUNCTION utility command (except for the
1162 * RENAME and OWNER clauses, which are handled as part of the generic
1163 * ALTER framework).
1164 */
1165 ObjectAddress
AlterFunction(AlterFunctionStmt * stmt)1166 AlterFunction(AlterFunctionStmt *stmt)
1167 {
1168 HeapTuple tup;
1169 Oid funcOid;
1170 Form_pg_proc procForm;
1171 Relation rel;
1172 ListCell *l;
1173 DefElem *volatility_item = NULL;
1174 DefElem *strict_item = NULL;
1175 DefElem *security_def_item = NULL;
1176 DefElem *leakproof_item = NULL;
1177 List *set_items = NIL;
1178 DefElem *cost_item = NULL;
1179 DefElem *rows_item = NULL;
1180 DefElem *parallel_item = NULL;
1181 ObjectAddress address;
1182
1183 rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1184
1185 funcOid = LookupFuncNameTypeNames(stmt->func->funcname,
1186 stmt->func->funcargs,
1187 false);
1188
1189 tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
1190 if (!HeapTupleIsValid(tup)) /* should not happen */
1191 elog(ERROR, "cache lookup failed for function %u", funcOid);
1192
1193 procForm = (Form_pg_proc) GETSTRUCT(tup);
1194
1195 /* Permission check: must own function */
1196 if (!pg_proc_ownercheck(funcOid, GetUserId()))
1197 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
1198 NameListToString(stmt->func->funcname));
1199
1200 if (procForm->proisagg)
1201 ereport(ERROR,
1202 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1203 errmsg("\"%s\" is an aggregate function",
1204 NameListToString(stmt->func->funcname))));
1205
1206 /* Examine requested actions. */
1207 foreach(l, stmt->actions)
1208 {
1209 DefElem *defel = (DefElem *) lfirst(l);
1210
1211 if (compute_common_attribute(defel,
1212 &volatility_item,
1213 &strict_item,
1214 &security_def_item,
1215 &leakproof_item,
1216 &set_items,
1217 &cost_item,
1218 &rows_item,
1219 ¶llel_item) == false)
1220 elog(ERROR, "option \"%s\" not recognized", defel->defname);
1221 }
1222
1223 if (volatility_item)
1224 procForm->provolatile = interpret_func_volatility(volatility_item);
1225 if (strict_item)
1226 procForm->proisstrict = intVal(strict_item->arg);
1227 if (security_def_item)
1228 procForm->prosecdef = intVal(security_def_item->arg);
1229 if (leakproof_item)
1230 {
1231 procForm->proleakproof = intVal(leakproof_item->arg);
1232 if (procForm->proleakproof && !superuser())
1233 ereport(ERROR,
1234 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1235 errmsg("only superuser can define a leakproof function")));
1236 }
1237 if (cost_item)
1238 {
1239 procForm->procost = defGetNumeric(cost_item);
1240 if (procForm->procost <= 0)
1241 ereport(ERROR,
1242 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1243 errmsg("COST must be positive")));
1244 }
1245 if (rows_item)
1246 {
1247 procForm->prorows = defGetNumeric(rows_item);
1248 if (procForm->prorows <= 0)
1249 ereport(ERROR,
1250 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1251 errmsg("ROWS must be positive")));
1252 if (!procForm->proretset)
1253 ereport(ERROR,
1254 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1255 errmsg("ROWS is not applicable when function does not return a set")));
1256 }
1257 if (set_items)
1258 {
1259 Datum datum;
1260 bool isnull;
1261 ArrayType *a;
1262 Datum repl_val[Natts_pg_proc];
1263 bool repl_null[Natts_pg_proc];
1264 bool repl_repl[Natts_pg_proc];
1265
1266 /* extract existing proconfig setting */
1267 datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull);
1268 a = isnull ? NULL : DatumGetArrayTypeP(datum);
1269
1270 /* update according to each SET or RESET item, left to right */
1271 a = update_proconfig_value(a, set_items);
1272
1273 /* update the tuple */
1274 memset(repl_repl, false, sizeof(repl_repl));
1275 repl_repl[Anum_pg_proc_proconfig - 1] = true;
1276
1277 if (a == NULL)
1278 {
1279 repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
1280 repl_null[Anum_pg_proc_proconfig - 1] = true;
1281 }
1282 else
1283 {
1284 repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a);
1285 repl_null[Anum_pg_proc_proconfig - 1] = false;
1286 }
1287
1288 tup = heap_modify_tuple(tup, RelationGetDescr(rel),
1289 repl_val, repl_null, repl_repl);
1290 }
1291 if (parallel_item)
1292 procForm->proparallel = interpret_func_parallel(parallel_item);
1293
1294 /* Do the update */
1295 simple_heap_update(rel, &tup->t_self, tup);
1296 CatalogUpdateIndexes(rel, tup);
1297
1298 InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
1299
1300 ObjectAddressSet(address, ProcedureRelationId, funcOid);
1301
1302 heap_close(rel, NoLock);
1303 heap_freetuple(tup);
1304
1305 return address;
1306 }
1307
1308 /*
1309 * SetFunctionReturnType - change declared return type of a function
1310 *
1311 * This is presently only used for adjusting legacy functions that return
1312 * OPAQUE to return whatever we find their correct definition should be.
1313 * The caller should emit a suitable warning explaining what we did.
1314 */
1315 void
SetFunctionReturnType(Oid funcOid,Oid newRetType)1316 SetFunctionReturnType(Oid funcOid, Oid newRetType)
1317 {
1318 Relation pg_proc_rel;
1319 HeapTuple tup;
1320 Form_pg_proc procForm;
1321 ObjectAddress func_address;
1322 ObjectAddress type_address;
1323
1324 pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1325
1326 tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
1327 if (!HeapTupleIsValid(tup)) /* should not happen */
1328 elog(ERROR, "cache lookup failed for function %u", funcOid);
1329 procForm = (Form_pg_proc) GETSTRUCT(tup);
1330
1331 if (procForm->prorettype != OPAQUEOID) /* caller messed up */
1332 elog(ERROR, "function %u doesn't return OPAQUE", funcOid);
1333
1334 /* okay to overwrite copied tuple */
1335 procForm->prorettype = newRetType;
1336
1337 /* update the catalog and its indexes */
1338 simple_heap_update(pg_proc_rel, &tup->t_self, tup);
1339
1340 CatalogUpdateIndexes(pg_proc_rel, tup);
1341
1342 heap_close(pg_proc_rel, RowExclusiveLock);
1343
1344 /*
1345 * Also update the dependency to the new type. Opaque is a pinned type, so
1346 * there is no old dependency record for it that we would need to remove.
1347 */
1348 ObjectAddressSet(type_address, TypeRelationId, newRetType);
1349 ObjectAddressSet(func_address, ProcedureRelationId, funcOid);
1350 recordDependencyOn(&func_address, &type_address, DEPENDENCY_NORMAL);
1351 }
1352
1353
1354 /*
1355 * SetFunctionArgType - change declared argument type of a function
1356 *
1357 * As above, but change an argument's type.
1358 */
1359 void
SetFunctionArgType(Oid funcOid,int argIndex,Oid newArgType)1360 SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType)
1361 {
1362 Relation pg_proc_rel;
1363 HeapTuple tup;
1364 Form_pg_proc procForm;
1365 ObjectAddress func_address;
1366 ObjectAddress type_address;
1367
1368 pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1369
1370 tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
1371 if (!HeapTupleIsValid(tup)) /* should not happen */
1372 elog(ERROR, "cache lookup failed for function %u", funcOid);
1373 procForm = (Form_pg_proc) GETSTRUCT(tup);
1374
1375 if (argIndex < 0 || argIndex >= procForm->pronargs ||
1376 procForm->proargtypes.values[argIndex] != OPAQUEOID)
1377 elog(ERROR, "function %u doesn't take OPAQUE", funcOid);
1378
1379 /* okay to overwrite copied tuple */
1380 procForm->proargtypes.values[argIndex] = newArgType;
1381
1382 /* update the catalog and its indexes */
1383 simple_heap_update(pg_proc_rel, &tup->t_self, tup);
1384
1385 CatalogUpdateIndexes(pg_proc_rel, tup);
1386
1387 heap_close(pg_proc_rel, RowExclusiveLock);
1388
1389 /*
1390 * Also update the dependency to the new type. Opaque is a pinned type, so
1391 * there is no old dependency record for it that we would need to remove.
1392 */
1393 ObjectAddressSet(type_address, TypeRelationId, newArgType);
1394 ObjectAddressSet(func_address, ProcedureRelationId, funcOid);
1395 recordDependencyOn(&func_address, &type_address, DEPENDENCY_NORMAL);
1396 }
1397
1398
1399
1400 /*
1401 * CREATE CAST
1402 */
1403 ObjectAddress
CreateCast(CreateCastStmt * stmt)1404 CreateCast(CreateCastStmt *stmt)
1405 {
1406 Oid sourcetypeid;
1407 Oid targettypeid;
1408 char sourcetyptype;
1409 char targettyptype;
1410 Oid funcid;
1411 Oid castid;
1412 int nargs;
1413 char castcontext;
1414 char castmethod;
1415 Relation relation;
1416 HeapTuple tuple;
1417 Datum values[Natts_pg_cast];
1418 bool nulls[Natts_pg_cast];
1419 ObjectAddress myself,
1420 referenced;
1421 AclResult aclresult;
1422
1423 sourcetypeid = typenameTypeId(NULL, stmt->sourcetype);
1424 targettypeid = typenameTypeId(NULL, stmt->targettype);
1425 sourcetyptype = get_typtype(sourcetypeid);
1426 targettyptype = get_typtype(targettypeid);
1427
1428 /* No pseudo-types allowed */
1429 if (sourcetyptype == TYPTYPE_PSEUDO)
1430 ereport(ERROR,
1431 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1432 errmsg("source data type %s is a pseudo-type",
1433 TypeNameToString(stmt->sourcetype))));
1434
1435 if (targettyptype == TYPTYPE_PSEUDO)
1436 ereport(ERROR,
1437 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1438 errmsg("target data type %s is a pseudo-type",
1439 TypeNameToString(stmt->targettype))));
1440
1441 /* Permission check */
1442 if (!pg_type_ownercheck(sourcetypeid, GetUserId())
1443 && !pg_type_ownercheck(targettypeid, GetUserId()))
1444 ereport(ERROR,
1445 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1446 errmsg("must be owner of type %s or type %s",
1447 format_type_be(sourcetypeid),
1448 format_type_be(targettypeid))));
1449
1450 aclresult = pg_type_aclcheck(sourcetypeid, GetUserId(), ACL_USAGE);
1451 if (aclresult != ACLCHECK_OK)
1452 aclcheck_error_type(aclresult, sourcetypeid);
1453
1454 aclresult = pg_type_aclcheck(targettypeid, GetUserId(), ACL_USAGE);
1455 if (aclresult != ACLCHECK_OK)
1456 aclcheck_error_type(aclresult, targettypeid);
1457
1458 /* Domains are allowed for historical reasons, but we warn */
1459 if (sourcetyptype == TYPTYPE_DOMAIN)
1460 ereport(WARNING,
1461 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1462 errmsg("cast will be ignored because the source data type is a domain")));
1463
1464 else if (targettyptype == TYPTYPE_DOMAIN)
1465 ereport(WARNING,
1466 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1467 errmsg("cast will be ignored because the target data type is a domain")));
1468
1469 /* Determine the cast method */
1470 if (stmt->func != NULL)
1471 castmethod = COERCION_METHOD_FUNCTION;
1472 else if (stmt->inout)
1473 castmethod = COERCION_METHOD_INOUT;
1474 else
1475 castmethod = COERCION_METHOD_BINARY;
1476
1477 if (castmethod == COERCION_METHOD_FUNCTION)
1478 {
1479 Form_pg_proc procstruct;
1480
1481 funcid = LookupFuncNameTypeNames(stmt->func->funcname,
1482 stmt->func->funcargs,
1483 false);
1484
1485 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1486 if (!HeapTupleIsValid(tuple))
1487 elog(ERROR, "cache lookup failed for function %u", funcid);
1488
1489 procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1490 nargs = procstruct->pronargs;
1491 if (nargs < 1 || nargs > 3)
1492 ereport(ERROR,
1493 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1494 errmsg("cast function must take one to three arguments")));
1495 if (!IsBinaryCoercible(sourcetypeid, procstruct->proargtypes.values[0]))
1496 ereport(ERROR,
1497 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1498 errmsg("argument of cast function must match or be binary-coercible from source data type")));
1499 if (nargs > 1 && procstruct->proargtypes.values[1] != INT4OID)
1500 ereport(ERROR,
1501 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1502 errmsg("second argument of cast function must be type integer")));
1503 if (nargs > 2 && procstruct->proargtypes.values[2] != BOOLOID)
1504 ereport(ERROR,
1505 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1506 errmsg("third argument of cast function must be type boolean")));
1507 if (!IsBinaryCoercible(procstruct->prorettype, targettypeid))
1508 ereport(ERROR,
1509 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1510 errmsg("return data type of cast function must match or be binary-coercible to target data type")));
1511
1512 /*
1513 * Restricting the volatility of a cast function may or may not be a
1514 * good idea in the abstract, but it definitely breaks many old
1515 * user-defined types. Disable this check --- tgl 2/1/03
1516 */
1517 #ifdef NOT_USED
1518 if (procstruct->provolatile == PROVOLATILE_VOLATILE)
1519 ereport(ERROR,
1520 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1521 errmsg("cast function must not be volatile")));
1522 #endif
1523 if (procstruct->proisagg)
1524 ereport(ERROR,
1525 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1526 errmsg("cast function must not be an aggregate function")));
1527 if (procstruct->proiswindow)
1528 ereport(ERROR,
1529 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1530 errmsg("cast function must not be a window function")));
1531 if (procstruct->proretset)
1532 ereport(ERROR,
1533 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1534 errmsg("cast function must not return a set")));
1535
1536 ReleaseSysCache(tuple);
1537 }
1538 else
1539 {
1540 funcid = InvalidOid;
1541 nargs = 0;
1542 }
1543
1544 if (castmethod == COERCION_METHOD_BINARY)
1545 {
1546 int16 typ1len;
1547 int16 typ2len;
1548 bool typ1byval;
1549 bool typ2byval;
1550 char typ1align;
1551 char typ2align;
1552
1553 /*
1554 * Must be superuser to create binary-compatible casts, since
1555 * erroneous casts can easily crash the backend.
1556 */
1557 if (!superuser())
1558 ereport(ERROR,
1559 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1560 errmsg("must be superuser to create a cast WITHOUT FUNCTION")));
1561
1562 /*
1563 * Also, insist that the types match as to size, alignment, and
1564 * pass-by-value attributes; this provides at least a crude check that
1565 * they have similar representations. A pair of types that fail this
1566 * test should certainly not be equated.
1567 */
1568 get_typlenbyvalalign(sourcetypeid, &typ1len, &typ1byval, &typ1align);
1569 get_typlenbyvalalign(targettypeid, &typ2len, &typ2byval, &typ2align);
1570 if (typ1len != typ2len ||
1571 typ1byval != typ2byval ||
1572 typ1align != typ2align)
1573 ereport(ERROR,
1574 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1575 errmsg("source and target data types are not physically compatible")));
1576
1577 /*
1578 * We know that composite, enum and array types are never binary-
1579 * compatible with each other. They all have OIDs embedded in them.
1580 *
1581 * Theoretically you could build a user-defined base type that is
1582 * binary-compatible with a composite, enum, or array type. But we
1583 * disallow that too, as in practice such a cast is surely a mistake.
1584 * You can always work around that by writing a cast function.
1585 */
1586 if (sourcetyptype == TYPTYPE_COMPOSITE ||
1587 targettyptype == TYPTYPE_COMPOSITE)
1588 ereport(ERROR,
1589 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1590 errmsg("composite data types are not binary-compatible")));
1591
1592 if (sourcetyptype == TYPTYPE_ENUM ||
1593 targettyptype == TYPTYPE_ENUM)
1594 ereport(ERROR,
1595 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1596 errmsg("enum data types are not binary-compatible")));
1597
1598 if (OidIsValid(get_element_type(sourcetypeid)) ||
1599 OidIsValid(get_element_type(targettypeid)))
1600 ereport(ERROR,
1601 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1602 errmsg("array data types are not binary-compatible")));
1603
1604 /*
1605 * We also disallow creating binary-compatibility casts involving
1606 * domains. Casting from a domain to its base type is already
1607 * allowed, and casting the other way ought to go through domain
1608 * coercion to permit constraint checking. Again, if you're intent on
1609 * having your own semantics for that, create a no-op cast function.
1610 *
1611 * NOTE: if we were to relax this, the above checks for composites
1612 * etc. would have to be modified to look through domains to their
1613 * base types.
1614 */
1615 if (sourcetyptype == TYPTYPE_DOMAIN ||
1616 targettyptype == TYPTYPE_DOMAIN)
1617 ereport(ERROR,
1618 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1619 errmsg("domain data types must not be marked binary-compatible")));
1620 }
1621
1622 /*
1623 * Allow source and target types to be same only for length coercion
1624 * functions. We assume a multi-arg function does length coercion.
1625 */
1626 if (sourcetypeid == targettypeid && nargs < 2)
1627 ereport(ERROR,
1628 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1629 errmsg("source data type and target data type are the same")));
1630
1631 /* convert CoercionContext enum to char value for castcontext */
1632 switch (stmt->context)
1633 {
1634 case COERCION_IMPLICIT:
1635 castcontext = COERCION_CODE_IMPLICIT;
1636 break;
1637 case COERCION_ASSIGNMENT:
1638 castcontext = COERCION_CODE_ASSIGNMENT;
1639 break;
1640 case COERCION_EXPLICIT:
1641 castcontext = COERCION_CODE_EXPLICIT;
1642 break;
1643 default:
1644 elog(ERROR, "unrecognized CoercionContext: %d", stmt->context);
1645 castcontext = 0; /* keep compiler quiet */
1646 break;
1647 }
1648
1649 relation = heap_open(CastRelationId, RowExclusiveLock);
1650
1651 /*
1652 * Check for duplicate. This is just to give a friendly error message,
1653 * the unique index would catch it anyway (so no need to sweat about race
1654 * conditions).
1655 */
1656 tuple = SearchSysCache2(CASTSOURCETARGET,
1657 ObjectIdGetDatum(sourcetypeid),
1658 ObjectIdGetDatum(targettypeid));
1659 if (HeapTupleIsValid(tuple))
1660 ereport(ERROR,
1661 (errcode(ERRCODE_DUPLICATE_OBJECT),
1662 errmsg("cast from type %s to type %s already exists",
1663 format_type_be(sourcetypeid),
1664 format_type_be(targettypeid))));
1665
1666 /* ready to go */
1667 values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
1668 values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid);
1669 values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid);
1670 values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext);
1671 values[Anum_pg_cast_castmethod - 1] = CharGetDatum(castmethod);
1672
1673 MemSet(nulls, false, sizeof(nulls));
1674
1675 tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
1676
1677 castid = simple_heap_insert(relation, tuple);
1678
1679 CatalogUpdateIndexes(relation, tuple);
1680
1681 /* make dependency entries */
1682 myself.classId = CastRelationId;
1683 myself.objectId = castid;
1684 myself.objectSubId = 0;
1685
1686 /* dependency on source type */
1687 referenced.classId = TypeRelationId;
1688 referenced.objectId = sourcetypeid;
1689 referenced.objectSubId = 0;
1690 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1691
1692 /* dependency on target type */
1693 referenced.classId = TypeRelationId;
1694 referenced.objectId = targettypeid;
1695 referenced.objectSubId = 0;
1696 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1697
1698 /* dependency on function */
1699 if (OidIsValid(funcid))
1700 {
1701 referenced.classId = ProcedureRelationId;
1702 referenced.objectId = funcid;
1703 referenced.objectSubId = 0;
1704 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1705 }
1706
1707 /* dependency on extension */
1708 recordDependencyOnCurrentExtension(&myself, false);
1709
1710 /* Post creation hook for new cast */
1711 InvokeObjectPostCreateHook(CastRelationId, castid, 0);
1712
1713 heap_freetuple(tuple);
1714
1715 heap_close(relation, RowExclusiveLock);
1716
1717 return myself;
1718 }
1719
1720 /*
1721 * get_cast_oid - given two type OIDs, look up a cast OID
1722 *
1723 * If missing_ok is false, throw an error if the cast is not found. If
1724 * true, just return InvalidOid.
1725 */
1726 Oid
get_cast_oid(Oid sourcetypeid,Oid targettypeid,bool missing_ok)1727 get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok)
1728 {
1729 Oid oid;
1730
1731 oid = GetSysCacheOid2(CASTSOURCETARGET,
1732 ObjectIdGetDatum(sourcetypeid),
1733 ObjectIdGetDatum(targettypeid));
1734 if (!OidIsValid(oid) && !missing_ok)
1735 ereport(ERROR,
1736 (errcode(ERRCODE_UNDEFINED_OBJECT),
1737 errmsg("cast from type %s to type %s does not exist",
1738 format_type_be(sourcetypeid),
1739 format_type_be(targettypeid))));
1740 return oid;
1741 }
1742
1743 void
DropCastById(Oid castOid)1744 DropCastById(Oid castOid)
1745 {
1746 Relation relation;
1747 ScanKeyData scankey;
1748 SysScanDesc scan;
1749 HeapTuple tuple;
1750
1751 relation = heap_open(CastRelationId, RowExclusiveLock);
1752
1753 ScanKeyInit(&scankey,
1754 ObjectIdAttributeNumber,
1755 BTEqualStrategyNumber, F_OIDEQ,
1756 ObjectIdGetDatum(castOid));
1757 scan = systable_beginscan(relation, CastOidIndexId, true,
1758 NULL, 1, &scankey);
1759
1760 tuple = systable_getnext(scan);
1761 if (!HeapTupleIsValid(tuple))
1762 elog(ERROR, "could not find tuple for cast %u", castOid);
1763 simple_heap_delete(relation, &tuple->t_self);
1764
1765 systable_endscan(scan);
1766 heap_close(relation, RowExclusiveLock);
1767 }
1768
1769
1770 static void
check_transform_function(Form_pg_proc procstruct)1771 check_transform_function(Form_pg_proc procstruct)
1772 {
1773 if (procstruct->provolatile == PROVOLATILE_VOLATILE)
1774 ereport(ERROR,
1775 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1776 errmsg("transform function must not be volatile")));
1777 if (procstruct->proisagg)
1778 ereport(ERROR,
1779 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1780 errmsg("transform function must not be an aggregate function")));
1781 if (procstruct->proiswindow)
1782 ereport(ERROR,
1783 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1784 errmsg("transform function must not be a window function")));
1785 if (procstruct->proretset)
1786 ereport(ERROR,
1787 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1788 errmsg("transform function must not return a set")));
1789 if (procstruct->pronargs != 1)
1790 ereport(ERROR,
1791 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1792 errmsg("transform function must take one argument")));
1793 if (procstruct->proargtypes.values[0] != INTERNALOID)
1794 ereport(ERROR,
1795 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1796 errmsg("first argument of transform function must be type \"internal\"")));
1797 }
1798
1799
1800 /*
1801 * CREATE TRANSFORM
1802 */
1803 ObjectAddress
CreateTransform(CreateTransformStmt * stmt)1804 CreateTransform(CreateTransformStmt *stmt)
1805 {
1806 Oid typeid;
1807 char typtype;
1808 Oid langid;
1809 Oid fromsqlfuncid;
1810 Oid tosqlfuncid;
1811 AclResult aclresult;
1812 Form_pg_proc procstruct;
1813 Datum values[Natts_pg_transform];
1814 bool nulls[Natts_pg_transform];
1815 bool replaces[Natts_pg_transform];
1816 Oid transformid;
1817 HeapTuple tuple;
1818 HeapTuple newtuple;
1819 Relation relation;
1820 ObjectAddress myself,
1821 referenced;
1822 bool is_replace;
1823
1824 /*
1825 * Get the type
1826 */
1827 typeid = typenameTypeId(NULL, stmt->type_name);
1828 typtype = get_typtype(typeid);
1829
1830 if (typtype == TYPTYPE_PSEUDO)
1831 ereport(ERROR,
1832 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1833 errmsg("data type %s is a pseudo-type",
1834 TypeNameToString(stmt->type_name))));
1835
1836 if (typtype == TYPTYPE_DOMAIN)
1837 ereport(ERROR,
1838 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1839 errmsg("data type %s is a domain",
1840 TypeNameToString(stmt->type_name))));
1841
1842 if (!pg_type_ownercheck(typeid, GetUserId()))
1843 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeid);
1844
1845 aclresult = pg_type_aclcheck(typeid, GetUserId(), ACL_USAGE);
1846 if (aclresult != ACLCHECK_OK)
1847 aclcheck_error_type(aclresult, typeid);
1848
1849 /*
1850 * Get the language
1851 */
1852 langid = get_language_oid(stmt->lang, false);
1853
1854 aclresult = pg_language_aclcheck(langid, GetUserId(), ACL_USAGE);
1855 if (aclresult != ACLCHECK_OK)
1856 aclcheck_error(aclresult, ACL_KIND_LANGUAGE, stmt->lang);
1857
1858 /*
1859 * Get the functions
1860 */
1861 if (stmt->fromsql)
1862 {
1863 fromsqlfuncid = LookupFuncNameTypeNames(stmt->fromsql->funcname, stmt->fromsql->funcargs, false);
1864
1865 if (!pg_proc_ownercheck(fromsqlfuncid, GetUserId()))
1866 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(stmt->fromsql->funcname));
1867
1868 aclresult = pg_proc_aclcheck(fromsqlfuncid, GetUserId(), ACL_EXECUTE);
1869 if (aclresult != ACLCHECK_OK)
1870 aclcheck_error(aclresult, ACL_KIND_PROC, NameListToString(stmt->fromsql->funcname));
1871
1872 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fromsqlfuncid));
1873 if (!HeapTupleIsValid(tuple))
1874 elog(ERROR, "cache lookup failed for function %u", fromsqlfuncid);
1875 procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1876 if (procstruct->prorettype != INTERNALOID)
1877 ereport(ERROR,
1878 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1879 errmsg("return data type of FROM SQL function must be \"internal\"")));
1880 check_transform_function(procstruct);
1881 ReleaseSysCache(tuple);
1882 }
1883 else
1884 fromsqlfuncid = InvalidOid;
1885
1886 if (stmt->tosql)
1887 {
1888 tosqlfuncid = LookupFuncNameTypeNames(stmt->tosql->funcname, stmt->tosql->funcargs, false);
1889
1890 if (!pg_proc_ownercheck(tosqlfuncid, GetUserId()))
1891 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(stmt->tosql->funcname));
1892
1893 aclresult = pg_proc_aclcheck(tosqlfuncid, GetUserId(), ACL_EXECUTE);
1894 if (aclresult != ACLCHECK_OK)
1895 aclcheck_error(aclresult, ACL_KIND_PROC, NameListToString(stmt->tosql->funcname));
1896
1897 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(tosqlfuncid));
1898 if (!HeapTupleIsValid(tuple))
1899 elog(ERROR, "cache lookup failed for function %u", tosqlfuncid);
1900 procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1901 if (procstruct->prorettype != typeid)
1902 ereport(ERROR,
1903 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1904 errmsg("return data type of TO SQL function must be the transform data type")));
1905 check_transform_function(procstruct);
1906 ReleaseSysCache(tuple);
1907 }
1908 else
1909 tosqlfuncid = InvalidOid;
1910
1911 /*
1912 * Ready to go
1913 */
1914 values[Anum_pg_transform_trftype - 1] = ObjectIdGetDatum(typeid);
1915 values[Anum_pg_transform_trflang - 1] = ObjectIdGetDatum(langid);
1916 values[Anum_pg_transform_trffromsql - 1] = ObjectIdGetDatum(fromsqlfuncid);
1917 values[Anum_pg_transform_trftosql - 1] = ObjectIdGetDatum(tosqlfuncid);
1918
1919 MemSet(nulls, false, sizeof(nulls));
1920
1921 relation = heap_open(TransformRelationId, RowExclusiveLock);
1922
1923 tuple = SearchSysCache2(TRFTYPELANG,
1924 ObjectIdGetDatum(typeid),
1925 ObjectIdGetDatum(langid));
1926 if (HeapTupleIsValid(tuple))
1927 {
1928 if (!stmt->replace)
1929 ereport(ERROR,
1930 (errcode(ERRCODE_DUPLICATE_OBJECT),
1931 errmsg("transform for type %s language \"%s\" already exists",
1932 format_type_be(typeid),
1933 stmt->lang)));
1934
1935 MemSet(replaces, false, sizeof(replaces));
1936 replaces[Anum_pg_transform_trffromsql - 1] = true;
1937 replaces[Anum_pg_transform_trftosql - 1] = true;
1938
1939 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
1940 simple_heap_update(relation, &newtuple->t_self, newtuple);
1941
1942 transformid = HeapTupleGetOid(tuple);
1943 ReleaseSysCache(tuple);
1944 is_replace = true;
1945 }
1946 else
1947 {
1948 newtuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
1949 transformid = simple_heap_insert(relation, newtuple);
1950 is_replace = false;
1951 }
1952
1953 CatalogUpdateIndexes(relation, newtuple);
1954
1955 if (is_replace)
1956 deleteDependencyRecordsFor(TransformRelationId, transformid, true);
1957
1958 /* make dependency entries */
1959 myself.classId = TransformRelationId;
1960 myself.objectId = transformid;
1961 myself.objectSubId = 0;
1962
1963 /* dependency on language */
1964 referenced.classId = LanguageRelationId;
1965 referenced.objectId = langid;
1966 referenced.objectSubId = 0;
1967 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1968
1969 /* dependency on type */
1970 referenced.classId = TypeRelationId;
1971 referenced.objectId = typeid;
1972 referenced.objectSubId = 0;
1973 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1974
1975 /* dependencies on functions */
1976 if (OidIsValid(fromsqlfuncid))
1977 {
1978 referenced.classId = ProcedureRelationId;
1979 referenced.objectId = fromsqlfuncid;
1980 referenced.objectSubId = 0;
1981 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1982 }
1983 if (OidIsValid(tosqlfuncid))
1984 {
1985 referenced.classId = ProcedureRelationId;
1986 referenced.objectId = tosqlfuncid;
1987 referenced.objectSubId = 0;
1988 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1989 }
1990
1991 /* dependency on extension */
1992 recordDependencyOnCurrentExtension(&myself, is_replace);
1993
1994 /* Post creation hook for new transform */
1995 InvokeObjectPostCreateHook(TransformRelationId, transformid, 0);
1996
1997 heap_freetuple(newtuple);
1998
1999 heap_close(relation, RowExclusiveLock);
2000
2001 return myself;
2002 }
2003
2004
2005 /*
2006 * get_transform_oid - given type OID and language OID, look up a transform OID
2007 *
2008 * If missing_ok is false, throw an error if the transform is not found. If
2009 * true, just return InvalidOid.
2010 */
2011 Oid
get_transform_oid(Oid type_id,Oid lang_id,bool missing_ok)2012 get_transform_oid(Oid type_id, Oid lang_id, bool missing_ok)
2013 {
2014 Oid oid;
2015
2016 oid = GetSysCacheOid2(TRFTYPELANG,
2017 ObjectIdGetDatum(type_id),
2018 ObjectIdGetDatum(lang_id));
2019 if (!OidIsValid(oid) && !missing_ok)
2020 ereport(ERROR,
2021 (errcode(ERRCODE_UNDEFINED_OBJECT),
2022 errmsg("transform for type %s language \"%s\" does not exist",
2023 format_type_be(type_id),
2024 get_language_name(lang_id, false))));
2025 return oid;
2026 }
2027
2028
2029 void
DropTransformById(Oid transformOid)2030 DropTransformById(Oid transformOid)
2031 {
2032 Relation relation;
2033 ScanKeyData scankey;
2034 SysScanDesc scan;
2035 HeapTuple tuple;
2036
2037 relation = heap_open(TransformRelationId, RowExclusiveLock);
2038
2039 ScanKeyInit(&scankey,
2040 ObjectIdAttributeNumber,
2041 BTEqualStrategyNumber, F_OIDEQ,
2042 ObjectIdGetDatum(transformOid));
2043 scan = systable_beginscan(relation, TransformOidIndexId, true,
2044 NULL, 1, &scankey);
2045
2046 tuple = systable_getnext(scan);
2047 if (!HeapTupleIsValid(tuple))
2048 elog(ERROR, "could not find tuple for transform %u", transformOid);
2049 simple_heap_delete(relation, &tuple->t_self);
2050
2051 systable_endscan(scan);
2052 heap_close(relation, RowExclusiveLock);
2053 }
2054
2055
2056 /*
2057 * Subroutine for ALTER FUNCTION/AGGREGATE SET SCHEMA/RENAME
2058 *
2059 * Is there a function with the given name and signature already in the given
2060 * namespace? If so, raise an appropriate error message.
2061 */
2062 void
IsThereFunctionInNamespace(const char * proname,int pronargs,oidvector * proargtypes,Oid nspOid)2063 IsThereFunctionInNamespace(const char *proname, int pronargs,
2064 oidvector *proargtypes, Oid nspOid)
2065 {
2066 /* check for duplicate name (more friendly than unique-index failure) */
2067 if (SearchSysCacheExists3(PROCNAMEARGSNSP,
2068 CStringGetDatum(proname),
2069 PointerGetDatum(proargtypes),
2070 ObjectIdGetDatum(nspOid)))
2071 ereport(ERROR,
2072 (errcode(ERRCODE_DUPLICATE_FUNCTION),
2073 errmsg("function %s already exists in schema \"%s\"",
2074 funcname_signature_string(proname, pronargs,
2075 NIL, proargtypes->values),
2076 get_namespace_name(nspOid))));
2077 }
2078
2079 /*
2080 * ExecuteDoStmt
2081 * Execute inline procedural-language code
2082 */
2083 void
ExecuteDoStmt(DoStmt * stmt)2084 ExecuteDoStmt(DoStmt *stmt)
2085 {
2086 InlineCodeBlock *codeblock = makeNode(InlineCodeBlock);
2087 ListCell *arg;
2088 DefElem *as_item = NULL;
2089 DefElem *language_item = NULL;
2090 char *language;
2091 Oid laninline;
2092 HeapTuple languageTuple;
2093 Form_pg_language languageStruct;
2094
2095 /* Process options we got from gram.y */
2096 foreach(arg, stmt->args)
2097 {
2098 DefElem *defel = (DefElem *) lfirst(arg);
2099
2100 if (strcmp(defel->defname, "as") == 0)
2101 {
2102 if (as_item)
2103 ereport(ERROR,
2104 (errcode(ERRCODE_SYNTAX_ERROR),
2105 errmsg("conflicting or redundant options")));
2106 as_item = defel;
2107 }
2108 else if (strcmp(defel->defname, "language") == 0)
2109 {
2110 if (language_item)
2111 ereport(ERROR,
2112 (errcode(ERRCODE_SYNTAX_ERROR),
2113 errmsg("conflicting or redundant options")));
2114 language_item = defel;
2115 }
2116 else
2117 elog(ERROR, "option \"%s\" not recognized",
2118 defel->defname);
2119 }
2120
2121 if (as_item)
2122 codeblock->source_text = strVal(as_item->arg);
2123 else
2124 ereport(ERROR,
2125 (errcode(ERRCODE_SYNTAX_ERROR),
2126 errmsg("no inline code specified")));
2127
2128 /* if LANGUAGE option wasn't specified, use the default */
2129 if (language_item)
2130 language = strVal(language_item->arg);
2131 else
2132 language = "plpgsql";
2133
2134 /* Look up the language and validate permissions */
2135 languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
2136 if (!HeapTupleIsValid(languageTuple))
2137 ereport(ERROR,
2138 (errcode(ERRCODE_UNDEFINED_OBJECT),
2139 errmsg("language \"%s\" does not exist", language),
2140 (PLTemplateExists(language) ?
2141 errhint("Use CREATE LANGUAGE to load the language into the database.") : 0)));
2142
2143 codeblock->langOid = HeapTupleGetOid(languageTuple);
2144 languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
2145 codeblock->langIsTrusted = languageStruct->lanpltrusted;
2146
2147 if (languageStruct->lanpltrusted)
2148 {
2149 /* if trusted language, need USAGE privilege */
2150 AclResult aclresult;
2151
2152 aclresult = pg_language_aclcheck(codeblock->langOid, GetUserId(),
2153 ACL_USAGE);
2154 if (aclresult != ACLCHECK_OK)
2155 aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
2156 NameStr(languageStruct->lanname));
2157 }
2158 else
2159 {
2160 /* if untrusted language, must be superuser */
2161 if (!superuser())
2162 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
2163 NameStr(languageStruct->lanname));
2164 }
2165
2166 /* get the handler function's OID */
2167 laninline = languageStruct->laninline;
2168 if (!OidIsValid(laninline))
2169 ereport(ERROR,
2170 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2171 errmsg("language \"%s\" does not support inline code execution",
2172 NameStr(languageStruct->lanname))));
2173
2174 ReleaseSysCache(languageTuple);
2175
2176 /* execute the inline handler */
2177 OidFunctionCall1(laninline, PointerGetDatum(codeblock));
2178 }
2179