1 /*-------------------------------------------------------------------------
2  *
3  * funcapi.c
4  *	  Utility and convenience functions for fmgr functions that return
5  *	  sets and/or composite types, or deal with VARIADIC inputs.
6  *
7  * Copyright (c) 2002-2017, PostgreSQL Global Development Group
8  *
9  * IDENTIFICATION
10  *	  src/backend/utils/fmgr/funcapi.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 
16 #include "access/htup_details.h"
17 #include "catalog/namespace.h"
18 #include "catalog/pg_proc.h"
19 #include "catalog/pg_type.h"
20 #include "funcapi.h"
21 #include "nodes/nodeFuncs.h"
22 #include "utils/array.h"
23 #include "utils/builtins.h"
24 #include "utils/lsyscache.h"
25 #include "utils/memutils.h"
26 #include "utils/regproc.h"
27 #include "utils/rel.h"
28 #include "utils/syscache.h"
29 #include "utils/typcache.h"
30 
31 
32 typedef struct polymorphic_actuals
33 {
34 	Oid			anyelement_type;	/* anyelement mapping, if known */
35 	Oid			anyarray_type;	/* anyarray mapping, if known */
36 	Oid			anyrange_type;	/* anyrange mapping, if known */
37 } polymorphic_actuals;
38 
39 static void shutdown_MultiFuncCall(Datum arg);
40 static TypeFuncClass internal_get_result_type(Oid funcid,
41 						 Node *call_expr,
42 						 ReturnSetInfo *rsinfo,
43 						 Oid *resultTypeId,
44 						 TupleDesc *resultTupleDesc);
45 static void resolve_anyelement_from_others(polymorphic_actuals *actuals);
46 static void resolve_anyarray_from_others(polymorphic_actuals *actuals);
47 static void resolve_anyrange_from_others(polymorphic_actuals *actuals);
48 static bool resolve_polymorphic_tupdesc(TupleDesc tupdesc,
49 							oidvector *declared_args,
50 							Node *call_expr);
51 static TypeFuncClass get_type_func_class(Oid typid);
52 
53 
54 /*
55  * init_MultiFuncCall
56  * Create an empty FuncCallContext data structure
57  * and do some other basic Multi-function call setup
58  * and error checking
59  */
60 FuncCallContext *
init_MultiFuncCall(PG_FUNCTION_ARGS)61 init_MultiFuncCall(PG_FUNCTION_ARGS)
62 {
63 	FuncCallContext *retval;
64 
65 	/*
66 	 * Bail if we're called in the wrong context
67 	 */
68 	if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo))
69 		ereport(ERROR,
70 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
71 				 errmsg("set-valued function called in context that cannot accept a set")));
72 
73 	if (fcinfo->flinfo->fn_extra == NULL)
74 	{
75 		/*
76 		 * First call
77 		 */
78 		ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
79 		MemoryContext multi_call_ctx;
80 
81 		/*
82 		 * Create a suitably long-lived context to hold cross-call data
83 		 */
84 		multi_call_ctx = AllocSetContextCreate(fcinfo->flinfo->fn_mcxt,
85 											   "SRF multi-call context",
86 											   ALLOCSET_SMALL_SIZES);
87 
88 		/*
89 		 * Allocate suitably long-lived space and zero it
90 		 */
91 		retval = (FuncCallContext *)
92 			MemoryContextAllocZero(multi_call_ctx,
93 								   sizeof(FuncCallContext));
94 
95 		/*
96 		 * initialize the elements
97 		 */
98 		retval->call_cntr = 0;
99 		retval->max_calls = 0;
100 		retval->slot = NULL;
101 		retval->user_fctx = NULL;
102 		retval->attinmeta = NULL;
103 		retval->tuple_desc = NULL;
104 		retval->multi_call_memory_ctx = multi_call_ctx;
105 
106 		/*
107 		 * save the pointer for cross-call use
108 		 */
109 		fcinfo->flinfo->fn_extra = retval;
110 
111 		/*
112 		 * Ensure we will get shut down cleanly if the exprcontext is not run
113 		 * to completion.
114 		 */
115 		RegisterExprContextCallback(rsi->econtext,
116 									shutdown_MultiFuncCall,
117 									PointerGetDatum(fcinfo->flinfo));
118 	}
119 	else
120 	{
121 		/* second and subsequent calls */
122 		elog(ERROR, "init_MultiFuncCall cannot be called more than once");
123 
124 		/* never reached, but keep compiler happy */
125 		retval = NULL;
126 	}
127 
128 	return retval;
129 }
130 
131 /*
132  * per_MultiFuncCall
133  *
134  * Do Multi-function per-call setup
135  */
136 FuncCallContext *
per_MultiFuncCall(PG_FUNCTION_ARGS)137 per_MultiFuncCall(PG_FUNCTION_ARGS)
138 {
139 	FuncCallContext *retval = (FuncCallContext *) fcinfo->flinfo->fn_extra;
140 
141 	/*
142 	 * Clear the TupleTableSlot, if present.  This is for safety's sake: the
143 	 * Slot will be in a long-lived context (it better be, if the
144 	 * FuncCallContext is pointing to it), but in most usage patterns the
145 	 * tuples stored in it will be in the function's per-tuple context. So at
146 	 * the beginning of each call, the Slot will hold a dangling pointer to an
147 	 * already-recycled tuple.  We clear it out here.
148 	 *
149 	 * Note: use of retval->slot is obsolete as of 8.0, and we expect that it
150 	 * will always be NULL.  This is just here for backwards compatibility in
151 	 * case someone creates a slot anyway.
152 	 */
153 	if (retval->slot != NULL)
154 		ExecClearTuple(retval->slot);
155 
156 	return retval;
157 }
158 
159 /*
160  * end_MultiFuncCall
161  * Clean up after init_MultiFuncCall
162  */
163 void
end_MultiFuncCall(PG_FUNCTION_ARGS,FuncCallContext * funcctx)164 end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
165 {
166 	ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
167 
168 	/* Deregister the shutdown callback */
169 	UnregisterExprContextCallback(rsi->econtext,
170 								  shutdown_MultiFuncCall,
171 								  PointerGetDatum(fcinfo->flinfo));
172 
173 	/* But use it to do the real work */
174 	shutdown_MultiFuncCall(PointerGetDatum(fcinfo->flinfo));
175 }
176 
177 /*
178  * shutdown_MultiFuncCall
179  * Shutdown function to clean up after init_MultiFuncCall
180  */
181 static void
shutdown_MultiFuncCall(Datum arg)182 shutdown_MultiFuncCall(Datum arg)
183 {
184 	FmgrInfo   *flinfo = (FmgrInfo *) DatumGetPointer(arg);
185 	FuncCallContext *funcctx = (FuncCallContext *) flinfo->fn_extra;
186 
187 	/* unbind from flinfo */
188 	flinfo->fn_extra = NULL;
189 
190 	/*
191 	 * Delete context that holds all multi-call data, including the
192 	 * FuncCallContext itself
193 	 */
194 	MemoryContextDelete(funcctx->multi_call_memory_ctx);
195 }
196 
197 
198 /*
199  * get_call_result_type
200  *		Given a function's call info record, determine the kind of datatype
201  *		it is supposed to return.  If resultTypeId isn't NULL, *resultTypeId
202  *		receives the actual datatype OID (this is mainly useful for scalar
203  *		result types).  If resultTupleDesc isn't NULL, *resultTupleDesc
204  *		receives a pointer to a TupleDesc when the result is of a composite
205  *		type, or NULL when it's a scalar result.
206  *
207  * One hard case that this handles is resolution of actual rowtypes for
208  * functions returning RECORD (from either the function's OUT parameter
209  * list, or a ReturnSetInfo context node).  TYPEFUNC_RECORD is returned
210  * only when we couldn't resolve the actual rowtype for lack of information.
211  *
212  * The other hard case that this handles is resolution of polymorphism.
213  * We will never return polymorphic pseudotypes (ANYELEMENT etc), either
214  * as a scalar result type or as a component of a rowtype.
215  *
216  * This function is relatively expensive --- in a function returning set,
217  * try to call it only the first time through.
218  */
219 TypeFuncClass
get_call_result_type(FunctionCallInfo fcinfo,Oid * resultTypeId,TupleDesc * resultTupleDesc)220 get_call_result_type(FunctionCallInfo fcinfo,
221 					 Oid *resultTypeId,
222 					 TupleDesc *resultTupleDesc)
223 {
224 	return internal_get_result_type(fcinfo->flinfo->fn_oid,
225 									fcinfo->flinfo->fn_expr,
226 									(ReturnSetInfo *) fcinfo->resultinfo,
227 									resultTypeId,
228 									resultTupleDesc);
229 }
230 
231 /*
232  * get_expr_result_type
233  *		As above, but work from a calling expression node tree
234  */
235 TypeFuncClass
get_expr_result_type(Node * expr,Oid * resultTypeId,TupleDesc * resultTupleDesc)236 get_expr_result_type(Node *expr,
237 					 Oid *resultTypeId,
238 					 TupleDesc *resultTupleDesc)
239 {
240 	TypeFuncClass result;
241 
242 	if (expr && IsA(expr, FuncExpr))
243 		result = internal_get_result_type(((FuncExpr *) expr)->funcid,
244 										  expr,
245 										  NULL,
246 										  resultTypeId,
247 										  resultTupleDesc);
248 	else if (expr && IsA(expr, OpExpr))
249 		result = internal_get_result_type(get_opcode(((OpExpr *) expr)->opno),
250 										  expr,
251 										  NULL,
252 										  resultTypeId,
253 										  resultTupleDesc);
254 	else
255 	{
256 		/* handle as a generic expression; no chance to resolve RECORD */
257 		Oid			typid = exprType(expr);
258 
259 		if (resultTypeId)
260 			*resultTypeId = typid;
261 		if (resultTupleDesc)
262 			*resultTupleDesc = NULL;
263 		result = get_type_func_class(typid);
264 		if (result == TYPEFUNC_COMPOSITE && resultTupleDesc)
265 			*resultTupleDesc = lookup_rowtype_tupdesc_copy(typid, -1);
266 	}
267 
268 	return result;
269 }
270 
271 /*
272  * get_func_result_type
273  *		As above, but work from a function's OID only
274  *
275  * This will not be able to resolve pure-RECORD results nor polymorphism.
276  */
277 TypeFuncClass
get_func_result_type(Oid functionId,Oid * resultTypeId,TupleDesc * resultTupleDesc)278 get_func_result_type(Oid functionId,
279 					 Oid *resultTypeId,
280 					 TupleDesc *resultTupleDesc)
281 {
282 	return internal_get_result_type(functionId,
283 									NULL,
284 									NULL,
285 									resultTypeId,
286 									resultTupleDesc);
287 }
288 
289 /*
290  * internal_get_result_type -- workhorse code implementing all the above
291  *
292  * funcid must always be supplied.  call_expr and rsinfo can be NULL if not
293  * available.  We will return TYPEFUNC_RECORD, and store NULL into
294  * *resultTupleDesc, if we cannot deduce the complete result rowtype from
295  * the available information.
296  */
297 static TypeFuncClass
internal_get_result_type(Oid funcid,Node * call_expr,ReturnSetInfo * rsinfo,Oid * resultTypeId,TupleDesc * resultTupleDesc)298 internal_get_result_type(Oid funcid,
299 						 Node *call_expr,
300 						 ReturnSetInfo *rsinfo,
301 						 Oid *resultTypeId,
302 						 TupleDesc *resultTupleDesc)
303 {
304 	TypeFuncClass result;
305 	HeapTuple	tp;
306 	Form_pg_proc procform;
307 	Oid			rettype;
308 	TupleDesc	tupdesc;
309 
310 	/* First fetch the function's pg_proc row to inspect its rettype */
311 	tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
312 	if (!HeapTupleIsValid(tp))
313 		elog(ERROR, "cache lookup failed for function %u", funcid);
314 	procform = (Form_pg_proc) GETSTRUCT(tp);
315 
316 	rettype = procform->prorettype;
317 
318 	/* Check for OUT parameters defining a RECORD result */
319 	tupdesc = build_function_result_tupdesc_t(tp);
320 	if (tupdesc)
321 	{
322 		/*
323 		 * It has OUT parameters, so it's basically like a regular composite
324 		 * type, except we have to be able to resolve any polymorphic OUT
325 		 * parameters.
326 		 */
327 		if (resultTypeId)
328 			*resultTypeId = rettype;
329 
330 		if (resolve_polymorphic_tupdesc(tupdesc,
331 										&procform->proargtypes,
332 										call_expr))
333 		{
334 			if (tupdesc->tdtypeid == RECORDOID &&
335 				tupdesc->tdtypmod < 0)
336 				assign_record_type_typmod(tupdesc);
337 			if (resultTupleDesc)
338 				*resultTupleDesc = tupdesc;
339 			result = TYPEFUNC_COMPOSITE;
340 		}
341 		else
342 		{
343 			if (resultTupleDesc)
344 				*resultTupleDesc = NULL;
345 			result = TYPEFUNC_RECORD;
346 		}
347 
348 		ReleaseSysCache(tp);
349 
350 		return result;
351 	}
352 
353 	/*
354 	 * If scalar polymorphic result, try to resolve it.
355 	 */
356 	if (IsPolymorphicType(rettype))
357 	{
358 		Oid			newrettype = exprType(call_expr);
359 
360 		if (newrettype == InvalidOid)	/* this probably should not happen */
361 			ereport(ERROR,
362 					(errcode(ERRCODE_DATATYPE_MISMATCH),
363 					 errmsg("could not determine actual result type for function \"%s\" declared to return type %s",
364 							NameStr(procform->proname),
365 							format_type_be(rettype))));
366 		rettype = newrettype;
367 	}
368 
369 	if (resultTypeId)
370 		*resultTypeId = rettype;
371 	if (resultTupleDesc)
372 		*resultTupleDesc = NULL;	/* default result */
373 
374 	/* Classify the result type */
375 	result = get_type_func_class(rettype);
376 	switch (result)
377 	{
378 		case TYPEFUNC_COMPOSITE:
379 			if (resultTupleDesc)
380 				*resultTupleDesc = lookup_rowtype_tupdesc_copy(rettype, -1);
381 			/* Named composite types can't have any polymorphic columns */
382 			break;
383 		case TYPEFUNC_SCALAR:
384 			break;
385 		case TYPEFUNC_RECORD:
386 			/* We must get the tupledesc from call context */
387 			if (rsinfo && IsA(rsinfo, ReturnSetInfo) &&
388 				rsinfo->expectedDesc != NULL)
389 			{
390 				result = TYPEFUNC_COMPOSITE;
391 				if (resultTupleDesc)
392 					*resultTupleDesc = rsinfo->expectedDesc;
393 				/* Assume no polymorphic columns here, either */
394 			}
395 			break;
396 		default:
397 			break;
398 	}
399 
400 	ReleaseSysCache(tp);
401 
402 	return result;
403 }
404 
405 /*
406  * Resolve actual type of ANYELEMENT from other polymorphic inputs
407  *
408  * Note: the error cases here and in the sibling functions below are not
409  * really user-facing; they could only occur if the function signature is
410  * incorrect or the parser failed to enforce consistency of the actual
411  * argument types.  Hence, we don't sweat too much over the error messages.
412  */
413 static void
resolve_anyelement_from_others(polymorphic_actuals * actuals)414 resolve_anyelement_from_others(polymorphic_actuals *actuals)
415 {
416 	if (OidIsValid(actuals->anyarray_type))
417 	{
418 		/* Use the element type corresponding to actual type */
419 		Oid			array_base_type = getBaseType(actuals->anyarray_type);
420 		Oid			array_typelem = get_element_type(array_base_type);
421 
422 		if (!OidIsValid(array_typelem))
423 			ereport(ERROR,
424 					(errcode(ERRCODE_DATATYPE_MISMATCH),
425 					 errmsg("argument declared %s is not an array but type %s",
426 							"anyarray",
427 							format_type_be(array_base_type))));
428 		actuals->anyelement_type = array_typelem;
429 	}
430 	else if (OidIsValid(actuals->anyrange_type))
431 	{
432 		/* Use the element type corresponding to actual type */
433 		Oid			range_base_type = getBaseType(actuals->anyrange_type);
434 		Oid			range_typelem = get_range_subtype(range_base_type);
435 
436 		if (!OidIsValid(range_typelem))
437 			ereport(ERROR,
438 					(errcode(ERRCODE_DATATYPE_MISMATCH),
439 					 errmsg("argument declared %s is not a range type but type %s",
440 							"anyrange",
441 							format_type_be(range_base_type))));
442 		actuals->anyelement_type = range_typelem;
443 	}
444 	else
445 		elog(ERROR, "could not determine polymorphic type");
446 }
447 
448 /*
449  * Resolve actual type of ANYARRAY from other polymorphic inputs
450  */
451 static void
resolve_anyarray_from_others(polymorphic_actuals * actuals)452 resolve_anyarray_from_others(polymorphic_actuals *actuals)
453 {
454 	/* If we don't know ANYELEMENT, resolve that first */
455 	if (!OidIsValid(actuals->anyelement_type))
456 		resolve_anyelement_from_others(actuals);
457 
458 	if (OidIsValid(actuals->anyelement_type))
459 	{
460 		/* Use the array type corresponding to actual type */
461 		Oid			array_typeid = get_array_type(actuals->anyelement_type);
462 
463 		if (!OidIsValid(array_typeid))
464 			ereport(ERROR,
465 					(errcode(ERRCODE_UNDEFINED_OBJECT),
466 					 errmsg("could not find array type for data type %s",
467 							format_type_be(actuals->anyelement_type))));
468 		actuals->anyarray_type = array_typeid;
469 	}
470 	else
471 		elog(ERROR, "could not determine polymorphic type");
472 }
473 
474 /*
475  * Resolve actual type of ANYRANGE from other polymorphic inputs
476  */
477 static void
resolve_anyrange_from_others(polymorphic_actuals * actuals)478 resolve_anyrange_from_others(polymorphic_actuals *actuals)
479 {
480 	/*
481 	 * We can't deduce a range type from other polymorphic inputs, because
482 	 * there may be multiple range types with the same subtype.
483 	 */
484 	elog(ERROR, "could not determine polymorphic type");
485 }
486 
487 /*
488  * Given the result tuple descriptor for a function with OUT parameters,
489  * replace any polymorphic column types (ANYELEMENT etc) in the tupdesc
490  * with concrete data types deduced from the input arguments.
491  * declared_args is an oidvector of the function's declared input arg types
492  * (showing which are polymorphic), and call_expr is the call expression.
493  * Returns true if able to deduce all types, false if not.
494  */
495 static bool
resolve_polymorphic_tupdesc(TupleDesc tupdesc,oidvector * declared_args,Node * call_expr)496 resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
497 							Node *call_expr)
498 {
499 	int			natts = tupdesc->natts;
500 	int			nargs = declared_args->dim1;
501 	bool		have_polymorphic_result = false;
502 	bool		have_anyelement_result = false;
503 	bool		have_anyarray_result = false;
504 	bool		have_anyrange_result = false;
505 	polymorphic_actuals poly_actuals;
506 	Oid			anycollation = InvalidOid;
507 	int			i;
508 
509 	/* See if there are any polymorphic outputs; quick out if not */
510 	for (i = 0; i < natts; i++)
511 	{
512 		switch (tupdesc->attrs[i]->atttypid)
513 		{
514 			case ANYELEMENTOID:
515 			case ANYNONARRAYOID:
516 			case ANYENUMOID:
517 				have_polymorphic_result = true;
518 				have_anyelement_result = true;
519 				break;
520 			case ANYARRAYOID:
521 				have_polymorphic_result = true;
522 				have_anyarray_result = true;
523 				break;
524 			case ANYRANGEOID:
525 				have_polymorphic_result = true;
526 				have_anyrange_result = true;
527 				break;
528 			default:
529 				break;
530 		}
531 	}
532 	if (!have_polymorphic_result)
533 		return true;
534 
535 	/*
536 	 * Otherwise, extract actual datatype(s) from input arguments.  (We assume
537 	 * the parser already validated consistency of the arguments.)
538 	 */
539 	if (!call_expr)
540 		return false;			/* no hope */
541 
542 	memset(&poly_actuals, 0, sizeof(poly_actuals));
543 
544 	for (i = 0; i < nargs; i++)
545 	{
546 		switch (declared_args->values[i])
547 		{
548 			case ANYELEMENTOID:
549 			case ANYNONARRAYOID:
550 			case ANYENUMOID:
551 				if (!OidIsValid(poly_actuals.anyelement_type))
552 				{
553 					poly_actuals.anyelement_type =
554 						get_call_expr_argtype(call_expr, i);
555 					if (!OidIsValid(poly_actuals.anyelement_type))
556 						return false;
557 				}
558 				break;
559 			case ANYARRAYOID:
560 				if (!OidIsValid(poly_actuals.anyarray_type))
561 				{
562 					poly_actuals.anyarray_type =
563 						get_call_expr_argtype(call_expr, i);
564 					if (!OidIsValid(poly_actuals.anyarray_type))
565 						return false;
566 				}
567 				break;
568 			case ANYRANGEOID:
569 				if (!OidIsValid(poly_actuals.anyrange_type))
570 				{
571 					poly_actuals.anyrange_type =
572 						get_call_expr_argtype(call_expr, i);
573 					if (!OidIsValid(poly_actuals.anyrange_type))
574 						return false;
575 				}
576 				break;
577 			default:
578 				break;
579 		}
580 	}
581 
582 	/* If needed, deduce one polymorphic type from others */
583 	if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
584 		resolve_anyelement_from_others(&poly_actuals);
585 
586 	if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
587 		resolve_anyarray_from_others(&poly_actuals);
588 
589 	if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
590 		resolve_anyrange_from_others(&poly_actuals);
591 
592 	/*
593 	 * Identify the collation to use for polymorphic OUT parameters. (It'll
594 	 * necessarily be the same for both anyelement and anyarray.)  Note that
595 	 * range types are not collatable, so any possible internal collation of a
596 	 * range type is not considered here.
597 	 */
598 	if (OidIsValid(poly_actuals.anyelement_type))
599 		anycollation = get_typcollation(poly_actuals.anyelement_type);
600 	else if (OidIsValid(poly_actuals.anyarray_type))
601 		anycollation = get_typcollation(poly_actuals.anyarray_type);
602 
603 	if (OidIsValid(anycollation))
604 	{
605 		/*
606 		 * The types are collatable, so consider whether to use a nondefault
607 		 * collation.  We do so if we can identify the input collation used
608 		 * for the function.
609 		 */
610 		Oid			inputcollation = exprInputCollation(call_expr);
611 
612 		if (OidIsValid(inputcollation))
613 			anycollation = inputcollation;
614 	}
615 
616 	/* And finally replace the tuple column types as needed */
617 	for (i = 0; i < natts; i++)
618 	{
619 		Form_pg_attribute att = tupdesc->attrs[i];
620 
621 		switch (att->atttypid)
622 		{
623 			case ANYELEMENTOID:
624 			case ANYNONARRAYOID:
625 			case ANYENUMOID:
626 				TupleDescInitEntry(tupdesc, i + 1,
627 								   NameStr(att->attname),
628 								   poly_actuals.anyelement_type,
629 								   -1,
630 								   0);
631 				TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
632 				break;
633 			case ANYARRAYOID:
634 				TupleDescInitEntry(tupdesc, i + 1,
635 								   NameStr(att->attname),
636 								   poly_actuals.anyarray_type,
637 								   -1,
638 								   0);
639 				TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
640 				break;
641 			case ANYRANGEOID:
642 				TupleDescInitEntry(tupdesc, i + 1,
643 								   NameStr(att->attname),
644 								   poly_actuals.anyrange_type,
645 								   -1,
646 								   0);
647 				/* no collation should be attached to a range type */
648 				break;
649 			default:
650 				break;
651 		}
652 	}
653 
654 	return true;
655 }
656 
657 /*
658  * Given the declared argument types and modes for a function, replace any
659  * polymorphic types (ANYELEMENT etc) in argtypes[] with concrete data types
660  * deduced from the input arguments found in call_expr.
661  * Returns true if able to deduce all types, false if not.
662  *
663  * This is the same logic as resolve_polymorphic_tupdesc, but with a different
664  * argument representation, and slightly different output responsibilities.
665  *
666  * argmodes may be NULL, in which case all arguments are assumed to be IN mode.
667  */
668 bool
resolve_polymorphic_argtypes(int numargs,Oid * argtypes,char * argmodes,Node * call_expr)669 resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
670 							 Node *call_expr)
671 {
672 	bool		have_polymorphic_result = false;
673 	bool		have_anyelement_result = false;
674 	bool		have_anyarray_result = false;
675 	bool		have_anyrange_result = false;
676 	polymorphic_actuals poly_actuals;
677 	int			inargno;
678 	int			i;
679 
680 	/*
681 	 * First pass: resolve polymorphic inputs, check for outputs.  As in
682 	 * resolve_polymorphic_tupdesc, we rely on the parser to have enforced
683 	 * type consistency.
684 	 */
685 	memset(&poly_actuals, 0, sizeof(poly_actuals));
686 	inargno = 0;
687 	for (i = 0; i < numargs; i++)
688 	{
689 		char		argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
690 
691 		switch (argtypes[i])
692 		{
693 			case ANYELEMENTOID:
694 			case ANYNONARRAYOID:
695 			case ANYENUMOID:
696 				if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
697 				{
698 					have_polymorphic_result = true;
699 					have_anyelement_result = true;
700 				}
701 				else
702 				{
703 					if (!OidIsValid(poly_actuals.anyelement_type))
704 					{
705 						poly_actuals.anyelement_type =
706 							get_call_expr_argtype(call_expr, inargno);
707 						if (!OidIsValid(poly_actuals.anyelement_type))
708 							return false;
709 					}
710 					argtypes[i] = poly_actuals.anyelement_type;
711 				}
712 				break;
713 			case ANYARRAYOID:
714 				if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
715 				{
716 					have_polymorphic_result = true;
717 					have_anyarray_result = true;
718 				}
719 				else
720 				{
721 					if (!OidIsValid(poly_actuals.anyarray_type))
722 					{
723 						poly_actuals.anyarray_type =
724 							get_call_expr_argtype(call_expr, inargno);
725 						if (!OidIsValid(poly_actuals.anyarray_type))
726 							return false;
727 					}
728 					argtypes[i] = poly_actuals.anyarray_type;
729 				}
730 				break;
731 			case ANYRANGEOID:
732 				if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
733 				{
734 					have_polymorphic_result = true;
735 					have_anyrange_result = true;
736 				}
737 				else
738 				{
739 					if (!OidIsValid(poly_actuals.anyrange_type))
740 					{
741 						poly_actuals.anyrange_type =
742 							get_call_expr_argtype(call_expr, inargno);
743 						if (!OidIsValid(poly_actuals.anyrange_type))
744 							return false;
745 					}
746 					argtypes[i] = poly_actuals.anyrange_type;
747 				}
748 				break;
749 			default:
750 				break;
751 		}
752 		if (argmode != PROARGMODE_OUT && argmode != PROARGMODE_TABLE)
753 			inargno++;
754 	}
755 
756 	/* Done? */
757 	if (!have_polymorphic_result)
758 		return true;
759 
760 	/* If needed, deduce one polymorphic type from others */
761 	if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
762 		resolve_anyelement_from_others(&poly_actuals);
763 
764 	if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
765 		resolve_anyarray_from_others(&poly_actuals);
766 
767 	if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
768 		resolve_anyrange_from_others(&poly_actuals);
769 
770 	/* And finally replace the output column types as needed */
771 	for (i = 0; i < numargs; i++)
772 	{
773 		switch (argtypes[i])
774 		{
775 			case ANYELEMENTOID:
776 			case ANYNONARRAYOID:
777 			case ANYENUMOID:
778 				argtypes[i] = poly_actuals.anyelement_type;
779 				break;
780 			case ANYARRAYOID:
781 				argtypes[i] = poly_actuals.anyarray_type;
782 				break;
783 			case ANYRANGEOID:
784 				argtypes[i] = poly_actuals.anyrange_type;
785 				break;
786 			default:
787 				break;
788 		}
789 	}
790 
791 	return true;
792 }
793 
794 /*
795  * get_type_func_class
796  *		Given the type OID, obtain its TYPEFUNC classification.
797  *
798  * This is intended to centralize a bunch of formerly ad-hoc code for
799  * classifying types.  The categories used here are useful for deciding
800  * how to handle functions returning the datatype.
801  */
802 static TypeFuncClass
get_type_func_class(Oid typid)803 get_type_func_class(Oid typid)
804 {
805 	switch (get_typtype(typid))
806 	{
807 		case TYPTYPE_COMPOSITE:
808 			return TYPEFUNC_COMPOSITE;
809 		case TYPTYPE_BASE:
810 		case TYPTYPE_DOMAIN:
811 		case TYPTYPE_ENUM:
812 		case TYPTYPE_RANGE:
813 			return TYPEFUNC_SCALAR;
814 		case TYPTYPE_PSEUDO:
815 			if (typid == RECORDOID)
816 				return TYPEFUNC_RECORD;
817 
818 			/*
819 			 * We treat VOID and CSTRING as legitimate scalar datatypes,
820 			 * mostly for the convenience of the JDBC driver (which wants to
821 			 * be able to do "SELECT * FROM foo()" for all legitimately
822 			 * user-callable functions).
823 			 */
824 			if (typid == VOIDOID || typid == CSTRINGOID)
825 				return TYPEFUNC_SCALAR;
826 			return TYPEFUNC_OTHER;
827 	}
828 	/* shouldn't get here, probably */
829 	return TYPEFUNC_OTHER;
830 }
831 
832 
833 /*
834  * get_func_arg_info
835  *
836  * Fetch info about the argument types, names, and IN/OUT modes from the
837  * pg_proc tuple.  Return value is the total number of arguments.
838  * Other results are palloc'd.  *p_argtypes is always filled in, but
839  * *p_argnames and *p_argmodes will be set NULL in the default cases
840  * (no names, and all IN arguments, respectively).
841  *
842  * Note that this function simply fetches what is in the pg_proc tuple;
843  * it doesn't do any interpretation of polymorphic types.
844  */
845 int
get_func_arg_info(HeapTuple procTup,Oid ** p_argtypes,char *** p_argnames,char ** p_argmodes)846 get_func_arg_info(HeapTuple procTup,
847 				  Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
848 {
849 	Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
850 	Datum		proallargtypes;
851 	Datum		proargmodes;
852 	Datum		proargnames;
853 	bool		isNull;
854 	ArrayType  *arr;
855 	int			numargs;
856 	Datum	   *elems;
857 	int			nelems;
858 	int			i;
859 
860 	/* First discover the total number of parameters and get their types */
861 	proallargtypes = SysCacheGetAttr(PROCOID, procTup,
862 									 Anum_pg_proc_proallargtypes,
863 									 &isNull);
864 	if (!isNull)
865 	{
866 		/*
867 		 * We expect the arrays to be 1-D arrays of the right types; verify
868 		 * that.  For the OID and char arrays, we don't need to use
869 		 * deconstruct_array() since the array data is just going to look like
870 		 * a C array of values.
871 		 */
872 		arr = DatumGetArrayTypeP(proallargtypes);	/* ensure not toasted */
873 		numargs = ARR_DIMS(arr)[0];
874 		if (ARR_NDIM(arr) != 1 ||
875 			numargs < 0 ||
876 			ARR_HASNULL(arr) ||
877 			ARR_ELEMTYPE(arr) != OIDOID)
878 			elog(ERROR, "proallargtypes is not a 1-D Oid array");
879 		Assert(numargs >= procStruct->pronargs);
880 		*p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
881 		memcpy(*p_argtypes, ARR_DATA_PTR(arr),
882 			   numargs * sizeof(Oid));
883 	}
884 	else
885 	{
886 		/* If no proallargtypes, use proargtypes */
887 		numargs = procStruct->proargtypes.dim1;
888 		Assert(numargs == procStruct->pronargs);
889 		*p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
890 		memcpy(*p_argtypes, procStruct->proargtypes.values,
891 			   numargs * sizeof(Oid));
892 	}
893 
894 	/* Get argument names, if available */
895 	proargnames = SysCacheGetAttr(PROCOID, procTup,
896 								  Anum_pg_proc_proargnames,
897 								  &isNull);
898 	if (isNull)
899 		*p_argnames = NULL;
900 	else
901 	{
902 		deconstruct_array(DatumGetArrayTypeP(proargnames),
903 						  TEXTOID, -1, false, 'i',
904 						  &elems, NULL, &nelems);
905 		if (nelems != numargs)	/* should not happen */
906 			elog(ERROR, "proargnames must have the same number of elements as the function has arguments");
907 		*p_argnames = (char **) palloc(sizeof(char *) * numargs);
908 		for (i = 0; i < numargs; i++)
909 			(*p_argnames)[i] = TextDatumGetCString(elems[i]);
910 	}
911 
912 	/* Get argument modes, if available */
913 	proargmodes = SysCacheGetAttr(PROCOID, procTup,
914 								  Anum_pg_proc_proargmodes,
915 								  &isNull);
916 	if (isNull)
917 		*p_argmodes = NULL;
918 	else
919 	{
920 		arr = DatumGetArrayTypeP(proargmodes);	/* ensure not toasted */
921 		if (ARR_NDIM(arr) != 1 ||
922 			ARR_DIMS(arr)[0] != numargs ||
923 			ARR_HASNULL(arr) ||
924 			ARR_ELEMTYPE(arr) != CHAROID)
925 			elog(ERROR, "proargmodes is not a 1-D char array");
926 		*p_argmodes = (char *) palloc(numargs * sizeof(char));
927 		memcpy(*p_argmodes, ARR_DATA_PTR(arr),
928 			   numargs * sizeof(char));
929 	}
930 
931 	return numargs;
932 }
933 
934 /*
935  * get_func_trftypes
936  *
937  * Returns the number of transformed types used by the function.
938  * If there are any, a palloc'd array of the type OIDs is returned
939  * into *p_trftypes.
940  */
941 int
get_func_trftypes(HeapTuple procTup,Oid ** p_trftypes)942 get_func_trftypes(HeapTuple procTup,
943 				  Oid **p_trftypes)
944 {
945 	Datum		protrftypes;
946 	ArrayType  *arr;
947 	int			nelems;
948 	bool		isNull;
949 
950 	protrftypes = SysCacheGetAttr(PROCOID, procTup,
951 								  Anum_pg_proc_protrftypes,
952 								  &isNull);
953 	if (!isNull)
954 	{
955 		/*
956 		 * We expect the arrays to be 1-D arrays of the right types; verify
957 		 * that.  For the OID and char arrays, we don't need to use
958 		 * deconstruct_array() since the array data is just going to look like
959 		 * a C array of values.
960 		 */
961 		arr = DatumGetArrayTypeP(protrftypes);	/* ensure not toasted */
962 		nelems = ARR_DIMS(arr)[0];
963 		if (ARR_NDIM(arr) != 1 ||
964 			nelems < 0 ||
965 			ARR_HASNULL(arr) ||
966 			ARR_ELEMTYPE(arr) != OIDOID)
967 			elog(ERROR, "protrftypes is not a 1-D Oid array");
968 		*p_trftypes = (Oid *) palloc(nelems * sizeof(Oid));
969 		memcpy(*p_trftypes, ARR_DATA_PTR(arr),
970 			   nelems * sizeof(Oid));
971 
972 		return nelems;
973 	}
974 	else
975 		return 0;
976 }
977 
978 /*
979  * get_func_input_arg_names
980  *
981  * Extract the names of input arguments only, given a function's
982  * proargnames and proargmodes entries in Datum form.
983  *
984  * Returns the number of input arguments, which is the length of the
985  * palloc'd array returned to *arg_names.  Entries for unnamed args
986  * are set to NULL.  You don't get anything if proargnames is NULL.
987  */
988 int
get_func_input_arg_names(Datum proargnames,Datum proargmodes,char *** arg_names)989 get_func_input_arg_names(Datum proargnames, Datum proargmodes,
990 						 char ***arg_names)
991 {
992 	ArrayType  *arr;
993 	int			numargs;
994 	Datum	   *argnames;
995 	char	   *argmodes;
996 	char	  **inargnames;
997 	int			numinargs;
998 	int			i;
999 
1000 	/* Do nothing if null proargnames */
1001 	if (proargnames == PointerGetDatum(NULL))
1002 	{
1003 		*arg_names = NULL;
1004 		return 0;
1005 	}
1006 
1007 	/*
1008 	 * We expect the arrays to be 1-D arrays of the right types; verify that.
1009 	 * For proargmodes, we don't need to use deconstruct_array() since the
1010 	 * array data is just going to look like a C array of values.
1011 	 */
1012 	arr = DatumGetArrayTypeP(proargnames);	/* ensure not toasted */
1013 	if (ARR_NDIM(arr) != 1 ||
1014 		ARR_HASNULL(arr) ||
1015 		ARR_ELEMTYPE(arr) != TEXTOID)
1016 		elog(ERROR, "proargnames is not a 1-D text array");
1017 	deconstruct_array(arr, TEXTOID, -1, false, 'i',
1018 					  &argnames, NULL, &numargs);
1019 	if (proargmodes != PointerGetDatum(NULL))
1020 	{
1021 		arr = DatumGetArrayTypeP(proargmodes);	/* ensure not toasted */
1022 		if (ARR_NDIM(arr) != 1 ||
1023 			ARR_DIMS(arr)[0] != numargs ||
1024 			ARR_HASNULL(arr) ||
1025 			ARR_ELEMTYPE(arr) != CHAROID)
1026 			elog(ERROR, "proargmodes is not a 1-D char array");
1027 		argmodes = (char *) ARR_DATA_PTR(arr);
1028 	}
1029 	else
1030 		argmodes = NULL;
1031 
1032 	/* zero elements probably shouldn't happen, but handle it gracefully */
1033 	if (numargs <= 0)
1034 	{
1035 		*arg_names = NULL;
1036 		return 0;
1037 	}
1038 
1039 	/* extract input-argument names */
1040 	inargnames = (char **) palloc(numargs * sizeof(char *));
1041 	numinargs = 0;
1042 	for (i = 0; i < numargs; i++)
1043 	{
1044 		if (argmodes == NULL ||
1045 			argmodes[i] == PROARGMODE_IN ||
1046 			argmodes[i] == PROARGMODE_INOUT ||
1047 			argmodes[i] == PROARGMODE_VARIADIC)
1048 		{
1049 			char	   *pname = TextDatumGetCString(argnames[i]);
1050 
1051 			if (pname[0] != '\0')
1052 				inargnames[numinargs] = pname;
1053 			else
1054 				inargnames[numinargs] = NULL;
1055 			numinargs++;
1056 		}
1057 	}
1058 
1059 	*arg_names = inargnames;
1060 	return numinargs;
1061 }
1062 
1063 
1064 /*
1065  * get_func_result_name
1066  *
1067  * If the function has exactly one output parameter, and that parameter
1068  * is named, return the name (as a palloc'd string).  Else return NULL.
1069  *
1070  * This is used to determine the default output column name for functions
1071  * returning scalar types.
1072  */
1073 char *
get_func_result_name(Oid functionId)1074 get_func_result_name(Oid functionId)
1075 {
1076 	char	   *result;
1077 	HeapTuple	procTuple;
1078 	Datum		proargmodes;
1079 	Datum		proargnames;
1080 	bool		isnull;
1081 	ArrayType  *arr;
1082 	int			numargs;
1083 	char	   *argmodes;
1084 	Datum	   *argnames;
1085 	int			numoutargs;
1086 	int			nargnames;
1087 	int			i;
1088 
1089 	/* First fetch the function's pg_proc row */
1090 	procTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
1091 	if (!HeapTupleIsValid(procTuple))
1092 		elog(ERROR, "cache lookup failed for function %u", functionId);
1093 
1094 	/* If there are no named OUT parameters, return NULL */
1095 	if (heap_attisnull(procTuple, Anum_pg_proc_proargmodes) ||
1096 		heap_attisnull(procTuple, Anum_pg_proc_proargnames))
1097 		result = NULL;
1098 	else
1099 	{
1100 		/* Get the data out of the tuple */
1101 		proargmodes = SysCacheGetAttr(PROCOID, procTuple,
1102 									  Anum_pg_proc_proargmodes,
1103 									  &isnull);
1104 		Assert(!isnull);
1105 		proargnames = SysCacheGetAttr(PROCOID, procTuple,
1106 									  Anum_pg_proc_proargnames,
1107 									  &isnull);
1108 		Assert(!isnull);
1109 
1110 		/*
1111 		 * We expect the arrays to be 1-D arrays of the right types; verify
1112 		 * that.  For the char array, we don't need to use deconstruct_array()
1113 		 * since the array data is just going to look like a C array of
1114 		 * values.
1115 		 */
1116 		arr = DatumGetArrayTypeP(proargmodes);	/* ensure not toasted */
1117 		numargs = ARR_DIMS(arr)[0];
1118 		if (ARR_NDIM(arr) != 1 ||
1119 			numargs < 0 ||
1120 			ARR_HASNULL(arr) ||
1121 			ARR_ELEMTYPE(arr) != CHAROID)
1122 			elog(ERROR, "proargmodes is not a 1-D char array");
1123 		argmodes = (char *) ARR_DATA_PTR(arr);
1124 		arr = DatumGetArrayTypeP(proargnames);	/* ensure not toasted */
1125 		if (ARR_NDIM(arr) != 1 ||
1126 			ARR_DIMS(arr)[0] != numargs ||
1127 			ARR_HASNULL(arr) ||
1128 			ARR_ELEMTYPE(arr) != TEXTOID)
1129 			elog(ERROR, "proargnames is not a 1-D text array");
1130 		deconstruct_array(arr, TEXTOID, -1, false, 'i',
1131 						  &argnames, NULL, &nargnames);
1132 		Assert(nargnames == numargs);
1133 
1134 		/* scan for output argument(s) */
1135 		result = NULL;
1136 		numoutargs = 0;
1137 		for (i = 0; i < numargs; i++)
1138 		{
1139 			if (argmodes[i] == PROARGMODE_IN ||
1140 				argmodes[i] == PROARGMODE_VARIADIC)
1141 				continue;
1142 			Assert(argmodes[i] == PROARGMODE_OUT ||
1143 				   argmodes[i] == PROARGMODE_INOUT ||
1144 				   argmodes[i] == PROARGMODE_TABLE);
1145 			if (++numoutargs > 1)
1146 			{
1147 				/* multiple out args, so forget it */
1148 				result = NULL;
1149 				break;
1150 			}
1151 			result = TextDatumGetCString(argnames[i]);
1152 			if (result == NULL || result[0] == '\0')
1153 			{
1154 				/* Parameter is not named, so forget it */
1155 				result = NULL;
1156 				break;
1157 			}
1158 		}
1159 	}
1160 
1161 	ReleaseSysCache(procTuple);
1162 
1163 	return result;
1164 }
1165 
1166 
1167 /*
1168  * build_function_result_tupdesc_t
1169  *
1170  * Given a pg_proc row for a function, return a tuple descriptor for the
1171  * result rowtype, or NULL if the function does not have OUT parameters.
1172  *
1173  * Note that this does not handle resolution of polymorphic types;
1174  * that is deliberate.
1175  */
1176 TupleDesc
build_function_result_tupdesc_t(HeapTuple procTuple)1177 build_function_result_tupdesc_t(HeapTuple procTuple)
1178 {
1179 	Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(procTuple);
1180 	Datum		proallargtypes;
1181 	Datum		proargmodes;
1182 	Datum		proargnames;
1183 	bool		isnull;
1184 
1185 	/* Return NULL if the function isn't declared to return RECORD */
1186 	if (procform->prorettype != RECORDOID)
1187 		return NULL;
1188 
1189 	/* If there are no OUT parameters, return NULL */
1190 	if (heap_attisnull(procTuple, Anum_pg_proc_proallargtypes) ||
1191 		heap_attisnull(procTuple, Anum_pg_proc_proargmodes))
1192 		return NULL;
1193 
1194 	/* Get the data out of the tuple */
1195 	proallargtypes = SysCacheGetAttr(PROCOID, procTuple,
1196 									 Anum_pg_proc_proallargtypes,
1197 									 &isnull);
1198 	Assert(!isnull);
1199 	proargmodes = SysCacheGetAttr(PROCOID, procTuple,
1200 								  Anum_pg_proc_proargmodes,
1201 								  &isnull);
1202 	Assert(!isnull);
1203 	proargnames = SysCacheGetAttr(PROCOID, procTuple,
1204 								  Anum_pg_proc_proargnames,
1205 								  &isnull);
1206 	if (isnull)
1207 		proargnames = PointerGetDatum(NULL);	/* just to be sure */
1208 
1209 	return build_function_result_tupdesc_d(proallargtypes,
1210 										   proargmodes,
1211 										   proargnames);
1212 }
1213 
1214 /*
1215  * build_function_result_tupdesc_d
1216  *
1217  * Build a RECORD function's tupledesc from the pg_proc proallargtypes,
1218  * proargmodes, and proargnames arrays.  This is split out for the
1219  * convenience of ProcedureCreate, which needs to be able to compute the
1220  * tupledesc before actually creating the function.
1221  *
1222  * Returns NULL if there are not at least two OUT or INOUT arguments.
1223  */
1224 TupleDesc
build_function_result_tupdesc_d(Datum proallargtypes,Datum proargmodes,Datum proargnames)1225 build_function_result_tupdesc_d(Datum proallargtypes,
1226 								Datum proargmodes,
1227 								Datum proargnames)
1228 {
1229 	TupleDesc	desc;
1230 	ArrayType  *arr;
1231 	int			numargs;
1232 	Oid		   *argtypes;
1233 	char	   *argmodes;
1234 	Datum	   *argnames = NULL;
1235 	Oid		   *outargtypes;
1236 	char	  **outargnames;
1237 	int			numoutargs;
1238 	int			nargnames;
1239 	int			i;
1240 
1241 	/* Can't have output args if columns are null */
1242 	if (proallargtypes == PointerGetDatum(NULL) ||
1243 		proargmodes == PointerGetDatum(NULL))
1244 		return NULL;
1245 
1246 	/*
1247 	 * We expect the arrays to be 1-D arrays of the right types; verify that.
1248 	 * For the OID and char arrays, we don't need to use deconstruct_array()
1249 	 * since the array data is just going to look like a C array of values.
1250 	 */
1251 	arr = DatumGetArrayTypeP(proallargtypes);	/* ensure not toasted */
1252 	numargs = ARR_DIMS(arr)[0];
1253 	if (ARR_NDIM(arr) != 1 ||
1254 		numargs < 0 ||
1255 		ARR_HASNULL(arr) ||
1256 		ARR_ELEMTYPE(arr) != OIDOID)
1257 		elog(ERROR, "proallargtypes is not a 1-D Oid array");
1258 	argtypes = (Oid *) ARR_DATA_PTR(arr);
1259 	arr = DatumGetArrayTypeP(proargmodes);	/* ensure not toasted */
1260 	if (ARR_NDIM(arr) != 1 ||
1261 		ARR_DIMS(arr)[0] != numargs ||
1262 		ARR_HASNULL(arr) ||
1263 		ARR_ELEMTYPE(arr) != CHAROID)
1264 		elog(ERROR, "proargmodes is not a 1-D char array");
1265 	argmodes = (char *) ARR_DATA_PTR(arr);
1266 	if (proargnames != PointerGetDatum(NULL))
1267 	{
1268 		arr = DatumGetArrayTypeP(proargnames);	/* ensure not toasted */
1269 		if (ARR_NDIM(arr) != 1 ||
1270 			ARR_DIMS(arr)[0] != numargs ||
1271 			ARR_HASNULL(arr) ||
1272 			ARR_ELEMTYPE(arr) != TEXTOID)
1273 			elog(ERROR, "proargnames is not a 1-D text array");
1274 		deconstruct_array(arr, TEXTOID, -1, false, 'i',
1275 						  &argnames, NULL, &nargnames);
1276 		Assert(nargnames == numargs);
1277 	}
1278 
1279 	/* zero elements probably shouldn't happen, but handle it gracefully */
1280 	if (numargs <= 0)
1281 		return NULL;
1282 
1283 	/* extract output-argument types and names */
1284 	outargtypes = (Oid *) palloc(numargs * sizeof(Oid));
1285 	outargnames = (char **) palloc(numargs * sizeof(char *));
1286 	numoutargs = 0;
1287 	for (i = 0; i < numargs; i++)
1288 	{
1289 		char	   *pname;
1290 
1291 		if (argmodes[i] == PROARGMODE_IN ||
1292 			argmodes[i] == PROARGMODE_VARIADIC)
1293 			continue;
1294 		Assert(argmodes[i] == PROARGMODE_OUT ||
1295 			   argmodes[i] == PROARGMODE_INOUT ||
1296 			   argmodes[i] == PROARGMODE_TABLE);
1297 		outargtypes[numoutargs] = argtypes[i];
1298 		if (argnames)
1299 			pname = TextDatumGetCString(argnames[i]);
1300 		else
1301 			pname = NULL;
1302 		if (pname == NULL || pname[0] == '\0')
1303 		{
1304 			/* Parameter is not named, so gin up a column name */
1305 			pname = psprintf("column%d", numoutargs + 1);
1306 		}
1307 		outargnames[numoutargs] = pname;
1308 		numoutargs++;
1309 	}
1310 
1311 	/*
1312 	 * If there is no output argument, or only one, the function does not
1313 	 * return tuples.
1314 	 */
1315 	if (numoutargs < 2)
1316 		return NULL;
1317 
1318 	desc = CreateTemplateTupleDesc(numoutargs, false);
1319 	for (i = 0; i < numoutargs; i++)
1320 	{
1321 		TupleDescInitEntry(desc, i + 1,
1322 						   outargnames[i],
1323 						   outargtypes[i],
1324 						   -1,
1325 						   0);
1326 	}
1327 
1328 	return desc;
1329 }
1330 
1331 
1332 /*
1333  * RelationNameGetTupleDesc
1334  *
1335  * Given a (possibly qualified) relation name, build a TupleDesc.
1336  *
1337  * Note: while this works as advertised, it's seldom the best way to
1338  * build a tupdesc for a function's result type.  It's kept around
1339  * only for backwards compatibility with existing user-written code.
1340  */
1341 TupleDesc
RelationNameGetTupleDesc(const char * relname)1342 RelationNameGetTupleDesc(const char *relname)
1343 {
1344 	RangeVar   *relvar;
1345 	Relation	rel;
1346 	TupleDesc	tupdesc;
1347 	List	   *relname_list;
1348 
1349 	/* Open relation and copy the tuple description */
1350 	relname_list = stringToQualifiedNameList(relname);
1351 	relvar = makeRangeVarFromNameList(relname_list);
1352 	rel = relation_openrv(relvar, AccessShareLock);
1353 	tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
1354 	relation_close(rel, AccessShareLock);
1355 
1356 	return tupdesc;
1357 }
1358 
1359 /*
1360  * TypeGetTupleDesc
1361  *
1362  * Given a type Oid, build a TupleDesc.  (In most cases you should be
1363  * using get_call_result_type or one of its siblings instead of this
1364  * routine, so that you can handle OUT parameters, RECORD result type,
1365  * and polymorphic results.)
1366  *
1367  * If the type is composite, *and* a colaliases List is provided, *and*
1368  * the List is of natts length, use the aliases instead of the relation
1369  * attnames.  (NB: this usage is deprecated since it may result in
1370  * creation of unnecessary transient record types.)
1371  *
1372  * If the type is a base type, a single item alias List is required.
1373  */
1374 TupleDesc
TypeGetTupleDesc(Oid typeoid,List * colaliases)1375 TypeGetTupleDesc(Oid typeoid, List *colaliases)
1376 {
1377 	TypeFuncClass functypclass = get_type_func_class(typeoid);
1378 	TupleDesc	tupdesc = NULL;
1379 
1380 	/*
1381 	 * Build a suitable tupledesc representing the output rows
1382 	 */
1383 	if (functypclass == TYPEFUNC_COMPOSITE)
1384 	{
1385 		/* Composite data type, e.g. a table's row type */
1386 		tupdesc = lookup_rowtype_tupdesc_copy(typeoid, -1);
1387 
1388 		if (colaliases != NIL)
1389 		{
1390 			int			natts = tupdesc->natts;
1391 			int			varattno;
1392 
1393 			/* does the list length match the number of attributes? */
1394 			if (list_length(colaliases) != natts)
1395 				ereport(ERROR,
1396 						(errcode(ERRCODE_DATATYPE_MISMATCH),
1397 						 errmsg("number of aliases does not match number of columns")));
1398 
1399 			/* OK, use the aliases instead */
1400 			for (varattno = 0; varattno < natts; varattno++)
1401 			{
1402 				char	   *label = strVal(list_nth(colaliases, varattno));
1403 
1404 				if (label != NULL)
1405 					namestrcpy(&(tupdesc->attrs[varattno]->attname), label);
1406 			}
1407 
1408 			/* The tuple type is now an anonymous record type */
1409 			tupdesc->tdtypeid = RECORDOID;
1410 			tupdesc->tdtypmod = -1;
1411 		}
1412 	}
1413 	else if (functypclass == TYPEFUNC_SCALAR)
1414 	{
1415 		/* Base data type, i.e. scalar */
1416 		char	   *attname;
1417 
1418 		/* the alias list is required for base types */
1419 		if (colaliases == NIL)
1420 			ereport(ERROR,
1421 					(errcode(ERRCODE_DATATYPE_MISMATCH),
1422 					 errmsg("no column alias was provided")));
1423 
1424 		/* the alias list length must be 1 */
1425 		if (list_length(colaliases) != 1)
1426 			ereport(ERROR,
1427 					(errcode(ERRCODE_DATATYPE_MISMATCH),
1428 					 errmsg("number of aliases does not match number of columns")));
1429 
1430 		/* OK, get the column alias */
1431 		attname = strVal(linitial(colaliases));
1432 
1433 		tupdesc = CreateTemplateTupleDesc(1, false);
1434 		TupleDescInitEntry(tupdesc,
1435 						   (AttrNumber) 1,
1436 						   attname,
1437 						   typeoid,
1438 						   -1,
1439 						   0);
1440 	}
1441 	else if (functypclass == TYPEFUNC_RECORD)
1442 	{
1443 		/* XXX can't support this because typmod wasn't passed in ... */
1444 		ereport(ERROR,
1445 				(errcode(ERRCODE_DATATYPE_MISMATCH),
1446 				 errmsg("could not determine row description for function returning record")));
1447 	}
1448 	else
1449 	{
1450 		/* crummy error message, but parser should have caught this */
1451 		elog(ERROR, "function in FROM has unsupported return type");
1452 	}
1453 
1454 	return tupdesc;
1455 }
1456 
1457 /*
1458  * extract_variadic_args
1459  *
1460  * Extract a set of argument values, types and NULL markers for a given
1461  * input function which makes use of a VARIADIC input whose argument list
1462  * depends on the caller context. When doing a VARIADIC call, the caller
1463  * has provided one argument made of an array of values, so deconstruct the
1464  * array data before using it for the next processing. If no VARIADIC call
1465  * is used, just fill in the status data based on all the arguments given
1466  * by the caller.
1467  *
1468  * This function returns the number of arguments generated, or -1 in the
1469  * case of "VARIADIC NULL".
1470  */
1471 int
extract_variadic_args(FunctionCallInfo fcinfo,int variadic_start,bool convert_unknown,Datum ** args,Oid ** types,bool ** nulls)1472 extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start,
1473 					  bool convert_unknown, Datum **args, Oid **types,
1474 					  bool **nulls)
1475 {
1476 	bool		variadic = get_fn_expr_variadic(fcinfo->flinfo);
1477 	Datum	   *args_res;
1478 	bool	   *nulls_res;
1479 	Oid		   *types_res;
1480 	int			nargs, i;
1481 
1482 	*args = NULL;
1483 	*types = NULL;
1484 	*nulls = NULL;
1485 
1486 	if (variadic)
1487 	{
1488 		ArrayType  *array_in;
1489 		Oid			element_type;
1490 		bool		typbyval;
1491 		char		typalign;
1492 		int16		typlen;
1493 
1494 		Assert(PG_NARGS() == variadic_start + 1);
1495 
1496 		if (PG_ARGISNULL(variadic_start))
1497 			return -1;
1498 
1499 		array_in = PG_GETARG_ARRAYTYPE_P(variadic_start);
1500 		element_type = ARR_ELEMTYPE(array_in);
1501 
1502 		get_typlenbyvalalign(element_type,
1503 							 &typlen, &typbyval, &typalign);
1504 		deconstruct_array(array_in, element_type, typlen, typbyval,
1505 						  typalign, &args_res, &nulls_res,
1506 						  &nargs);
1507 
1508 		/* All the elements of the array have the same type */
1509 		types_res = (Oid *) palloc0(nargs * sizeof(Oid));
1510 		for (i = 0; i < nargs; i++)
1511 			types_res[i] = element_type;
1512 	}
1513 	else
1514 	{
1515 		nargs = PG_NARGS() - variadic_start;
1516 		Assert (nargs > 0);
1517 		nulls_res = (bool *) palloc0(nargs * sizeof(bool));
1518 		args_res = (Datum *) palloc0(nargs * sizeof(Datum));
1519 		types_res = (Oid *) palloc0(nargs * sizeof(Oid));
1520 
1521 		for (i = 0; i < nargs; i++)
1522 		{
1523 			nulls_res[i] = PG_ARGISNULL(i + variadic_start);
1524 			types_res[i] = get_fn_expr_argtype(fcinfo->flinfo,
1525 											   i + variadic_start);
1526 
1527 			/*
1528 			 * Turn a constant (more or less literal) value that's of unknown
1529 			 * type into text if required . Unknowns come in as a cstring
1530 			 * pointer.
1531 			 * Note: for functions declared as taking type "any", the parser
1532 			 * will not do any type conversion on unknown-type literals (that
1533 			 * is, undecorated strings or NULLs).
1534 			 */
1535 			if (convert_unknown &&
1536 				types_res[i] == UNKNOWNOID &&
1537 				get_fn_expr_arg_stable(fcinfo->flinfo, i + variadic_start))
1538 			{
1539 				types_res[i] = TEXTOID;
1540 
1541 				if (PG_ARGISNULL(i + variadic_start))
1542 					args_res[i] = (Datum) 0;
1543 				else
1544 					args_res[i] =
1545 						CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start));
1546 			}
1547 			else
1548 			{
1549 				/* no conversion needed, just take the datum as given */
1550 				args_res[i] = PG_GETARG_DATUM(i + variadic_start);
1551 			}
1552 
1553 			if (!OidIsValid(types_res[i]) ||
1554 				(convert_unknown && types_res[i] == UNKNOWNOID))
1555 				ereport(ERROR,
1556 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1557 						 errmsg("could not determine data type for argument %d",
1558 								i + 1)));
1559 		}
1560 	}
1561 
1562 	/* Fill in results */
1563 	*args = args_res;
1564 	*nulls = nulls_res;
1565 	*types = types_res;
1566 
1567 	return nargs;
1568 }
1569