]> granicus.if.org Git - postgresql/blob - src/backend/parser/parse_target.c
Create a new parsetree node type, TypeCast, so that transformation of
[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.52 2000/01/17 00:14:48 tgl Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14
15 #include "postgres.h"
16 #include "nodes/makefuncs.h"
17 #include "parser/parse_coerce.h"
18 #include "parser/parse_expr.h"
19 #include "parser/parse_func.h"
20 #include "parser/parse_relation.h"
21 #include "parser/parse_target.h"
22 #include "utils/builtins.h"
23 #include "utils/lsyscache.h"
24 #include "utils/syscache.h"
25
26
27 static List *ExpandAllTables(ParseState *pstate);
28 static char *FigureColname(Node *expr, Node *resval);
29
30
31 /*
32  * transformTargetEntry()
33  *      Transform any ordinary "expression-type" node into a targetlist entry.
34  *      This is exported so that parse_clause.c can generate targetlist entries
35  *      for ORDER/GROUP BY items that are not already in the targetlist.
36  *
37  * node         the (untransformed) parse tree for the value expression.
38  * expr         the transformed expression, or NULL if caller didn't do it yet.
39  * colname      the column name to be assigned, or NULL if none yet set.
40  * resjunk      true if the target should be marked resjunk, ie, it is not
41  *                      wanted in the final projected tuple.
42  */
43 TargetEntry *
44 transformTargetEntry(ParseState *pstate,
45                                          Node *node,
46                                          Node *expr,
47                                          char *colname,
48                                          bool resjunk)
49 {
50         Oid                     type_id;
51         int32           type_mod;
52         Resdom     *resnode;
53
54         /* Transform the node if caller didn't do it already */
55         if (expr == NULL)
56                 expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST);
57
58         type_id = exprType(expr);
59         type_mod = exprTypmod(expr);
60
61         if (colname == NULL)
62         {
63                 /* Generate a suitable column name for a column without any
64                  * explicit 'AS ColumnName' clause.
65                  */
66                 colname = FigureColname(expr, node);
67         }
68
69         resnode = makeResdom((AttrNumber) pstate->p_last_resno++,
70                                                  type_id,
71                                                  type_mod,
72                                                  colname,
73                                                  (Index) 0,
74                                                  (Oid) InvalidOid,
75                                                  resjunk);
76
77         return makeTargetEntry(resnode, expr);
78 }
79
80
81 /*
82  * transformTargetList()
83  * Turns a list of ResTarget's into a list of TargetEntry's.
84  *
85  * At this point, we don't care whether we are doing SELECT, INSERT,
86  * or UPDATE; we just transform the given expressions.
87  */
88 List *
89 transformTargetList(ParseState *pstate, List *targetlist)
90 {
91         List       *p_target = NIL;
92
93         while (targetlist != NIL)
94         {
95                 ResTarget  *res = (ResTarget *) lfirst(targetlist);
96
97                 if (IsA(res->val, Attr))
98                 {
99                         Attr       *att = (Attr *) res->val;
100
101                         if (att->relname != NULL && strcmp(att->relname, "*") == 0)
102                         {
103                                 /*
104                                  * Target item is a single '*', expand all tables
105                                  * (eg. SELECT * FROM emp)
106                                  */
107                                 p_target = nconc(p_target,
108                                                                  ExpandAllTables(pstate));
109                         }
110                         else if (att->attrs != NIL &&
111                                          strcmp(strVal(lfirst(att->attrs)), "*") == 0)
112                         {
113                                 /*
114                                  * Target item is relation.*, expand that table
115                                  * (eg. SELECT emp.*, dname FROM emp, dept)
116                                  */
117                                 p_target = nconc(p_target,
118                                                                  expandAll(pstate,
119                                                                                    att->relname,
120                                                                                    att->relname,
121                                                                                    &pstate->p_last_resno));
122                         }
123                         else
124                         {
125                                 /* Plain Attr node, treat it as an expression */
126                                 p_target = lappend(p_target,
127                                                                    transformTargetEntry(pstate,
128                                                                                                                 res->val,
129                                                                                                                 NULL,
130                                                                                                                 res->name,
131                                                                                                                 false));
132                         }
133                 }
134                 else
135                 {
136                         /* Everything else but Attr */
137                         p_target = lappend(p_target,
138                                                            transformTargetEntry(pstate,
139                                                                                                         res->val,
140                                                                                                         NULL,
141                                                                                                         res->name,
142                                                                                                         false));
143                 }
144
145                 targetlist = lnext(targetlist);
146         }
147
148         return p_target;
149 }
150
151
152 /*
153  * updateTargetListEntry()
154  *      This is used in INSERT and UPDATE statements only.  It prepares a
155  *      TargetEntry for assignment to a column of the target table.
156  *      This includes coercing the given value to the target column's type
157  *      (if necessary), and dealing with any subscripts attached to the target
158  *      column itself.
159  *
160  * pstate               parse state
161  * tle                  target list entry to be modified
162  * colname              target column name (ie, name of attribute to be assigned to)
163  * attrno               target attribute number
164  * indirection  subscripts for target column, if any
165  */
166 void
167 updateTargetListEntry(ParseState *pstate,
168                                           TargetEntry *tle,
169                                           char *colname,
170                                           int attrno,
171                                           List *indirection)
172 {
173         Oid                     type_id = exprType(tle->expr); /* type of value provided */
174         Oid                     attrtype;               /* type of target column */
175         int32           attrtypmod;
176         Resdom     *resnode = tle->resdom;
177         Relation        rd = pstate->p_target_relation;
178
179         Assert(rd != NULL);
180         if (attrno <= 0)
181                 elog(ERROR, "Cannot assign to system attribute '%s'", colname);
182         attrtype = attnumTypeId(rd, attrno);
183         attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
184
185         /*
186          * If there are subscripts on the target column, prepare an
187          * array assignment expression.  This will generate an array value
188          * that the source value has been inserted into, which can then
189          * be placed in the new tuple constructed by INSERT or UPDATE.
190          * Note that transformArraySubscripts takes care of type coercion.
191          */
192         if (indirection)
193         {
194                 Attr       *att = makeNode(Attr);
195                 Node       *arrayBase;
196                 ArrayRef   *aref;
197
198                 att->relname = pstrdup(RelationGetRelationName(rd));
199                 att->attrs = lcons(makeString(colname), NIL);
200                 arrayBase = ParseNestedFuncOrColumn(pstate, att,
201                                                                                         &pstate->p_last_resno,
202                                                                                         EXPR_COLUMN_FIRST);
203                 aref = transformArraySubscripts(pstate, arrayBase,
204                                                                                 indirection,
205                                                                                 pstate->p_is_insert,
206                                                                                 tle->expr);
207                 if (pstate->p_is_insert)
208                 {
209                         /*
210                          * The command is INSERT INTO table (arraycol[subscripts]) ...
211                          * so there is not really a source array value to work with.
212                          * Let the executor do something reasonable, if it can.
213                          * Notice that we forced transformArraySubscripts to treat
214                          * the subscripting op as an array-slice op above, so the
215                          * source data will have been coerced to array type.
216                          */
217                         aref->refexpr = NULL; /* signal there is no source array */
218                 }
219                 tle->expr = (Node *) aref;
220         }
221         else
222         {
223                 /*
224                  * For normal non-subscripted target column, do type checking
225                  * and coercion.  But accept InvalidOid, which indicates the
226                  * source is a NULL constant.
227                  */
228                 if (type_id != InvalidOid)
229                 {
230                         if (type_id != attrtype)
231                         {
232                                 tle->expr = CoerceTargetExpr(pstate, tle->expr,
233                                                                                          type_id, attrtype);
234                                 if (tle->expr == NULL)
235                                         elog(ERROR, "Attribute '%s' is of type '%s'"
236                                                  " but expression is of type '%s'"
237                                                  "\n\tYou will need to rewrite or cast the expression",
238                                                  colname,
239                                                  typeidTypeName(attrtype),
240                                                  typeidTypeName(type_id));
241                         }
242                         /*
243                          * If the target is a fixed-length type, it may need a length
244                          * coercion as well as a type coercion.
245                          */
246                         tle->expr = coerce_type_typmod(pstate, tle->expr,
247                                                                                    attrtype, attrtypmod);
248                 }
249         }
250
251         /*
252          * The result of the target expression should now match the destination
253          * column's type.  Also, reset the resname and resno to identify
254          * the destination column --- rewriter and planner depend on that!
255          */
256         resnode->restype = attrtype;
257         resnode->restypmod = attrtypmod;
258         resnode->resname = colname;
259         resnode->resno = (AttrNumber) attrno;
260 }
261
262
263 Node *
264 CoerceTargetExpr(ParseState *pstate,
265                                  Node *expr,
266                                  Oid type_id,
267                                  Oid attrtype)
268 {
269         if (can_coerce_type(1, &type_id, &attrtype))
270                 expr = coerce_type(pstate, expr, type_id, attrtype, -1);
271
272 #ifndef DISABLE_STRING_HACKS
273
274         /*
275          * string hacks to get transparent conversions w/o explicit
276          * conversions
277          */
278         else if ((attrtype == BPCHAROID) || (attrtype == VARCHAROID))
279         {
280                 Oid                     text_id = TEXTOID;
281
282                 if (type_id == TEXTOID)
283                 {
284                 }
285                 else if (can_coerce_type(1, &type_id, &text_id))
286                         expr = coerce_type(pstate, expr, type_id, text_id, -1);
287                 else
288                         expr = NULL;
289         }
290 #endif
291
292         else
293                 expr = NULL;
294
295         return expr;
296 }
297
298
299 /*
300  * checkInsertTargets -
301  *        generate a list of column names if not supplied or
302  *        test supplied column names to make sure they are in target table.
303  *        Also return an integer list of the columns' attribute numbers.
304  *        (used exclusively for inserts)
305  */
306 List *
307 checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
308 {
309         *attrnos = NIL;
310
311         if (cols == NIL)
312         {
313                 /*
314                  * Generate default column list for INSERT.
315                  */
316                 Form_pg_attribute *attr = pstate->p_target_relation->rd_att->attrs;
317                 int                     numcol = pstate->p_target_relation->rd_rel->relnatts;
318                 int                     i;
319
320                 for (i = 0; i < numcol; i++)
321                 {
322                         Ident      *id = makeNode(Ident);
323
324                         id->name = palloc(NAMEDATALEN);
325                         StrNCpy(id->name, NameStr(attr[i]->attname), NAMEDATALEN);
326                         id->indirection = NIL;
327                         id->isRel = false;
328                         cols = lappend(cols, id);
329                         *attrnos = lappendi(*attrnos, i+1);
330                 }
331         }
332         else
333         {
334                 /*
335                  * Do initial validation of user-supplied INSERT column list.
336                  */
337                 List       *tl;
338
339                 foreach(tl, cols)
340                 {
341                         char       *name = ((Ident *) lfirst(tl))->name;
342                         int                     attrno;
343
344                         /* Lookup column name, elog on failure */
345                         attrno = attnameAttNum(pstate->p_target_relation, name);
346                         /* Check for duplicates */
347                         if (intMember(attrno, *attrnos))
348                                 elog(ERROR, "Attribute '%s' specified more than once", name);
349                         *attrnos = lappendi(*attrnos, attrno);
350                 }
351         }
352
353         return cols;
354 }
355
356 /*
357  * ExpandAllTables -
358  *        turns '*' (in the target list) into a list of attributes
359  *         (of all relations in the range table)
360  */
361 static List *
362 ExpandAllTables(ParseState *pstate)
363 {
364         List       *target = NIL;
365         List       *rt,
366                            *rtable;
367
368         rtable = pstate->p_rtable;
369         if (pstate->p_is_rule)
370         {
371                 /*
372                  * skip first two entries, "*new*" and "*current*"
373                  */
374                 rtable = lnext(lnext(rtable));
375         }
376
377         /* SELECT *; */
378         if (rtable == NIL)
379                 elog(ERROR, "Wildcard with no tables specified.");
380
381         foreach(rt, rtable)
382         {
383                 RangeTblEntry *rte = lfirst(rt);
384
385                 /*
386                  * we only expand those listed in the from clause. (This will
387                  * also prevent us from using the wrong table in inserts: eg.
388                  * tenk2 in "insert into tenk2 select * from tenk1;")
389                  */
390                 if (!rte->inFromCl)
391                         continue;
392
393                 target = nconc(target,
394                                            expandAll(pstate, rte->relname, rte->refname,
395                                                                  &pstate->p_last_resno));
396         }
397         return target;
398 }
399
400 /*
401  * FigureColname -
402  *        if the name of the resulting column is not specified in the target
403  *        list, we have to guess a suitable name.  The SQL spec provides some
404  *        guidance, but not much...
405  *
406  */
407 static char *
408 FigureColname(Node *expr, Node *resval)
409 {
410         /* Some of these are easiest to do with the untransformed node */
411         switch (nodeTag(resval))
412         {
413                 case T_Ident:
414                         return ((Ident *) resval)->name;
415                 case T_Attr:
416                         {
417                                 List       *attrs = ((Attr *) resval)->attrs;
418                                 if (attrs)
419                                 {
420                                         while (lnext(attrs) != NIL)
421                                                 attrs = lnext(attrs);
422                                         return strVal(lfirst(attrs));
423                                 }
424                         }
425                         break;
426                 default:
427                         break;
428         }
429         /* Otherwise, work with the transformed node */
430         switch (nodeTag(expr))
431         {
432                 case T_Expr:
433                         if (((Expr *) expr)->opType == FUNC_EXPR && IsA(resval, FuncCall))
434                                 return ((FuncCall *) resval)->funcname;
435                         break;
436                 case T_Aggref:
437                         return ((Aggref *) expr)->aggname;
438                 case T_CaseExpr:
439                         {
440                                 char       *name;
441
442                                 name = FigureColname(((CaseExpr *) expr)->defresult, resval);
443                                 if (strcmp(name, "?column?") == 0)
444                                         name = "case";
445                                 return name;
446                         }
447                         break;
448                 default:
449                         break;
450         }
451
452         return "?column?";
453 }