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