]> granicus.if.org Git - postgresql/blob - src/backend/parser/parse_target.c
Defend against function calls with more than 8 arguments (code
[postgresql] / src / backend / parser / parse_target.c
1 /*-------------------------------------------------------------------------
2  *
3  * parse_target.c
4  *        handle target lists
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.42 1999/06/17 22:21:41 tgl Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include "postgres.h"
19 #include "catalog/pg_type.h"
20 #include "nodes/makefuncs.h"
21 #include "nodes/primnodes.h"
22 #include "nodes/print.h"
23 #include "parser/parse_expr.h"
24 #include "parser/parse_func.h"
25 #include "parser/parse_node.h"
26 #include "parser/parse_relation.h"
27 #include "parser/parse_target.h"
28 #include "parser/parse_coerce.h"
29 #include "utils/builtins.h"
30 #include "utils/lsyscache.h"
31 #include "utils/syscache.h"
32
33
34 static List *ExpandAllTables(ParseState *pstate);
35 static char *FigureColname(Node *expr, Node *resval);
36 static Node *SizeTargetExpr(ParseState *pstate,
37                            Node *expr,
38                            Oid attrtype,
39                            int32 attrtypmod);
40
41
42 /* MakeTargetEntryIdent()
43  * Transforms an Ident Node to a Target Entry
44  * Created this function to allow the ORDER/GROUP BY clause to be able
45  *      to construct a TargetEntry from an Ident.
46  *
47  * resjunk = TRUE will hide the target entry in the final result tuple.
48  *              daveh@insightdist.com     5/20/98
49  *
50  * Added more conversion logic to match up types from source to target.
51  * - thomas 1998-06-02
52  */
53 TargetEntry *
54 MakeTargetEntryIdent(ParseState *pstate,
55                                          Node *node,
56                                          char **resname,
57                                          char *refname,
58                                          char *colname,
59                                          bool resjunk)
60 {
61         Node       *expr = NULL;
62         Oid                     attrtype_target;
63         TargetEntry *tent = makeNode(TargetEntry);
64
65         if (pstate->p_is_insert && !resjunk)
66         {
67
68                 /*
69                  * Assign column name of destination column to the new TLE. XXX
70                  * this is probably WRONG in INSERT ... SELECT case, since
71                  * handling of GROUP BY and so forth probably should use the
72                  * source table's names not the destination's names.
73                  */
74                 if (pstate->p_insert_columns != NIL)
75                 {
76                         Ident      *id = lfirst(pstate->p_insert_columns);
77
78                         *resname = id->name;
79                         pstate->p_insert_columns = lnext(pstate->p_insert_columns);
80                 }
81                 else
82                         elog(ERROR, "INSERT has more expressions than target columns");
83         }
84
85         if ((pstate->p_is_insert || pstate->p_is_update) && !resjunk)
86         {
87                 Oid                     attrtype_id;
88                 int                     resdomno_id,
89                                         resdomno_target;
90                 RangeTblEntry *rte;
91                 char       *target_colname;
92                 int32           attrtypmod,
93                                         attrtypmod_target;
94
95                 target_colname = *resname;
96
97                 /*
98                  * this looks strange to me, returning an empty TargetEntry bjm
99                  * 1998/08/24
100                  */
101                 if (target_colname == NULL || colname == NULL)
102                         return tent;
103
104                 if (refname != NULL)
105                         rte = refnameRangeTableEntry(pstate, refname);
106                 else
107                 {
108                         rte = colnameRangeTableEntry(pstate, colname);
109                         if (rte == (RangeTblEntry *) NULL)
110                                 elog(ERROR, "Attribute %s not found", colname);
111                         refname = rte->refname;
112                 }
113
114                 resdomno_id = get_attnum(rte->relid, colname);
115                 attrtype_id = get_atttype(rte->relid, resdomno_id);
116                 attrtypmod = get_atttypmod(rte->relid, resdomno_id);
117
118                 resdomno_target = attnameAttNum(pstate->p_target_relation, target_colname);
119                 attrtype_target = attnumTypeId(pstate->p_target_relation, resdomno_target);
120                 attrtypmod_target = get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target);
121
122                 if ((attrtype_id != attrtype_target)
123                         || ((attrtypmod_target >= 0) && (attrtypmod_target != attrtypmod)))
124                 {
125                         if (can_coerce_type(1, &attrtype_id, &attrtype_target))
126                         {
127                                 expr = coerce_type(pstate, node, attrtype_id,
128                                                                    attrtype_target,
129                                                                    get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target));
130                                 expr = transformExpr(pstate, expr, EXPR_COLUMN_FIRST);
131                                 tent = MakeTargetEntryExpr(pstate, *resname, expr, false, false);
132                                 expr = tent->expr;
133                         }
134                         else
135                         {
136                                 elog(ERROR, "Unable to convert %s to %s for column %s",
137                                          typeidTypeName(attrtype_id), typeidTypeName(attrtype_target),
138                                          target_colname);
139                         }
140                 }
141         }
142
143         /*
144          * here we want to look for column names only, not relation names
145          * (even though they can be stored in Ident nodes, too)
146          */
147         if (expr == NULL)
148         {
149                 char       *name;
150                 int32           type_mod;
151
152                 name = ((*resname != NULL) ? *resname : colname);
153
154                 expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST);
155
156                 attrtype_target = exprType(expr);
157                 if (nodeTag(expr) == T_Var)
158                         type_mod = ((Var *) expr)->vartypmod;
159                 else
160                         type_mod = -1;
161
162                 tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
163                                                                   (Oid) attrtype_target,
164                                                                   type_mod,
165                                                                   name,
166                                                                   (Index) 0,
167                                                                   (Oid) 0,
168                                                                   resjunk);
169                 tent->expr = expr;
170         }
171
172         return tent;
173 }       /* MakeTargetEntryIdent() */
174
175
176 /* MakeTargetEntryExpr()
177  * Make a TargetEntry from an expression.
178  * arrayRef is a list of transformed A_Indices.
179  *
180  * For type mismatches between expressions and targets, use the same
181  *      techniques as for function and operator type coersion.
182  * - thomas 1998-05-08
183  *
184  * Added resjunk flag and made extern so that it can be use by GROUP/
185  * ORDER BY a function or expression not in the target_list
186  * -  daveh@insightdist.com 1998-07-31
187  */
188 TargetEntry *
189 MakeTargetEntryExpr(ParseState *pstate,
190                                         char *colname,
191                                         Node *expr,
192                                         List *arrayRef,
193                                         bool resjunk)
194 {
195         Oid                     type_id,
196                                 attrtype;
197         int32           type_mod,
198                                 attrtypmod;
199         int                     resdomno;
200         Relation        rd;
201         bool            attrisset;
202         Resdom     *resnode;
203
204         if (expr == NULL)
205                 elog(ERROR, "Invalid use of NULL expression (internal error)");
206
207         type_id = exprType(expr);
208         if (nodeTag(expr) == T_Var)
209                 type_mod = ((Var *) expr)->vartypmod;
210         else
211                 type_mod = -1;
212
213         /* Process target columns that will be receiving results */
214         if ((pstate->p_is_insert || pstate->p_is_update) && !resjunk)
215         {
216
217                 /*
218                  * insert or update query -- insert, update work only on one
219                  * relation, so multiple occurence of same resdomno is bogus
220                  */
221                 rd = pstate->p_target_relation;
222                 Assert(rd != NULL);
223                 resdomno = attnameAttNum(rd, colname);
224                 if (resdomno <= 0)
225                         elog(ERROR, "Cannot assign to system attribute '%s'", colname);
226                 attrisset = attnameIsSet(rd, colname);
227                 attrtype = attnumTypeId(rd, resdomno);
228                 if ((arrayRef != NIL) && (lfirst(arrayRef) == NIL))
229                         attrtype = GetArrayElementType(attrtype);
230                 attrtypmod = rd->rd_att->attrs[resdomno - 1]->atttypmod;
231
232                 /*
233                  * Check for InvalidOid since that seems to indicate a NULL
234                  * constant...
235                  */
236                 if (type_id != InvalidOid)
237                 {
238                         /* Mismatch on types? then try to coerce to target...  */
239                         if (attrtype != type_id)
240                         {
241                                 Oid                     typelem;
242
243                                 if (arrayRef && !(((A_Indices *) lfirst(arrayRef))->lidx))
244                                         typelem = typeTypElem(typeidType(attrtype));
245                                 else
246                                         typelem = attrtype;
247
248                                 expr = CoerceTargetExpr(pstate, expr, type_id, typelem);
249
250                                 if (!HeapTupleIsValid(expr))
251                                         elog(ERROR, "Attribute '%s' is of type '%s'"
252                                                  " but expression is of type '%s'"
253                                         "\n\tYou will need to rewrite or cast the expression",
254                                                  colname,
255                                                  typeidTypeName(attrtype),
256                                                  typeidTypeName(type_id));
257                         }
258
259                         /*
260                          * Apparently going to a fixed-length string? Then explicitly
261                          * size for storage...
262                          */
263                         if (attrtypmod > 0)
264                                 expr = SizeTargetExpr(pstate, expr, attrtype, attrtypmod);
265                 }
266
267                 if (arrayRef != NIL)
268                 {
269                         Expr       *target_expr;
270                         Attr       *att = makeNode(Attr);
271                         List       *ar = arrayRef;
272                         List       *upperIndexpr = NIL;
273                         List       *lowerIndexpr = NIL;
274
275                         att->relname = pstrdup(RelationGetRelationName(rd)->data);
276                         att->attrs = lcons(makeString(colname), NIL);
277                         target_expr = (Expr *) ParseNestedFuncOrColumn(pstate, att,
278                                                                                                    &pstate->p_last_resno,
279                                                                                                           EXPR_COLUMN_FIRST);
280                         while (ar != NIL)
281                         {
282                                 A_Indices  *ind = lfirst(ar);
283
284                                 if (lowerIndexpr || (!upperIndexpr && ind->lidx))
285                                 {
286
287                                         /*
288                                          * XXX assume all lowerIndexpr is non-null in this
289                                          * case
290                                          */
291                                         lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
292                                 }
293                                 upperIndexpr = lappend(upperIndexpr, ind->uidx);
294                                 ar = lnext(ar);
295                         }
296
297                         expr = (Node *) make_array_set(target_expr,
298                                                                                    upperIndexpr,
299                                                                                    lowerIndexpr,
300                                                                                    (Expr *) expr);
301                         attrtype = attnumTypeId(rd, resdomno);
302                         attrtypmod = get_atttypmod(RelationGetRelid(rd), resdomno);
303                 }
304         }
305         else
306         {
307                 resdomno = pstate->p_last_resno++;
308                 attrtype = type_id;
309                 attrtypmod = type_mod;
310         }
311
312         resnode = makeResdom((AttrNumber) resdomno,
313                                                  (Oid) attrtype,
314                                                  attrtypmod,
315                                                  colname,
316                                                  (Index) 0,
317                                                  (Oid) 0,
318                                                  resjunk);
319
320         return makeTargetEntry(resnode, expr);
321 }       /* MakeTargetEntryExpr() */
322
323 /*
324  *      MakeTargetEntryCase()
325  *      Make a TargetEntry from a case node.
326  */
327 static TargetEntry *
328 MakeTargetEntryCase(ParseState *pstate,
329                                         ResTarget *res)
330 {
331         TargetEntry *tent;
332         CaseExpr   *expr;
333         Resdom     *resnode;
334         int                     resdomno;
335         Oid                     type_id;
336         int32           type_mod;
337
338         expr = (CaseExpr *) transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
339
340         type_id = expr->casetype;
341         type_mod = -1;
342         handleTargetColname(pstate, &res->name, NULL, NULL);
343         if (res->name == NULL)
344                 res->name = FigureColname((Node *) expr, res->val);
345
346         resdomno = pstate->p_last_resno++;
347         resnode = makeResdom((AttrNumber) resdomno,
348                                                  (Oid) type_id,
349                                                  type_mod,
350                                                  res->name,
351                                                  (Index) 0,
352                                                  (Oid) 0,
353                                                  false);
354
355         tent = makeNode(TargetEntry);
356         tent->resdom = resnode;
357         tent->expr = (Node *) expr;
358
359         return tent;
360 }       /* MakeTargetEntryCase() */
361
362 /*
363  *      MakeTargetEntryComplex()
364  *      Make a TargetEntry from a complex node.
365  */
366 static TargetEntry *
367 MakeTargetEntryComplex(ParseState *pstate,
368                                            ResTarget *res)
369 {
370         Node       *expr = transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
371
372         handleTargetColname(pstate, &res->name, NULL, NULL);
373         /* note indirection has not been transformed */
374         if (pstate->p_is_insert && res->indirection != NIL)
375         {
376                 /* this is an array assignment */
377                 char       *val;
378                 char       *str,
379                                    *save_str;
380                 List       *elt;
381                 int                     i = 0,
382                                         ndims;
383                 int                     lindx[MAXDIM],
384                                         uindx[MAXDIM];
385                 int                     resdomno;
386                 Relation        rd;
387                 Value      *constval;
388
389                 if (exprType(expr) != UNKNOWNOID || !IsA(expr, Const))
390                         elog(ERROR, "String constant expected (internal error)");
391
392                 val = (char *) textout((struct varlena *)
393                                                            ((Const *) expr)->constvalue);
394                 str = save_str = (char *) palloc(strlen(val) + MAXDIM * 25 + 2);
395                 foreach(elt, res->indirection)
396                 {
397                         A_Indices  *aind = (A_Indices *) lfirst(elt);
398
399                         aind->uidx = transformExpr(pstate, aind->uidx, EXPR_COLUMN_FIRST);
400                         if (!IsA(aind->uidx, Const))
401                                 elog(ERROR, "Array Index for Append should be a constant");
402
403                         uindx[i] = ((Const *) aind->uidx)->constvalue;
404                         if (aind->lidx != NULL)
405                         {
406                                 aind->lidx = transformExpr(pstate, aind->lidx, EXPR_COLUMN_FIRST);
407                                 if (!IsA(aind->lidx, Const))
408                                         elog(ERROR, "Array Index for Append should be a constant");
409
410                                 lindx[i] = ((Const *) aind->lidx)->constvalue;
411                         }
412                         else
413                                 lindx[i] = 1;
414                         if (lindx[i] > uindx[i])
415                                 elog(ERROR, "Lower index cannot be greater than upper index");
416
417                         sprintf(str, "[%d:%d]", lindx[i], uindx[i]);
418                         str += strlen(str);
419                         i++;
420                 }
421                 sprintf(str, "=%s", val);
422                 rd = pstate->p_target_relation;
423                 Assert(rd != NULL);
424                 resdomno = attnameAttNum(rd, res->name);
425                 ndims = attnumAttNelems(rd, resdomno);
426                 if (i != ndims)
427                         elog(ERROR, "Array dimensions do not match");
428
429                 constval = makeNode(Value);
430                 constval->type = T_String;
431                 constval->val.str = save_str;
432                 return MakeTargetEntryExpr(pstate, res->name,
433                                                                    (Node *) make_const(constval),
434                                                                    NULL, false);
435                 pfree(save_str);
436         }
437         else
438         {
439                 /* this is not an array assignment */
440                 char       *colname = res->name;
441
442                 if (colname == NULL)
443                 {
444
445                         /*
446                          * if you're wondering why this is here, look at the yacc
447                          * grammar for why a name can be missing. -ay
448                          */
449                         colname = FigureColname(expr, res->val);
450                 }
451                 if (res->indirection)
452                 {
453                         List       *ilist = res->indirection;
454
455                         while (ilist != NIL)
456                         {
457                                 A_Indices  *ind = lfirst(ilist);
458
459                                 ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
460                                 ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
461                                 ilist = lnext(ilist);
462                         }
463                 }
464                 res->name = colname;
465                 return MakeTargetEntryExpr(pstate, res->name, expr,
466                                                                    res->indirection, false);
467         }
468 }
469
470 /*
471  *      MakeTargetEntryAttr()
472  *      Make a TargetEntry from a complex node.
473  */
474 static TargetEntry *
475 MakeTargetEntryAttr(ParseState *pstate,
476                                         ResTarget *res)
477 {
478         Oid                     type_id;
479         int32           type_mod;
480         Attr       *att = (Attr *) res->val;
481         Node       *result;
482         char       *attrname;
483         char       *resname;
484         Resdom     *resnode;
485         int                     resdomno;
486         List       *attrs = att->attrs;
487         TargetEntry *tent;
488
489         attrname = strVal(lfirst(att->attrs));
490
491         /*
492          * Target item is fully specified: ie. relation.attribute
493          */
494         result = ParseNestedFuncOrColumn(pstate, att, &pstate->p_last_resno, EXPR_COLUMN_FIRST);
495         handleTargetColname(pstate, &res->name, att->relname, attrname);
496         if (att->indirection != NIL)
497         {
498                 List       *ilist = att->indirection;
499
500                 while (ilist != NIL)
501                 {
502                         A_Indices  *ind = lfirst(ilist);
503
504                         ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
505                         ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
506                         ilist = lnext(ilist);
507                 }
508                 result = (Node *) make_array_ref(result, att->indirection);
509         }
510         type_id = exprType(result);
511         if (nodeTag(result) == T_Var)
512                 type_mod = ((Var *) result)->vartypmod;
513         else
514                 type_mod = -1;
515         /* move to last entry */
516         while (lnext(attrs) != NIL)
517                 attrs = lnext(attrs);
518         resname = (res->name) ? res->name : strVal(lfirst(attrs));
519         if (pstate->p_is_insert || pstate->p_is_update)
520         {
521                 Relation        rd;
522
523                 /*
524                  * insert or update query -- insert, update work only on one
525                  * relation, so multiple occurence of same resdomno is bogus
526                  */
527                 rd = pstate->p_target_relation;
528                 Assert(rd != NULL);
529                 resdomno = attnameAttNum(rd, res->name);
530         }
531         else
532                 resdomno = pstate->p_last_resno++;
533         resnode = makeResdom((AttrNumber) resdomno,
534                                                  (Oid) type_id,
535                                                  type_mod,
536                                                  resname,
537                                                  (Index) 0,
538                                                  (Oid) 0,
539                                                  false);
540         tent = makeNode(TargetEntry);
541         tent->resdom = resnode;
542         tent->expr = result;
543         return tent;
544 }
545
546
547 /* transformTargetList()
548  * Turns a list of ResTarget's into a list of TargetEntry's.
549  */
550 List *
551 transformTargetList(ParseState *pstate, List *targetlist)
552 {
553         List       *p_target = NIL;
554         List       *tail_p_target = NIL;
555
556         while (targetlist != NIL)
557         {
558                 ResTarget  *res = (ResTarget *) lfirst(targetlist);
559                 TargetEntry *tent = NULL;
560
561                 switch (nodeTag(res->val))
562                 {
563                         case T_Ident:
564                                 {
565                                         char       *identname;
566
567                                         identname = ((Ident *) res->val)->name;
568                                         tent = MakeTargetEntryIdent(pstate,
569                                                                                                 (Node *) res->val, &res->name, NULL, identname, false);
570                                         break;
571                                 }
572                         case T_ParamNo:
573                         case T_FuncCall:
574                         case T_A_Const:
575                         case T_A_Expr:
576                                 {
577                                         tent = MakeTargetEntryComplex(pstate, res);
578                                         break;
579                                 }
580                         case T_CaseExpr:
581                                 {
582                                         tent = MakeTargetEntryCase(pstate, res);
583                                         break;
584                                 }
585                         case T_Attr:
586                                 {
587                                         bool            expand_star = false;
588                                         char       *attrname;
589                                         Attr       *att = (Attr *) res->val;
590
591                                         /*
592                                          * Target item is a single '*', expand all tables (eg.
593                                          * SELECT * FROM emp)
594                                          */
595                                         if (att->relname != NULL && !strcmp(att->relname, "*"))
596                                         {
597                                                 if (tail_p_target == NIL)
598                                                         p_target = tail_p_target = ExpandAllTables(pstate);
599                                                 else
600                                                         lnext(tail_p_target) = ExpandAllTables(pstate);
601                                                 expand_star = true;
602                                         }
603                                         else
604                                         {
605
606                                                 /*
607                                                  * Target item is relation.*, expand the table
608                                                  * (eg. SELECT emp.*, dname FROM emp, dept)
609                                                  */
610                                                 attrname = strVal(lfirst(att->attrs));
611                                                 if (att->attrs != NIL && !strcmp(attrname, "*"))
612                                                 {
613
614                                                         /*
615                                                          * tail_p_target is the target list we're
616                                                          * building in the while loop. Make sure we
617                                                          * fix it after appending more nodes.
618                                                          */
619                                                         if (tail_p_target == NIL)
620                                                                 p_target = tail_p_target = expandAll(pstate, att->relname,
621                                                                         att->relname, &pstate->p_last_resno);
622                                                         else
623                                                                 lnext(tail_p_target) = expandAll(pstate, att->relname, att->relname,
624                                                                                                   &pstate->p_last_resno);
625                                                         expand_star = true;
626                                                 }
627                                         }
628                                         if (expand_star)
629                                         {
630                                                 while (lnext(tail_p_target) != NIL)
631                                                         /* make sure we point to the last target entry */
632                                                         tail_p_target = lnext(tail_p_target);
633
634                                                 /*
635                                                  * skip rest of while loop
636                                                  */
637                                                 targetlist = lnext(targetlist);
638                                                 continue;
639                                         }
640                                         else
641                                         {
642                                                 tent = MakeTargetEntryAttr(pstate, res);
643                                                 break;
644                                         }
645                                 }
646                         default:
647                                 /* internal error */
648                                 elog(ERROR, "Unable to transform targetlist (internal error)");
649                                 break;
650                 }
651
652                 if (p_target == NIL)
653                         p_target = tail_p_target = lcons(tent, NIL);
654                 else
655                 {
656                         lnext(tail_p_target) = lcons(tent, NIL);
657                         tail_p_target = lnext(tail_p_target);
658                 }
659                 targetlist = lnext(targetlist);
660         }
661
662         return p_target;
663 }       /* transformTargetList() */
664
665
666 Node *
667 CoerceTargetExpr(ParseState *pstate,
668                                  Node *expr,
669                                  Oid type_id,
670                                  Oid attrtype)
671 {
672         if (can_coerce_type(1, &type_id, &attrtype))
673                 expr = coerce_type(pstate, expr, type_id, attrtype, -1);
674
675 #ifndef DISABLE_STRING_HACKS
676
677         /*
678          * string hacks to get transparent conversions w/o explicit
679          * conversions
680          */
681         else if ((attrtype == BPCHAROID) || (attrtype == VARCHAROID))
682         {
683                 Oid                     text_id = TEXTOID;
684
685                 if (type_id == TEXTOID)
686                 {
687                 }
688                 else if (can_coerce_type(1, &type_id, &text_id))
689                         expr = coerce_type(pstate, expr, type_id, text_id, -1);
690                 else
691                         expr = NULL;
692         }
693 #endif
694
695         else
696                 expr = NULL;
697
698         return expr;
699 }       /* CoerceTargetExpr() */
700
701
702 /* SizeTargetExpr()
703  * Apparently going to a fixed-length string?
704  * Then explicitly size for storage...
705  */
706 static Node *
707 SizeTargetExpr(ParseState *pstate,
708                            Node *expr,
709                            Oid attrtype,
710                            int32 attrtypmod)
711 {
712         int                     i;
713         HeapTuple       ftup;
714         char       *funcname;
715         Oid                     oid_array[MAXFARGS];
716
717         FuncCall   *func;
718         A_Const    *cons;
719
720         funcname = typeidTypeName(attrtype);
721         oid_array[0] = attrtype;
722         oid_array[1] = INT4OID;
723         for (i = 2; i < MAXFARGS; i++)
724                 oid_array[i] = InvalidOid;
725
726         /* attempt to find with arguments exactly as specified... */
727         ftup = SearchSysCacheTuple(PRONAME,
728                                                            PointerGetDatum(funcname),
729                                                            Int32GetDatum(2),
730                                                            PointerGetDatum(oid_array),
731                                                            0);
732
733         if (HeapTupleIsValid(ftup))
734         {
735                 func = makeNode(FuncCall);
736                 func->funcname = funcname;
737
738                 cons = makeNode(A_Const);
739                 cons->val.type = T_Integer;
740                 cons->val.val.ival = attrtypmod;
741                 func->args = lappend(lcons(expr, NIL), cons);
742
743                 expr = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST);
744         }
745
746         return expr;
747 }       /* SizeTargetExpr() */
748
749
750 /*
751  * makeTargetNames -
752  *        generate a list of column names if not supplied or
753  *        test supplied column names to make sure they are in target table
754  *        (used exclusively for inserts)
755  */
756 List *
757 makeTargetNames(ParseState *pstate, List *cols)
758 {
759         List       *tl = NULL;
760
761         /* Generate ResTarget if not supplied */
762
763         if (cols == NIL)
764         {
765                 int                     numcol;
766                 int                     i;
767                 Form_pg_attribute *attr = pstate->p_target_relation->rd_att->attrs;
768
769                 numcol = pstate->p_target_relation->rd_rel->relnatts;
770                 for (i = 0; i < numcol; i++)
771                 {
772                         Ident      *id = makeNode(Ident);
773
774                         id->name = palloc(NAMEDATALEN);
775                         StrNCpy(id->name, attr[i]->attname.data, NAMEDATALEN);
776                         id->indirection = NIL;
777                         id->isRel = false;
778                         if (tl == NIL)
779                                 cols = tl = lcons(id, NIL);
780                         else
781                         {
782                                 lnext(tl) = lcons(id, NIL);
783                                 tl = lnext(tl);
784                         }
785                 }
786         }
787         else
788         {
789                 foreach(tl, cols)
790                 {
791                         List       *nxt;
792                         char       *name = ((Ident *) lfirst(tl))->name;
793
794                         /* elog on failure */
795                         attnameAttNum(pstate->p_target_relation, name);
796                         foreach(nxt, lnext(tl))
797                                 if (!strcmp(name, ((Ident *) lfirst(nxt))->name))
798                                 elog(ERROR, "Attribute '%s' should be specified only once", name);
799                 }
800         }
801
802         return cols;
803 }
804
805 /*
806  * ExpandAllTables -
807  *        turns '*' (in the target list) into a list of attributes
808  *         (of all relations in the range table)
809  */
810 static List *
811 ExpandAllTables(ParseState *pstate)
812 {
813         List       *target = NIL;
814         List       *legit_rtable = NIL;
815         List       *rt,
816                            *rtable;
817
818         rtable = pstate->p_rtable;
819         if (pstate->p_is_rule)
820         {
821
822                 /*
823                  * skip first two entries, "*new*" and "*current*"
824                  */
825                 rtable = lnext(lnext(pstate->p_rtable));
826         }
827
828         /* SELECT *; */
829         if (rtable == NULL)
830                 elog(ERROR, "Wildcard with no tables specified.");
831
832         /*
833          * go through the range table and make a list of range table entries
834          * which we will expand.
835          */
836         foreach(rt, rtable)
837         {
838                 RangeTblEntry *rte = lfirst(rt);
839
840                 /*
841                  * we only expand those specify in the from clause. (This will
842                  * also prevent us from using the wrong table in inserts: eg.
843                  * tenk2 in "insert into tenk2 select * from tenk1;")
844                  */
845                 if (!rte->inFromCl)
846                         continue;
847                 legit_rtable = lappend(legit_rtable, rte);
848         }
849
850         foreach(rt, legit_rtable)
851         {
852                 RangeTblEntry *rte = lfirst(rt);
853                 List       *temp = target;
854
855                 if (temp == NIL)
856                         target = expandAll(pstate, rte->relname, rte->refname,
857                                                            &pstate->p_last_resno);
858                 else
859                 {
860                         while (temp != NIL && lnext(temp) != NIL)
861                                 temp = lnext(temp);
862                         lnext(temp) = expandAll(pstate, rte->relname, rte->refname,
863                                                                         &pstate->p_last_resno);
864                 }
865         }
866         return target;
867 }
868
869 /*
870  * FigureColname -
871  *        if the name of the resulting column is not specified in the target
872  *        list, we have to guess.
873  *
874  */
875 static char *
876 FigureColname(Node *expr, Node *resval)
877 {
878         switch (nodeTag(expr))
879         {
880                         case T_Aggref:
881                         return (char *) ((Aggref *) expr)->aggname;
882                 case T_Expr:
883                         if (((Expr *) expr)->opType == FUNC_EXPR)
884                         {
885                                 if (nodeTag(resval) == T_FuncCall)
886                                         return ((FuncCall *) resval)->funcname;
887                         }
888                         break;
889                 case T_CaseExpr:
890                         {
891                                 char       *name;
892
893                                 name = FigureColname(((CaseExpr *) expr)->defresult, resval);
894                                 if (!strcmp(name, "?column?"))
895                                         name = "case";
896                                 return name;
897                         }
898                         break;
899                 default:
900                         break;
901         }
902
903         return "?column?";
904 }