]> granicus.if.org Git - postgresql/blob - src/backend/parser/parse_target.c
Pass around typmod as int16.
[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.9 1998/02/10 16:03:41 momjian 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 "parser/parse_expr.h"
23 #include "parser/parse_func.h"
24 #include "parser/parse_node.h"
25 #include "parser/parse_relation.h"
26 #include "parser/parse_target.h"
27 #include "utils/builtins.h"
28 #include "utils/lsyscache.h"
29
30 static List *expandAllTables(ParseState *pstate);
31 static char *figureColname(Node *expr, Node *resval);
32 static TargetEntry *make_targetlist_expr(ParseState *pstate,
33                                          char *colname,
34                                          Node *expr,
35                                          List *arrayRef);
36
37 /*
38  * transformTargetList -
39  *        turns a list of ResTarget's into a list of TargetEntry's
40  */
41 List *
42 transformTargetList(ParseState *pstate, List *targetlist)
43 {
44         List       *p_target = NIL;
45         List       *tail_p_target = NIL;
46
47         while (targetlist != NIL)
48         {
49                 ResTarget  *res = (ResTarget *) lfirst(targetlist);
50                 TargetEntry *tent = makeNode(TargetEntry);
51
52                 switch (nodeTag(res->val))
53                 {
54                         case T_Ident:
55                                 {
56                                         Node       *expr;
57                                         Oid                     type_id;
58                                         int16           type_mod;
59                                         char       *identname;
60                                         char       *resname;
61
62                                         identname = ((Ident *) res->val)->name;
63                                         handleTargetColname(pstate, &res->name, NULL, identname);
64
65                                         /*
66                                          * here we want to look for column names only, not relation
67                                          * names (even though they can be stored in Ident nodes, too)
68                                          */
69                                         expr = transformIdent(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
70                                         type_id = exprType(expr);
71                                         if (nodeTag(expr) == T_Var)
72                                                 type_mod = ((Var *)expr)->vartypmod;
73                                         else
74                                                 type_mod = -1;
75                                         resname = (res->name) ? res->name : identname;
76                                         tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
77                                                                                           (Oid) type_id,
78                                                                                           type_mod,
79                                                                                           resname,
80                                                                                           (Index) 0,
81                                                                                           (Oid) 0,
82                                                                                           0);
83
84                                         tent->expr = expr;
85                                         break;
86                                 }
87                         case T_ParamNo:
88                         case T_FuncCall:
89                         case T_A_Const:
90                         case T_A_Expr:
91                                 {
92                                         Node       *expr = transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
93
94                                         handleTargetColname(pstate, &res->name, NULL, NULL);
95                                         /* note indirection has not been transformed */
96                                         if (pstate->p_is_insert && res->indirection != NIL)
97                                         {
98                                                 /* this is an array assignment */
99                                                 char       *val;
100                                                 char       *str,
101                                                                    *save_str;
102                                                 List       *elt;
103                                                 int                     i = 0,
104                                                                         ndims;
105                                                 int                     lindx[MAXDIM],
106                                                                         uindx[MAXDIM];
107                                                 int                     resdomno;
108                                                 Relation        rd;
109                                                 Value      *constval;
110
111                                                 if (exprType(expr) != UNKNOWNOID ||
112                                                         !IsA(expr, Const))
113                                                         elog(ERROR, "yyparse: string constant expected");
114
115                                                 val = (char *) textout((struct varlena *)
116                                                                                    ((Const *) expr)->constvalue);
117                                                 str = save_str = (char *) palloc(strlen(val) + MAXDIM * 25 + 2);
118                                                 foreach(elt, res->indirection)
119                                                 {
120                                                         A_Indices  *aind = (A_Indices *) lfirst(elt);
121
122                                                         aind->uidx = transformExpr(pstate, aind->uidx, EXPR_COLUMN_FIRST);
123                                                         if (!IsA(aind->uidx, Const))
124                                                                 elog(ERROR,
125                                                                          "Array Index for Append should be a constant");
126                                                         uindx[i] = ((Const *) aind->uidx)->constvalue;
127                                                         if (aind->lidx != NULL)
128                                                         {
129                                                                 aind->lidx = transformExpr(pstate, aind->lidx, EXPR_COLUMN_FIRST);
130                                                                 if (!IsA(aind->lidx, Const))
131                                                                         elog(ERROR,
132                                                                                  "Array Index for Append should be a constant");
133                                                                 lindx[i] = ((Const *) aind->lidx)->constvalue;
134                                                         }
135                                                         else
136                                                         {
137                                                                 lindx[i] = 1;
138                                                         }
139                                                         if (lindx[i] > uindx[i])
140                                                                 elog(ERROR, "yyparse: lower index cannot be greater than upper index");
141                                                         sprintf(str, "[%d:%d]", lindx[i], uindx[i]);
142                                                         str += strlen(str);
143                                                         i++;
144                                                 }
145                                                 sprintf(str, "=%s", val);
146                                                 rd = pstate->p_target_relation;
147                                                 Assert(rd != NULL);
148                                                 resdomno = attnameAttNum(rd, res->name);
149                                                 ndims = attnumAttNelems(rd, resdomno);
150                                                 if (i != ndims)
151                                                         elog(ERROR, "yyparse: array dimensions do not match");
152                                                 constval = makeNode(Value);
153                                                 constval->type = T_String;
154                                                 constval->val.str = save_str;
155                                                 tent = make_targetlist_expr(pstate, res->name,
156                                                                                    (Node *) make_const(constval),
157                                                                                                         NULL);
158                                                 pfree(save_str);
159                                         }
160                                         else
161                                         {
162                                                 char       *colname = res->name;
163
164                                                 /* this is not an array assignment */
165                                                 if (colname == NULL)
166                                                 {
167
168                                                         /*
169                                                          * if you're wondering why this is here, look
170                                                          * at the yacc grammar for why a name can be
171                                                          * missing. -ay
172                                                          */
173                                                         colname = figureColname(expr, res->val);
174                                                 }
175                                                 if (res->indirection)
176                                                 {
177                                                         List       *ilist = res->indirection;
178
179                                                         while (ilist != NIL)
180                                                         {
181                                                                 A_Indices  *ind = lfirst(ilist);
182
183                                                                 ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
184                                                                 ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
185                                                                 ilist = lnext(ilist);
186                                                         }
187                                                 }
188                                                 res->name = colname;
189                                                 tent = make_targetlist_expr(pstate, res->name, expr,
190                                                                                                         res->indirection);
191                                         }
192                                         break;
193                                 }
194                         case T_Attr:
195                                 {
196                                         Oid                     type_id;
197                                         int16           type_mod;
198                                         Attr       *att = (Attr *) res->val;
199                                         Node       *result;
200                                         char       *attrname;
201                                         char       *resname;
202                                         Resdom     *resnode;
203                                         List       *attrs = att->attrs;
204
205                                         /*
206                                          * Target item is a single '*', expand all tables (eg.
207                                          * SELECT * FROM emp)
208                                          */
209                                         if (att->relname != NULL && !strcmp(att->relname, "*"))
210                                         {
211                                                 if (tail_p_target == NIL)
212                                                         p_target = tail_p_target = expandAllTables(pstate);
213                                                 else
214                                                         lnext(tail_p_target) = expandAllTables(pstate);
215
216                                                 while (lnext(tail_p_target) != NIL)
217                                                         /* make sure we point to the last target entry */
218                                                         tail_p_target = lnext(tail_p_target);
219
220                                                 /*
221                                                  * skip rest of while loop
222                                                  */
223                                                 targetlist = lnext(targetlist);
224                                                 continue;
225                                         }
226
227                                         /*
228                                          * Target item is relation.*, expand the table (eg.
229                                          * SELECT emp.*, dname FROM emp, dept)
230                                          */
231                                         attrname = strVal(lfirst(att->attrs));
232                                         if (att->attrs != NIL && !strcmp(attrname, "*"))
233                                         {
234
235                                                 /*
236                                                  * tail_p_target is the target list we're building
237                                                  * in the while loop. Make sure we fix it after
238                                                  * appending more nodes.
239                                                  */
240                                                 if (tail_p_target == NIL)
241                                                         p_target = tail_p_target = expandAll(pstate, att->relname,
242                                                                         att->relname, &pstate->p_last_resno);
243                                                 else
244                                                         lnext(tail_p_target) =
245                                                                 expandAll(pstate, att->relname, att->relname,
246                                                                                   &pstate->p_last_resno);
247                                                 while (lnext(tail_p_target) != NIL)
248                                                         /* make sure we point to the last target entry */
249                                                         tail_p_target = lnext(tail_p_target);
250
251                                                 /*
252                                                  * skip the rest of the while loop
253                                                  */
254                                                 targetlist = lnext(targetlist);
255                                                 continue;
256                                         }
257
258
259                                         /*
260                                          * Target item is fully specified: ie. relation.attribute
261                                          */
262                                         result = ParseNestedFuncOrColumn(pstate, att, &pstate->p_last_resno,EXPR_COLUMN_FIRST);
263                                         handleTargetColname(pstate, &res->name, att->relname, attrname);
264                                         if (att->indirection != NIL)
265                                         {
266                                                 List       *ilist = att->indirection;
267
268                                                 while (ilist != NIL)
269                                                 {
270                                                         A_Indices  *ind = lfirst(ilist);
271
272                                                         ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
273                                                         ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
274                                                         ilist = lnext(ilist);
275                                                 }
276                                                 result = (Node *) make_array_ref(result, att->indirection);
277                                         }
278                                         type_id = exprType(result);
279                                         if (nodeTag(result) == T_Var)
280                                                 type_mod = ((Var *)result)->vartypmod;
281                                         else
282                                                 type_mod = -1;
283                                         /* move to last entry */
284                                         while (lnext(attrs) != NIL)
285                                                 attrs = lnext(attrs);
286                                         resname = (res->name) ? res->name : strVal(lfirst(attrs));
287                                         resnode = makeResdom((AttrNumber) pstate->p_last_resno++,
288                                                                                  (Oid) type_id,
289                                                                                  type_mod,
290                                                                                  resname,
291                                                                                  (Index) 0,
292                                                                                  (Oid) 0,
293                                                                                  0);
294                                         tent->resdom = resnode;
295                                         tent->expr = result;
296                                         break;
297                                 }
298                         default:
299                                 /* internal error */
300                                 elog(ERROR,
301                                          "internal error: do not know how to transform targetlist");
302                                 break;
303                 }
304
305                 if (p_target == NIL)
306                 {
307                         p_target = tail_p_target = lcons(tent, NIL);
308                 }
309                 else
310                 {
311                         lnext(tail_p_target) = lcons(tent, NIL);
312                         tail_p_target = lnext(tail_p_target);
313                 }
314                 targetlist = lnext(targetlist);
315         }
316
317         return p_target;
318 }
319
320
321 /*
322  * make_targetlist_expr -
323  *        make a TargetEntry from an expression
324  *
325  * arrayRef is a list of transformed A_Indices
326  */
327 static TargetEntry *
328 make_targetlist_expr(ParseState *pstate,
329                                          char *colname,
330                                          Node *expr,
331                                          List *arrayRef)
332 {
333         Oid                     type_id,
334                                 attrtype;
335         int16           type_mod,
336                                 attrtypmod;
337         int                     resdomno;
338         Relation        rd;
339         bool            attrisset;
340         TargetEntry *tent;
341         Resdom     *resnode;
342
343         if (expr == NULL)
344                 elog(ERROR, "make_targetlist_expr: invalid use of NULL expression");
345
346         type_id = exprType(expr);
347         if (nodeTag(expr) == T_Var)
348                 type_mod = ((Var *)expr)->vartypmod;
349         else
350                 type_mod = -1;
351
352         /* Processes target columns that will be receiving results */
353         if (pstate->p_is_insert || pstate->p_is_update)
354         {
355
356                 /*
357                  * insert or update query -- insert, update work only on one
358                  * relation, so multiple occurence of same resdomno is bogus
359                  */
360                 rd = pstate->p_target_relation;
361                 Assert(rd != NULL);
362                 resdomno = attnameAttNum(rd, colname);
363                 attrisset = attnameIsSet(rd, colname);
364                 attrtype = attnumTypeId(rd, resdomno);
365                 if ((arrayRef != NIL) && (lfirst(arrayRef) == NIL))
366                         attrtype = GetArrayElementType(attrtype);
367                 attrtypmod = rd->rd_att->attrs[resdomno - 1]->atttypmod;
368 #if 0
369                 if (Input_is_string && Typecast_ok)
370                 {
371                         Datum           val;
372
373                         if (type_id == typeTypeId(type("unknown")))
374                         {
375                                 val = (Datum) textout((struct varlena *)
376                                                                           ((Const) lnext(expr))->constvalue);
377                         }
378                         else
379                         {
380                                 val = ((Const) lnext(expr))->constvalue;
381                         }
382                         if (attrisset)
383                         {
384                                 lnext(expr) = makeConst(attrtype,
385                                                                                 attrlen,
386                                                                                 val,
387                                                                                 false,
388                                                                                 true,
389                                                                                 true,   /* is set */
390                                                                                 false);
391                         }
392                         else
393                         {
394                                 lnext(expr) =
395                                         makeConst(attrtype,
396                                                           attrlen,
397                                                           (Datum) fmgr(typeidRetinfunc(attrtype),
398                                                                                  val, typeidTypElem(attrtype), -1),
399                                                           false,
400                                                           true /* Maybe correct-- 80% chance */ ,
401                                                           false,        /* is not a set */
402                                                           false);
403                         }
404                 }
405                 else if ((Typecast_ok) && (attrtype != type_id))
406                 {
407                         lnext(expr) =
408                                 parser_typecast2(expr, typeidType(attrtype));
409                 }
410                 else if (attrtype != type_id)
411                 {
412                         if ((attrtype == INT2OID) && (type_id == INT4OID))
413                                 lfirst(expr) = lispInteger(INT2OID);    /* handle CASHOID too */
414                         else if ((attrtype == FLOAT4OID) && (type_id == FLOAT8OID))
415                                 lfirst(expr) = lispInteger(FLOAT4OID);
416                         else
417                                 elog(ERROR, "unequal type in tlist : %s \n", colname);
418                 }
419
420                 Input_is_string = false;
421                 Input_is_integer = false;
422                 Typecast_ok = true;
423 #endif
424
425                 if (attrtype != type_id)
426                 {
427                         if (IsA(expr, Const))
428                         {
429                                 /* try to cast the constant */
430                                 if (arrayRef && !(((A_Indices *) lfirst(arrayRef))->lidx))
431                                 {
432                                         /* updating a single item */
433                                         Oid                     typelem = typeidTypElem(attrtype);
434
435                                         expr = (Node *) parser_typecast2(expr,
436                                                                                                          type_id,
437                                                                                                          typeidType(typelem),
438                                                                                                          attrtypmod);
439                                 }
440                                 else
441                                         expr = (Node *) parser_typecast2(expr,
442                                                                                                          type_id,
443                                                                                                          typeidType(attrtype),
444                                                                                                          attrtypmod);
445                         }
446                         else
447                         {
448                                 /* currently, we can't handle casting of expressions */
449                                 elog(ERROR, "parser: attribute '%s' is of type '%s' but expression is of type '%s'",
450                                          colname,
451                                          typeidTypeName(attrtype),
452                                          typeidTypeName(type_id));
453                         }
454                 }
455
456                 if (arrayRef != NIL)
457                 {
458                         Expr       *target_expr;
459                         Attr       *att = makeNode(Attr);
460                         List       *ar = arrayRef;
461                         List       *upperIndexpr = NIL;
462                         List       *lowerIndexpr = NIL;
463
464                         att->relname = pstrdup(RelationGetRelationName(rd)->data);
465                         att->attrs = lcons(makeString(colname), NIL);
466                         target_expr = (Expr *) ParseNestedFuncOrColumn(pstate, att,
467                                                                                                   &pstate->p_last_resno,
468                                                                                                   EXPR_COLUMN_FIRST);
469                         while (ar != NIL)
470                         {
471                                 A_Indices  *ind = lfirst(ar);
472
473                                 if (lowerIndexpr || (!upperIndexpr && ind->lidx))
474                                 {
475
476                                         /*
477                                          * XXX assume all lowerIndexpr is non-null in this
478                                          * case
479                                          */
480                                         lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
481                                 }
482                                 upperIndexpr = lappend(upperIndexpr, ind->uidx);
483                                 ar = lnext(ar);
484                         }
485
486                         expr = (Node *) make_array_set(target_expr,
487                                                                                    upperIndexpr,
488                                                                                    lowerIndexpr,
489                                                                                    (Expr *) expr);
490                         attrtype = attnumTypeId(rd, resdomno);
491                         attrtypmod = get_atttypmod(rd->rd_id, resdomno);
492                 }
493         }
494         else
495         {
496                 resdomno = pstate->p_last_resno++;
497                 attrtype = type_id;
498                 attrtypmod = type_mod;
499         }
500         tent = makeNode(TargetEntry);
501
502         resnode = makeResdom((AttrNumber) resdomno,
503                                                  (Oid) attrtype,
504                                                  attrtypmod,
505                                                  colname,
506                                                  (Index) 0,
507                                                  (Oid) 0,
508                                                  0);
509
510         tent->resdom = resnode;
511         tent->expr = expr;
512
513         return tent;
514 }
515
516 /*
517  * makeTargetNames -
518  *        generate a list of column names if not supplied or
519  *        test supplied column names to make sure they are in target table
520  *        (used exclusively for inserts)
521  */
522 List *
523 makeTargetNames(ParseState *pstate, List *cols)
524 {
525         List       *tl = NULL;
526
527         /* Generate ResTarget if not supplied */
528
529         if (cols == NIL)
530         {
531                 int                     numcol;
532                 int                     i;
533                 AttributeTupleForm *attr = pstate->p_target_relation->rd_att->attrs;
534
535                 numcol = pstate->p_target_relation->rd_rel->relnatts;
536                 for (i = 0; i < numcol; i++)
537                 {
538                         Ident      *id = makeNode(Ident);
539
540                         id->name = palloc(NAMEDATALEN);
541                         StrNCpy(id->name, attr[i]->attname.data, NAMEDATALEN);
542                         id->indirection = NIL;
543                         id->isRel = false;
544                         if (tl == NIL)
545                                 cols = tl = lcons(id, NIL);
546                         else
547                         {
548                                 lnext(tl) = lcons(id, NIL);
549                                 tl = lnext(tl);
550                         }
551                 }
552         }
553         else
554         {
555                 foreach(tl, cols)
556                 {
557                         List       *nxt;
558                         char       *name = ((Ident *) lfirst(tl))->name;
559                 
560                         /* elog on failure */
561                         attnameAttNum(pstate->p_target_relation, name);
562                         foreach(nxt, lnext(tl))
563                                 if (!strcmp(name, ((Ident *) lfirst(nxt))->name))
564                                         elog(ERROR, "Attribute '%s' should be specified only once", name);
565                 }
566         }
567         
568         return cols;
569 }
570
571 /*
572  * expandAllTables -
573  *        turns '*' (in the target list) into a list of attributes
574  *         (of all relations in the range table)
575  */
576 static List *
577 expandAllTables(ParseState *pstate)
578 {
579         List       *target = NIL;
580         List       *legit_rtable = NIL;
581         List       *rt,
582                            *rtable;
583
584         rtable = pstate->p_rtable;
585         if (pstate->p_is_rule)
586         {
587
588                 /*
589                  * skip first two entries, "*new*" and "*current*"
590                  */
591                 rtable = lnext(lnext(pstate->p_rtable));
592         }
593
594         /* this should not happen */
595         if (rtable == NULL)
596                 elog(ERROR, "cannot expand: null p_rtable");
597
598         /*
599          * go through the range table and make a list of range table entries
600          * which we will expand.
601          */
602         foreach(rt, rtable)
603         {
604                 RangeTblEntry *rte = lfirst(rt);
605
606                 /*
607                  * we only expand those specify in the from clause. (This will
608                  * also prevent us from using the wrong table in inserts: eg.
609                  * tenk2 in "insert into tenk2 select * from tenk1;")
610                  */
611                 if (!rte->inFromCl)
612                         continue;
613                 legit_rtable = lappend(legit_rtable, rte);
614         }
615
616         foreach(rt, legit_rtable)
617         {
618                 RangeTblEntry *rte = lfirst(rt);
619                 List       *temp = target;
620
621                 if (temp == NIL)
622                         target = expandAll(pstate, rte->relname, rte->refname,
623                                                            &pstate->p_last_resno);
624                 else
625                 {
626                         while (temp != NIL && lnext(temp) != NIL)
627                                 temp = lnext(temp);
628                         lnext(temp) = expandAll(pstate, rte->relname, rte->refname,
629                                                                         &pstate->p_last_resno);
630                 }
631         }
632         return target;
633 }
634
635 /*
636  * figureColname -
637  *        if the name of the resulting column is not specified in the target
638  *        list, we have to guess.
639  *
640  */
641 static char *
642 figureColname(Node *expr, Node *resval)
643 {
644         switch (nodeTag(expr))
645         {
646                 case T_Aggreg:
647                         return (char *) ((Aggreg *) expr)->aggname;
648                 case T_Expr:
649                         if (((Expr *) expr)->opType == FUNC_EXPR)
650                         {
651                                 if (nodeTag(resval) == T_FuncCall)
652                                         return ((FuncCall *) resval)->funcname;
653                         }
654                         break;
655                 default:
656                         break;
657         }
658
659         return "?column?";
660 }