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