]> granicus.if.org Git - postgresql/blob - src/backend/utils/fmgr/funcapi.c
Update copyrights in source tree to 2008.
[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.
6  *
7  * Copyright (c) 2002-2008, PostgreSQL Global Development Group
8  *
9  * IDENTIFICATION
10  *        $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.37 2008/01/01 19:45:53 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15
16 #include "access/heapam.h"
17 #include "catalog/namespace.h"
18 #include "catalog/pg_proc.h"
19 #include "catalog/pg_type.h"
20 #include "funcapi.h"
21 #include "parser/parse_coerce.h"
22 #include "parser/parse_expr.h"
23 #include "utils/array.h"
24 #include "utils/builtins.h"
25 #include "utils/lsyscache.h"
26 #include "utils/syscache.h"
27 #include "utils/typcache.h"
28
29
30 static void shutdown_MultiFuncCall(Datum arg);
31 static TypeFuncClass internal_get_result_type(Oid funcid,
32                                                  Node *call_expr,
33                                                  ReturnSetInfo *rsinfo,
34                                                  Oid *resultTypeId,
35                                                  TupleDesc *resultTupleDesc);
36 static bool resolve_polymorphic_tupdesc(TupleDesc tupdesc,
37                                                         oidvector *declared_args,
38                                                         Node *call_expr);
39 static TypeFuncClass get_type_func_class(Oid typid);
40
41
42 /*
43  * init_MultiFuncCall
44  * Create an empty FuncCallContext data structure
45  * and do some other basic Multi-function call setup
46  * and error checking
47  */
48 FuncCallContext *
49 init_MultiFuncCall(PG_FUNCTION_ARGS)
50 {
51         FuncCallContext *retval;
52
53         /*
54          * Bail if we're called in the wrong context
55          */
56         if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo))
57                 ereport(ERROR,
58                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
59                                  errmsg("set-valued function called in context that cannot accept a set")));
60
61         if (fcinfo->flinfo->fn_extra == NULL)
62         {
63                 /*
64                  * First call
65                  */
66                 ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
67
68                 /*
69                  * Allocate suitably long-lived space and zero it
70                  */
71                 retval = (FuncCallContext *)
72                         MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
73                                                                    sizeof(FuncCallContext));
74
75                 /*
76                  * initialize the elements
77                  */
78                 retval->call_cntr = 0;
79                 retval->max_calls = 0;
80                 retval->slot = NULL;
81                 retval->user_fctx = NULL;
82                 retval->attinmeta = NULL;
83                 retval->tuple_desc = NULL;
84                 retval->multi_call_memory_ctx = fcinfo->flinfo->fn_mcxt;
85
86                 /*
87                  * save the pointer for cross-call use
88                  */
89                 fcinfo->flinfo->fn_extra = retval;
90
91                 /*
92                  * Ensure we will get shut down cleanly if the exprcontext is not run
93                  * to completion.
94                  */
95                 RegisterExprContextCallback(rsi->econtext,
96                                                                         shutdown_MultiFuncCall,
97                                                                         PointerGetDatum(fcinfo->flinfo));
98         }
99         else
100         {
101                 /* second and subsequent calls */
102                 elog(ERROR, "init_MultiFuncCall cannot be called more than once");
103
104                 /* never reached, but keep compiler happy */
105                 retval = NULL;
106         }
107
108         return retval;
109 }
110
111 /*
112  * per_MultiFuncCall
113  *
114  * Do Multi-function per-call setup
115  */
116 FuncCallContext *
117 per_MultiFuncCall(PG_FUNCTION_ARGS)
118 {
119         FuncCallContext *retval = (FuncCallContext *) fcinfo->flinfo->fn_extra;
120
121         /*
122          * Clear the TupleTableSlot, if present.  This is for safety's sake: the
123          * Slot will be in a long-lived context (it better be, if the
124          * FuncCallContext is pointing to it), but in most usage patterns the
125          * tuples stored in it will be in the function's per-tuple context. So at
126          * the beginning of each call, the Slot will hold a dangling pointer to an
127          * already-recycled tuple.      We clear it out here.
128          *
129          * Note: use of retval->slot is obsolete as of 8.0, and we expect that it
130          * will always be NULL.  This is just here for backwards compatibility in
131          * case someone creates a slot anyway.
132          */
133         if (retval->slot != NULL)
134                 ExecClearTuple(retval->slot);
135
136         return retval;
137 }
138
139 /*
140  * end_MultiFuncCall
141  * Clean up after init_MultiFuncCall
142  */
143 void
144 end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
145 {
146         ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
147
148         /* Deregister the shutdown callback */
149         UnregisterExprContextCallback(rsi->econtext,
150                                                                   shutdown_MultiFuncCall,
151                                                                   PointerGetDatum(fcinfo->flinfo));
152
153         /* But use it to do the real work */
154         shutdown_MultiFuncCall(PointerGetDatum(fcinfo->flinfo));
155 }
156
157 /*
158  * shutdown_MultiFuncCall
159  * Shutdown function to clean up after init_MultiFuncCall
160  */
161 static void
162 shutdown_MultiFuncCall(Datum arg)
163 {
164         FmgrInfo   *flinfo = (FmgrInfo *) DatumGetPointer(arg);
165         FuncCallContext *funcctx = (FuncCallContext *) flinfo->fn_extra;
166
167         /* unbind from flinfo */
168         flinfo->fn_extra = NULL;
169
170         /*
171          * Caller is responsible to free up memory for individual struct elements
172          * other than att_in_funcinfo and elements.
173          */
174         if (funcctx->attinmeta != NULL)
175                 pfree(funcctx->attinmeta);
176
177         pfree(funcctx);
178 }
179
180
181 /*
182  * get_call_result_type
183  *              Given a function's call info record, determine the kind of datatype
184  *              it is supposed to return.  If resultTypeId isn't NULL, *resultTypeId
185  *              receives the actual datatype OID (this is mainly useful for scalar
186  *              result types).  If resultTupleDesc isn't NULL, *resultTupleDesc
187  *              receives a pointer to a TupleDesc when the result is of a composite
188  *              type, or NULL when it's a scalar result.
189  *
190  * One hard case that this handles is resolution of actual rowtypes for
191  * functions returning RECORD (from either the function's OUT parameter
192  * list, or a ReturnSetInfo context node).      TYPEFUNC_RECORD is returned
193  * only when we couldn't resolve the actual rowtype for lack of information.
194  *
195  * The other hard case that this handles is resolution of polymorphism.
196  * We will never return polymorphic pseudotypes (ANYELEMENT etc), either
197  * as a scalar result type or as a component of a rowtype.
198  *
199  * This function is relatively expensive --- in a function returning set,
200  * try to call it only the first time through.
201  */
202 TypeFuncClass
203 get_call_result_type(FunctionCallInfo fcinfo,
204                                          Oid *resultTypeId,
205                                          TupleDesc *resultTupleDesc)
206 {
207         return internal_get_result_type(fcinfo->flinfo->fn_oid,
208                                                                         fcinfo->flinfo->fn_expr,
209                                                                         (ReturnSetInfo *) fcinfo->resultinfo,
210                                                                         resultTypeId,
211                                                                         resultTupleDesc);
212 }
213
214 /*
215  * get_expr_result_type
216  *              As above, but work from a calling expression node tree
217  */
218 TypeFuncClass
219 get_expr_result_type(Node *expr,
220                                          Oid *resultTypeId,
221                                          TupleDesc *resultTupleDesc)
222 {
223         TypeFuncClass result;
224
225         if (expr && IsA(expr, FuncExpr))
226                 result = internal_get_result_type(((FuncExpr *) expr)->funcid,
227                                                                                   expr,
228                                                                                   NULL,
229                                                                                   resultTypeId,
230                                                                                   resultTupleDesc);
231         else if (expr && IsA(expr, OpExpr))
232                 result = internal_get_result_type(get_opcode(((OpExpr *) expr)->opno),
233                                                                                   expr,
234                                                                                   NULL,
235                                                                                   resultTypeId,
236                                                                                   resultTupleDesc);
237         else
238         {
239                 /* handle as a generic expression; no chance to resolve RECORD */
240                 Oid                     typid = exprType(expr);
241
242                 if (resultTypeId)
243                         *resultTypeId = typid;
244                 if (resultTupleDesc)
245                         *resultTupleDesc = NULL;
246                 result = get_type_func_class(typid);
247                 if (result == TYPEFUNC_COMPOSITE && resultTupleDesc)
248                         *resultTupleDesc = lookup_rowtype_tupdesc_copy(typid, -1);
249         }
250
251         return result;
252 }
253
254 /*
255  * get_func_result_type
256  *              As above, but work from a function's OID only
257  *
258  * This will not be able to resolve pure-RECORD results nor polymorphism.
259  */
260 TypeFuncClass
261 get_func_result_type(Oid functionId,
262                                          Oid *resultTypeId,
263                                          TupleDesc *resultTupleDesc)
264 {
265         return internal_get_result_type(functionId,
266                                                                         NULL,
267                                                                         NULL,
268                                                                         resultTypeId,
269                                                                         resultTupleDesc);
270 }
271
272 /*
273  * internal_get_result_type -- workhorse code implementing all the above
274  *
275  * funcid must always be supplied.      call_expr and rsinfo can be NULL if not
276  * available.  We will return TYPEFUNC_RECORD, and store NULL into
277  * *resultTupleDesc, if we cannot deduce the complete result rowtype from
278  * the available information.
279  */
280 static TypeFuncClass
281 internal_get_result_type(Oid funcid,
282                                                  Node *call_expr,
283                                                  ReturnSetInfo *rsinfo,
284                                                  Oid *resultTypeId,
285                                                  TupleDesc *resultTupleDesc)
286 {
287         TypeFuncClass result;
288         HeapTuple       tp;
289         Form_pg_proc procform;
290         Oid                     rettype;
291         TupleDesc       tupdesc;
292
293         /* First fetch the function's pg_proc row to inspect its rettype */
294         tp = SearchSysCache(PROCOID,
295                                                 ObjectIdGetDatum(funcid),
296                                                 0, 0, 0);
297         if (!HeapTupleIsValid(tp))
298                 elog(ERROR, "cache lookup failed for function %u", funcid);
299         procform = (Form_pg_proc) GETSTRUCT(tp);
300
301         rettype = procform->prorettype;
302
303         /* Check for OUT parameters defining a RECORD result */
304         tupdesc = build_function_result_tupdesc_t(tp);
305         if (tupdesc)
306         {
307                 /*
308                  * It has OUT parameters, so it's basically like a regular composite
309                  * type, except we have to be able to resolve any polymorphic OUT
310                  * parameters.
311                  */
312                 if (resultTypeId)
313                         *resultTypeId = rettype;
314
315                 if (resolve_polymorphic_tupdesc(tupdesc,
316                                                                                 &procform->proargtypes,
317                                                                                 call_expr))
318                 {
319                         if (tupdesc->tdtypeid == RECORDOID &&
320                                 tupdesc->tdtypmod < 0)
321                                 assign_record_type_typmod(tupdesc);
322                         if (resultTupleDesc)
323                                 *resultTupleDesc = tupdesc;
324                         result = TYPEFUNC_COMPOSITE;
325                 }
326                 else
327                 {
328                         if (resultTupleDesc)
329                                 *resultTupleDesc = NULL;
330                         result = TYPEFUNC_RECORD;
331                 }
332
333                 ReleaseSysCache(tp);
334
335                 return result;
336         }
337
338         /*
339          * If scalar polymorphic result, try to resolve it.
340          */
341         if (IsPolymorphicType(rettype))
342         {
343                 Oid                     newrettype = exprType(call_expr);
344
345                 if (newrettype == InvalidOid)   /* this probably should not happen */
346                         ereport(ERROR,
347                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
348                                          errmsg("could not determine actual result type for function \"%s\" declared to return type %s",
349                                                         NameStr(procform->proname),
350                                                         format_type_be(rettype))));
351                 rettype = newrettype;
352         }
353
354         if (resultTypeId)
355                 *resultTypeId = rettype;
356         if (resultTupleDesc)
357                 *resultTupleDesc = NULL;        /* default result */
358
359         /* Classify the result type */
360         result = get_type_func_class(rettype);
361         switch (result)
362         {
363                 case TYPEFUNC_COMPOSITE:
364                         if (resultTupleDesc)
365                                 *resultTupleDesc = lookup_rowtype_tupdesc_copy(rettype, -1);
366                         /* Named composite types can't have any polymorphic columns */
367                         break;
368                 case TYPEFUNC_SCALAR:
369                         break;
370                 case TYPEFUNC_RECORD:
371                         /* We must get the tupledesc from call context */
372                         if (rsinfo && IsA(rsinfo, ReturnSetInfo) &&
373                                 rsinfo->expectedDesc != NULL)
374                         {
375                                 result = TYPEFUNC_COMPOSITE;
376                                 if (resultTupleDesc)
377                                         *resultTupleDesc = rsinfo->expectedDesc;
378                                 /* Assume no polymorphic columns here, either */
379                         }
380                         break;
381                 default:
382                         break;
383         }
384
385         ReleaseSysCache(tp);
386
387         return result;
388 }
389
390 /*
391  * Given the result tuple descriptor for a function with OUT parameters,
392  * replace any polymorphic columns (ANYELEMENT etc) with correct data types
393  * deduced from the input arguments. Returns TRUE if able to deduce all types,
394  * FALSE if not.
395  */
396 static bool
397 resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
398                                                         Node *call_expr)
399 {
400         int                     natts = tupdesc->natts;
401         int                     nargs = declared_args->dim1;
402         bool            have_anyelement_result = false;
403         bool            have_anyarray_result = false;
404         bool            have_anynonarray = false;
405         bool            have_anyenum = false;
406         Oid                     anyelement_type = InvalidOid;
407         Oid                     anyarray_type = InvalidOid;
408         int                     i;
409
410         /* See if there are any polymorphic outputs; quick out if not */
411         for (i = 0; i < natts; i++)
412         {
413                 switch (tupdesc->attrs[i]->atttypid)
414                 {
415                         case ANYELEMENTOID:
416                                 have_anyelement_result = true;
417                                 break;
418                         case ANYARRAYOID:
419                                 have_anyarray_result = true;
420                                 break;
421                         case ANYNONARRAYOID:
422                                 have_anyelement_result = true;
423                                 have_anynonarray = true;
424                                 break;
425                         case ANYENUMOID:
426                                 have_anyelement_result = true;
427                                 have_anyenum = true;
428                                 break;
429                         default:
430                                 break;
431                 }
432         }
433         if (!have_anyelement_result && !have_anyarray_result)
434                 return true;
435
436         /*
437          * Otherwise, extract actual datatype(s) from input arguments.  (We assume
438          * the parser already validated consistency of the arguments.)
439          */
440         if (!call_expr)
441                 return false;                   /* no hope */
442
443         for (i = 0; i < nargs; i++)
444         {
445                 switch (declared_args->values[i])
446                 {
447                         case ANYELEMENTOID:
448                         case ANYNONARRAYOID:
449                         case ANYENUMOID:
450                                 if (!OidIsValid(anyelement_type))
451                                         anyelement_type = get_call_expr_argtype(call_expr, i);
452                                 break;
453                         case ANYARRAYOID:
454                                 if (!OidIsValid(anyarray_type))
455                                         anyarray_type = get_call_expr_argtype(call_expr, i);
456                                 break;
457                         default:
458                                 break;
459                 }
460         }
461
462         /* If nothing found, parser messed up */
463         if (!OidIsValid(anyelement_type) && !OidIsValid(anyarray_type))
464                 return false;
465
466         /* If needed, deduce one polymorphic type from the other */
467         if (have_anyelement_result && !OidIsValid(anyelement_type))
468                 anyelement_type = resolve_generic_type(ANYELEMENTOID,
469                                                                                            anyarray_type,
470                                                                                            ANYARRAYOID);
471         if (have_anyarray_result && !OidIsValid(anyarray_type))
472                 anyarray_type = resolve_generic_type(ANYARRAYOID,
473                                                                                          anyelement_type,
474                                                                                          ANYELEMENTOID);
475
476         /* Enforce ANYNONARRAY if needed */
477         if (have_anynonarray && type_is_array(anyelement_type))
478                 return false;
479
480         /* Enforce ANYENUM if needed */
481         if (have_anyenum && !type_is_enum(anyelement_type))
482                 return false;
483
484         /* And finally replace the tuple column types as needed */
485         for (i = 0; i < natts; i++)
486         {
487                 switch (tupdesc->attrs[i]->atttypid)
488                 {
489                         case ANYELEMENTOID:
490                         case ANYNONARRAYOID:
491                         case ANYENUMOID:
492                                 TupleDescInitEntry(tupdesc, i + 1,
493                                                                    NameStr(tupdesc->attrs[i]->attname),
494                                                                    anyelement_type,
495                                                                    -1,
496                                                                    0);
497                                 break;
498                         case ANYARRAYOID:
499                                 TupleDescInitEntry(tupdesc, i + 1,
500                                                                    NameStr(tupdesc->attrs[i]->attname),
501                                                                    anyarray_type,
502                                                                    -1,
503                                                                    0);
504                                 break;
505                         default:
506                                 break;
507                 }
508         }
509
510         return true;
511 }
512
513 /*
514  * Given the declared argument types and modes for a function, replace any
515  * polymorphic types (ANYELEMENT etc) with correct data types deduced from the
516  * input arguments.  Returns TRUE if able to deduce all types, FALSE if not.
517  * This is the same logic as resolve_polymorphic_tupdesc, but with a different
518  * argument representation.
519  *
520  * argmodes may be NULL, in which case all arguments are assumed to be IN mode.
521  */
522 bool
523 resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
524                                                          Node *call_expr)
525 {
526         bool            have_anyelement_result = false;
527         bool            have_anyarray_result = false;
528         Oid                     anyelement_type = InvalidOid;
529         Oid                     anyarray_type = InvalidOid;
530         int                     inargno;
531         int                     i;
532
533         /* First pass: resolve polymorphic inputs, check for outputs */
534         inargno = 0;
535         for (i = 0; i < numargs; i++)
536         {
537                 char            argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
538
539                 switch (argtypes[i])
540                 {
541                         case ANYELEMENTOID:
542                         case ANYNONARRAYOID:
543                         case ANYENUMOID:
544                                 if (argmode == PROARGMODE_OUT)
545                                         have_anyelement_result = true;
546                                 else
547                                 {
548                                         if (!OidIsValid(anyelement_type))
549                                         {
550                                                 anyelement_type = get_call_expr_argtype(call_expr,
551                                                                                                                                 inargno);
552                                                 if (!OidIsValid(anyelement_type))
553                                                         return false;
554                                         }
555                                         argtypes[i] = anyelement_type;
556                                 }
557                                 break;
558                         case ANYARRAYOID:
559                                 if (argmode == PROARGMODE_OUT)
560                                         have_anyarray_result = true;
561                                 else
562                                 {
563                                         if (!OidIsValid(anyarray_type))
564                                         {
565                                                 anyarray_type = get_call_expr_argtype(call_expr,
566                                                                                                                           inargno);
567                                                 if (!OidIsValid(anyarray_type))
568                                                         return false;
569                                         }
570                                         argtypes[i] = anyarray_type;
571                                 }
572                                 break;
573                         default:
574                                 break;
575                 }
576                 if (argmode != PROARGMODE_OUT)
577                         inargno++;
578         }
579
580         /* Done? */
581         if (!have_anyelement_result && !have_anyarray_result)
582                 return true;
583
584         /* If no input polymorphics, parser messed up */
585         if (!OidIsValid(anyelement_type) && !OidIsValid(anyarray_type))
586                 return false;
587
588         /* If needed, deduce one polymorphic type from the other */
589         if (have_anyelement_result && !OidIsValid(anyelement_type))
590                 anyelement_type = resolve_generic_type(ANYELEMENTOID,
591                                                                                            anyarray_type,
592                                                                                            ANYARRAYOID);
593         if (have_anyarray_result && !OidIsValid(anyarray_type))
594                 anyarray_type = resolve_generic_type(ANYARRAYOID,
595                                                                                          anyelement_type,
596                                                                                          ANYELEMENTOID);
597
598         /* XXX do we need to enforce ANYNONARRAY or ANYENUM here?  I think not */
599
600         /* And finally replace the output column types as needed */
601         for (i = 0; i < numargs; i++)
602         {
603                 switch (argtypes[i])
604                 {
605                         case ANYELEMENTOID:
606                         case ANYNONARRAYOID:
607                         case ANYENUMOID:
608                                 argtypes[i] = anyelement_type;
609                                 break;
610                         case ANYARRAYOID:
611                                 argtypes[i] = anyarray_type;
612                                 break;
613                         default:
614                                 break;
615                 }
616         }
617
618         return true;
619 }
620
621 /*
622  * get_type_func_class
623  *              Given the type OID, obtain its TYPEFUNC classification.
624  *
625  * This is intended to centralize a bunch of formerly ad-hoc code for
626  * classifying types.  The categories used here are useful for deciding
627  * how to handle functions returning the datatype.
628  */
629 static TypeFuncClass
630 get_type_func_class(Oid typid)
631 {
632         switch (get_typtype(typid))
633         {
634                 case TYPTYPE_COMPOSITE:
635                         return TYPEFUNC_COMPOSITE;
636                 case TYPTYPE_BASE:
637                 case TYPTYPE_DOMAIN:
638                 case TYPTYPE_ENUM:
639                         return TYPEFUNC_SCALAR;
640                 case TYPTYPE_PSEUDO:
641                         if (typid == RECORDOID)
642                                 return TYPEFUNC_RECORD;
643
644                         /*
645                          * We treat VOID and CSTRING as legitimate scalar datatypes,
646                          * mostly for the convenience of the JDBC driver (which wants to
647                          * be able to do "SELECT * FROM foo()" for all legitimately
648                          * user-callable functions).
649                          */
650                         if (typid == VOIDOID || typid == CSTRINGOID)
651                                 return TYPEFUNC_SCALAR;
652                         return TYPEFUNC_OTHER;
653         }
654         /* shouldn't get here, probably */
655         return TYPEFUNC_OTHER;
656 }
657
658
659 /*
660  * get_func_arg_info
661  *
662  * Fetch info about the argument types, names, and IN/OUT modes from the
663  * pg_proc tuple.  Return value is the total number of arguments.
664  * Other results are palloc'd.  *p_argtypes is always filled in, but
665  * *p_argnames and *p_argmodes will be set NULL in the default cases
666  * (no names, and all IN arguments, respectively).
667  *
668  * Note that this function simply fetches what is in the pg_proc tuple;
669  * it doesn't do any interpretation of polymorphic types.
670  */
671 int
672 get_func_arg_info(HeapTuple procTup,
673                                   Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
674 {
675         Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
676         Datum           proallargtypes;
677         Datum           proargmodes;
678         Datum           proargnames;
679         bool            isNull;
680         ArrayType  *arr;
681         int                     numargs;
682         Datum      *elems;
683         int                     nelems;
684         int                     i;
685
686         /* First discover the total number of parameters and get their types */
687         proallargtypes = SysCacheGetAttr(PROCOID, procTup,
688                                                                          Anum_pg_proc_proallargtypes,
689                                                                          &isNull);
690         if (!isNull)
691         {
692                 /*
693                  * We expect the arrays to be 1-D arrays of the right types; verify
694                  * that.  For the OID and char arrays, we don't need to use
695                  * deconstruct_array() since the array data is just going to look like
696                  * a C array of values.
697                  */
698                 arr = DatumGetArrayTypeP(proallargtypes);               /* ensure not toasted */
699                 numargs = ARR_DIMS(arr)[0];
700                 if (ARR_NDIM(arr) != 1 ||
701                         numargs < 0 ||
702                         ARR_HASNULL(arr) ||
703                         ARR_ELEMTYPE(arr) != OIDOID)
704                         elog(ERROR, "proallargtypes is not a 1-D Oid array");
705                 Assert(numargs >= procStruct->pronargs);
706                 *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
707                 memcpy(*p_argtypes, ARR_DATA_PTR(arr),
708                            numargs * sizeof(Oid));
709         }
710         else
711         {
712                 /* If no proallargtypes, use proargtypes */
713                 numargs = procStruct->proargtypes.dim1;
714                 Assert(numargs == procStruct->pronargs);
715                 *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
716                 memcpy(*p_argtypes, procStruct->proargtypes.values,
717                            numargs * sizeof(Oid));
718         }
719
720         /* Get argument names, if available */
721         proargnames = SysCacheGetAttr(PROCOID, procTup,
722                                                                   Anum_pg_proc_proargnames,
723                                                                   &isNull);
724         if (isNull)
725                 *p_argnames = NULL;
726         else
727         {
728                 deconstruct_array(DatumGetArrayTypeP(proargnames),
729                                                   TEXTOID, -1, false, 'i',
730                                                   &elems, NULL, &nelems);
731                 if (nelems != numargs)  /* should not happen */
732                         elog(ERROR, "proargnames must have the same number of elements as the function has arguments");
733                 *p_argnames = (char **) palloc(sizeof(char *) * numargs);
734                 for (i = 0; i < numargs; i++)
735                         (*p_argnames)[i] = DatumGetCString(DirectFunctionCall1(textout,
736                                                                                                                                    elems[i]));
737         }
738
739         /* Get argument modes, if available */
740         proargmodes = SysCacheGetAttr(PROCOID, procTup,
741                                                                   Anum_pg_proc_proargmodes,
742                                                                   &isNull);
743         if (isNull)
744                 *p_argmodes = NULL;
745         else
746         {
747                 arr = DatumGetArrayTypeP(proargmodes);  /* ensure not toasted */
748                 if (ARR_NDIM(arr) != 1 ||
749                         ARR_DIMS(arr)[0] != numargs ||
750                         ARR_HASNULL(arr) ||
751                         ARR_ELEMTYPE(arr) != CHAROID)
752                         elog(ERROR, "proargmodes is not a 1-D char array");
753                 *p_argmodes = (char *) palloc(numargs * sizeof(char));
754                 memcpy(*p_argmodes, ARR_DATA_PTR(arr),
755                            numargs * sizeof(char));
756         }
757
758         return numargs;
759 }
760
761
762 /*
763  * get_func_result_name
764  *
765  * If the function has exactly one output parameter, and that parameter
766  * is named, return the name (as a palloc'd string).  Else return NULL.
767  *
768  * This is used to determine the default output column name for functions
769  * returning scalar types.
770  */
771 char *
772 get_func_result_name(Oid functionId)
773 {
774         char       *result;
775         HeapTuple       procTuple;
776         Datum           proargmodes;
777         Datum           proargnames;
778         bool            isnull;
779         ArrayType  *arr;
780         int                     numargs;
781         char       *argmodes;
782         Datum      *argnames;
783         int                     numoutargs;
784         int                     nargnames;
785         int                     i;
786
787         /* First fetch the function's pg_proc row */
788         procTuple = SearchSysCache(PROCOID,
789                                                            ObjectIdGetDatum(functionId),
790                                                            0, 0, 0);
791         if (!HeapTupleIsValid(procTuple))
792                 elog(ERROR, "cache lookup failed for function %u", functionId);
793
794         /* If there are no named OUT parameters, return NULL */
795         if (heap_attisnull(procTuple, Anum_pg_proc_proargmodes) ||
796                 heap_attisnull(procTuple, Anum_pg_proc_proargnames))
797                 result = NULL;
798         else
799         {
800                 /* Get the data out of the tuple */
801                 proargmodes = SysCacheGetAttr(PROCOID, procTuple,
802                                                                           Anum_pg_proc_proargmodes,
803                                                                           &isnull);
804                 Assert(!isnull);
805                 proargnames = SysCacheGetAttr(PROCOID, procTuple,
806                                                                           Anum_pg_proc_proargnames,
807                                                                           &isnull);
808                 Assert(!isnull);
809
810                 /*
811                  * We expect the arrays to be 1-D arrays of the right types; verify
812                  * that.  For the char array, we don't need to use deconstruct_array()
813                  * since the array data is just going to look like a C array of
814                  * values.
815                  */
816                 arr = DatumGetArrayTypeP(proargmodes);  /* ensure not toasted */
817                 numargs = ARR_DIMS(arr)[0];
818                 if (ARR_NDIM(arr) != 1 ||
819                         numargs < 0 ||
820                         ARR_HASNULL(arr) ||
821                         ARR_ELEMTYPE(arr) != CHAROID)
822                         elog(ERROR, "proargmodes is not a 1-D char array");
823                 argmodes = (char *) ARR_DATA_PTR(arr);
824                 arr = DatumGetArrayTypeP(proargnames);  /* ensure not toasted */
825                 if (ARR_NDIM(arr) != 1 ||
826                         ARR_DIMS(arr)[0] != numargs ||
827                         ARR_HASNULL(arr) ||
828                         ARR_ELEMTYPE(arr) != TEXTOID)
829                         elog(ERROR, "proargnames is not a 1-D text array");
830                 deconstruct_array(arr, TEXTOID, -1, false, 'i',
831                                                   &argnames, NULL, &nargnames);
832                 Assert(nargnames == numargs);
833
834                 /* scan for output argument(s) */
835                 result = NULL;
836                 numoutargs = 0;
837                 for (i = 0; i < numargs; i++)
838                 {
839                         if (argmodes[i] == PROARGMODE_IN)
840                                 continue;
841                         Assert(argmodes[i] == PROARGMODE_OUT ||
842                                    argmodes[i] == PROARGMODE_INOUT);
843                         if (++numoutargs > 1)
844                         {
845                                 /* multiple out args, so forget it */
846                                 result = NULL;
847                                 break;
848                         }
849                         result = DatumGetCString(DirectFunctionCall1(textout,
850                                                                                                                  argnames[i]));
851                         if (result == NULL || result[0] == '\0')
852                         {
853                                 /* Parameter is not named, so forget it */
854                                 result = NULL;
855                                 break;
856                         }
857                 }
858         }
859
860         ReleaseSysCache(procTuple);
861
862         return result;
863 }
864
865
866 /*
867  * build_function_result_tupdesc_t
868  *
869  * Given a pg_proc row for a function, return a tuple descriptor for the
870  * result rowtype, or NULL if the function does not have OUT parameters.
871  *
872  * Note that this does not handle resolution of polymorphic types;
873  * that is deliberate.
874  */
875 TupleDesc
876 build_function_result_tupdesc_t(HeapTuple procTuple)
877 {
878         Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(procTuple);
879         Datum           proallargtypes;
880         Datum           proargmodes;
881         Datum           proargnames;
882         bool            isnull;
883
884         /* Return NULL if the function isn't declared to return RECORD */
885         if (procform->prorettype != RECORDOID)
886                 return NULL;
887
888         /* If there are no OUT parameters, return NULL */
889         if (heap_attisnull(procTuple, Anum_pg_proc_proallargtypes) ||
890                 heap_attisnull(procTuple, Anum_pg_proc_proargmodes))
891                 return NULL;
892
893         /* Get the data out of the tuple */
894         proallargtypes = SysCacheGetAttr(PROCOID, procTuple,
895                                                                          Anum_pg_proc_proallargtypes,
896                                                                          &isnull);
897         Assert(!isnull);
898         proargmodes = SysCacheGetAttr(PROCOID, procTuple,
899                                                                   Anum_pg_proc_proargmodes,
900                                                                   &isnull);
901         Assert(!isnull);
902         proargnames = SysCacheGetAttr(PROCOID, procTuple,
903                                                                   Anum_pg_proc_proargnames,
904                                                                   &isnull);
905         if (isnull)
906                 proargnames = PointerGetDatum(NULL);    /* just to be sure */
907
908         return build_function_result_tupdesc_d(proallargtypes,
909                                                                                    proargmodes,
910                                                                                    proargnames);
911 }
912
913 /*
914  * build_function_result_tupdesc_d
915  *
916  * Build a RECORD function's tupledesc from the pg_proc proallargtypes,
917  * proargmodes, and proargnames arrays.  This is split out for the
918  * convenience of ProcedureCreate, which needs to be able to compute the
919  * tupledesc before actually creating the function.
920  *
921  * Returns NULL if there are not at least two OUT or INOUT arguments.
922  */
923 TupleDesc
924 build_function_result_tupdesc_d(Datum proallargtypes,
925                                                                 Datum proargmodes,
926                                                                 Datum proargnames)
927 {
928         TupleDesc       desc;
929         ArrayType  *arr;
930         int                     numargs;
931         Oid                *argtypes;
932         char       *argmodes;
933         Datum      *argnames = NULL;
934         Oid                *outargtypes;
935         char      **outargnames;
936         int                     numoutargs;
937         int                     nargnames;
938         int                     i;
939
940         /* Can't have output args if columns are null */
941         if (proallargtypes == PointerGetDatum(NULL) ||
942                 proargmodes == PointerGetDatum(NULL))
943                 return NULL;
944
945         /*
946          * We expect the arrays to be 1-D arrays of the right types; verify that.
947          * For the OID and char arrays, we don't need to use deconstruct_array()
948          * since the array data is just going to look like a C array of values.
949          */
950         arr = DatumGetArrayTypeP(proallargtypes);       /* ensure not toasted */
951         numargs = ARR_DIMS(arr)[0];
952         if (ARR_NDIM(arr) != 1 ||
953                 numargs < 0 ||
954                 ARR_HASNULL(arr) ||
955                 ARR_ELEMTYPE(arr) != OIDOID)
956                 elog(ERROR, "proallargtypes is not a 1-D Oid array");
957         argtypes = (Oid *) ARR_DATA_PTR(arr);
958         arr = DatumGetArrayTypeP(proargmodes);          /* ensure not toasted */
959         if (ARR_NDIM(arr) != 1 ||
960                 ARR_DIMS(arr)[0] != numargs ||
961                 ARR_HASNULL(arr) ||
962                 ARR_ELEMTYPE(arr) != CHAROID)
963                 elog(ERROR, "proargmodes is not a 1-D char array");
964         argmodes = (char *) ARR_DATA_PTR(arr);
965         if (proargnames != PointerGetDatum(NULL))
966         {
967                 arr = DatumGetArrayTypeP(proargnames);  /* ensure not toasted */
968                 if (ARR_NDIM(arr) != 1 ||
969                         ARR_DIMS(arr)[0] != numargs ||
970                         ARR_HASNULL(arr) ||
971                         ARR_ELEMTYPE(arr) != TEXTOID)
972                         elog(ERROR, "proargnames is not a 1-D text array");
973                 deconstruct_array(arr, TEXTOID, -1, false, 'i',
974                                                   &argnames, NULL, &nargnames);
975                 Assert(nargnames == numargs);
976         }
977
978         /* zero elements probably shouldn't happen, but handle it gracefully */
979         if (numargs <= 0)
980                 return NULL;
981
982         /* extract output-argument types and names */
983         outargtypes = (Oid *) palloc(numargs * sizeof(Oid));
984         outargnames = (char **) palloc(numargs * sizeof(char *));
985         numoutargs = 0;
986         for (i = 0; i < numargs; i++)
987         {
988                 char       *pname;
989
990                 if (argmodes[i] == PROARGMODE_IN)
991                         continue;
992                 Assert(argmodes[i] == PROARGMODE_OUT ||
993                            argmodes[i] == PROARGMODE_INOUT);
994                 outargtypes[numoutargs] = argtypes[i];
995                 if (argnames)
996                         pname = DatumGetCString(DirectFunctionCall1(textout, argnames[i]));
997                 else
998                         pname = NULL;
999                 if (pname == NULL || pname[0] == '\0')
1000                 {
1001                         /* Parameter is not named, so gin up a column name */
1002                         pname = (char *) palloc(32);
1003                         snprintf(pname, 32, "column%d", numoutargs + 1);
1004                 }
1005                 outargnames[numoutargs] = pname;
1006                 numoutargs++;
1007         }
1008
1009         /*
1010          * If there is no output argument, or only one, the function does not
1011          * return tuples.
1012          */
1013         if (numoutargs < 2)
1014                 return NULL;
1015
1016         desc = CreateTemplateTupleDesc(numoutargs, false);
1017         for (i = 0; i < numoutargs; i++)
1018         {
1019                 TupleDescInitEntry(desc, i + 1,
1020                                                    outargnames[i],
1021                                                    outargtypes[i],
1022                                                    -1,
1023                                                    0);
1024         }
1025
1026         return desc;
1027 }
1028
1029
1030 /*
1031  * RelationNameGetTupleDesc
1032  *
1033  * Given a (possibly qualified) relation name, build a TupleDesc.
1034  *
1035  * Note: while this works as advertised, it's seldom the best way to
1036  * build a tupdesc for a function's result type.  It's kept around
1037  * only for backwards compatibility with existing user-written code.
1038  */
1039 TupleDesc
1040 RelationNameGetTupleDesc(const char *relname)
1041 {
1042         RangeVar   *relvar;
1043         Relation        rel;
1044         TupleDesc       tupdesc;
1045         List       *relname_list;
1046
1047         /* Open relation and copy the tuple description */
1048         relname_list = stringToQualifiedNameList(relname);
1049         relvar = makeRangeVarFromNameList(relname_list);
1050         rel = relation_openrv(relvar, AccessShareLock);
1051         tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
1052         relation_close(rel, AccessShareLock);
1053
1054         return tupdesc;
1055 }
1056
1057 /*
1058  * TypeGetTupleDesc
1059  *
1060  * Given a type Oid, build a TupleDesc.  (In most cases you should be
1061  * using get_call_result_type or one of its siblings instead of this
1062  * routine, so that you can handle OUT parameters, RECORD result type,
1063  * and polymorphic results.)
1064  *
1065  * If the type is composite, *and* a colaliases List is provided, *and*
1066  * the List is of natts length, use the aliases instead of the relation
1067  * attnames.  (NB: this usage is deprecated since it may result in
1068  * creation of unnecessary transient record types.)
1069  *
1070  * If the type is a base type, a single item alias List is required.
1071  */
1072 TupleDesc
1073 TypeGetTupleDesc(Oid typeoid, List *colaliases)
1074 {
1075         TypeFuncClass functypclass = get_type_func_class(typeoid);
1076         TupleDesc       tupdesc = NULL;
1077
1078         /*
1079          * Build a suitable tupledesc representing the output rows
1080          */
1081         if (functypclass == TYPEFUNC_COMPOSITE)
1082         {
1083                 /* Composite data type, e.g. a table's row type */
1084                 tupdesc = lookup_rowtype_tupdesc_copy(typeoid, -1);
1085
1086                 if (colaliases != NIL)
1087                 {
1088                         int                     natts = tupdesc->natts;
1089                         int                     varattno;
1090
1091                         /* does the list length match the number of attributes? */
1092                         if (list_length(colaliases) != natts)
1093                                 ereport(ERROR,
1094                                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
1095                                                  errmsg("number of aliases does not match number of columns")));
1096
1097                         /* OK, use the aliases instead */
1098                         for (varattno = 0; varattno < natts; varattno++)
1099                         {
1100                                 char       *label = strVal(list_nth(colaliases, varattno));
1101
1102                                 if (label != NULL)
1103                                         namestrcpy(&(tupdesc->attrs[varattno]->attname), label);
1104                         }
1105
1106                         /* The tuple type is now an anonymous record type */
1107                         tupdesc->tdtypeid = RECORDOID;
1108                         tupdesc->tdtypmod = -1;
1109                 }
1110         }
1111         else if (functypclass == TYPEFUNC_SCALAR)
1112         {
1113                 /* Base data type, i.e. scalar */
1114                 char       *attname;
1115
1116                 /* the alias list is required for base types */
1117                 if (colaliases == NIL)
1118                         ereport(ERROR,
1119                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
1120                                          errmsg("no column alias was provided")));
1121
1122                 /* the alias list length must be 1 */
1123                 if (list_length(colaliases) != 1)
1124                         ereport(ERROR,
1125                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
1126                           errmsg("number of aliases does not match number of columns")));
1127
1128                 /* OK, get the column alias */
1129                 attname = strVal(linitial(colaliases));
1130
1131                 tupdesc = CreateTemplateTupleDesc(1, false);
1132                 TupleDescInitEntry(tupdesc,
1133                                                    (AttrNumber) 1,
1134                                                    attname,
1135                                                    typeoid,
1136                                                    -1,
1137                                                    0);
1138         }
1139         else if (functypclass == TYPEFUNC_RECORD)
1140         {
1141                 /* XXX can't support this because typmod wasn't passed in ... */
1142                 ereport(ERROR,
1143                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
1144                                  errmsg("could not determine row description for function returning record")));
1145         }
1146         else
1147         {
1148                 /* crummy error message, but parser should have caught this */
1149                 elog(ERROR, "function in FROM has unsupported return type");
1150         }
1151
1152         return tupdesc;
1153 }