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