Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * parse_target.c
4 : : * handle target lists
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/parser/parse_target.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include "catalog/namespace.h"
18 : : #include "catalog/pg_type.h"
19 : : #include "commands/dbcommands.h"
20 : : #include "funcapi.h"
21 : : #include "miscadmin.h"
22 : : #include "nodes/makefuncs.h"
23 : : #include "nodes/nodeFuncs.h"
24 : : #include "parser/parse_coerce.h"
25 : : #include "parser/parse_expr.h"
26 : : #include "parser/parse_relation.h"
27 : : #include "parser/parse_target.h"
28 : : #include "parser/parse_type.h"
29 : : #include "parser/parsetree.h"
30 : : #include "utils/builtins.h"
31 : : #include "utils/lsyscache.h"
32 : : #include "utils/rel.h"
33 : :
34 : : static void markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
35 : : Var *var, int levelsup);
36 : : static Node *transformAssignmentSubscripts(ParseState *pstate,
37 : : Node *basenode,
38 : : const char *targetName,
39 : : Oid targetTypeId,
40 : : int32 targetTypMod,
41 : : Oid targetCollation,
42 : : List *subscripts,
43 : : List *indirection,
44 : : ListCell *next_indirection,
45 : : Node *rhs,
46 : : CoercionContext ccontext,
47 : : int location);
48 : : static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
49 : : bool make_target_entry);
50 : : static List *ExpandAllTables(ParseState *pstate, int location);
51 : : static List *ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind,
52 : : bool make_target_entry, ParseExprKind exprKind);
53 : : static List *ExpandSingleTable(ParseState *pstate, ParseNamespaceItem *nsitem,
54 : : int sublevels_up, int location,
55 : : bool make_target_entry);
56 : : static List *ExpandRowReference(ParseState *pstate, Node *expr,
57 : : bool make_target_entry);
58 : : static int FigureColnameInternal(Node *node, char **name);
59 : :
60 : :
61 : : /*
62 : : * transformTargetEntry()
63 : : * Transform any ordinary "expression-type" node into a targetlist entry.
64 : : * This is exported so that parse_clause.c can generate targetlist entries
65 : : * for ORDER/GROUP BY items that are not already in the targetlist.
66 : : *
67 : : * node the (untransformed) parse tree for the value expression.
68 : : * expr the transformed expression, or NULL if caller didn't do it yet.
69 : : * exprKind expression kind (EXPR_KIND_SELECT_TARGET, etc)
70 : : * colname the column name to be assigned, or NULL if none yet set.
71 : : * resjunk true if the target should be marked resjunk, ie, it is not
72 : : * wanted in the final projected tuple.
73 : : */
74 : : TargetEntry *
9036 tgl@sss.pgh.pa.us 75 :CBC 494365 : transformTargetEntry(ParseState *pstate,
76 : : Node *node,
77 : : Node *expr,
78 : : ParseExprKind exprKind,
79 : : char *colname,
80 : : bool resjunk)
81 : : {
82 : : /* Transform the node if caller didn't do it already */
9366 bruce@momjian.us 83 [ + + ]: 494365 : if (expr == NULL)
84 : : {
85 : : /*
86 : : * If it's a SetToDefault node and we should allow that, pass it
87 : : * through unmodified. (transformExpr will throw the appropriate
88 : : * error if we're disallowing it.)
89 : : */
2700 tgl@sss.pgh.pa.us 90 [ + + + + ]: 482893 : if (exprKind == EXPR_KIND_UPDATE_SOURCE && IsA(node, SetToDefault))
91 : 94 : expr = node;
92 : : else
93 : 482799 : expr = transformExpr(pstate, node, exprKind);
94 : : }
95 : :
7552 96 [ + + + + ]: 491980 : if (colname == NULL && !resjunk)
97 : : {
98 : : /*
99 : : * Generate a suitable column name for a column without any explicit
100 : : * 'AS ColumnName' clause.
101 : : */
8245 102 : 378270 : colname = FigureColname(node);
103 : : }
104 : :
6948 105 : 983960 : return makeTargetEntry((Expr *) expr,
106 : 491980 : (AttrNumber) pstate->p_next_resno++,
107 : : colname,
108 : : resjunk);
109 : : }
110 : :
111 : :
112 : : /*
113 : : * transformTargetList()
114 : : * Turns a list of ResTarget's into a list of TargetEntry's.
115 : : *
116 : : * This code acts mostly the same for SELECT, UPDATE, or RETURNING lists;
117 : : * the main thing is to transform the given expressions (the "val" fields).
118 : : * The exprKind parameter distinguishes these cases when necessary.
119 : : */
120 : : List *
4265 121 : 233576 : transformTargetList(ParseState *pstate, List *targetlist,
122 : : ParseExprKind exprKind)
123 : : {
7257 124 : 233576 : List *p_target = NIL;
125 : : bool expand_star;
126 : : ListCell *o_target;
127 : :
128 : : /* Shouldn't have any leftover multiassign items at start */
3588 129 [ - + ]: 233576 : Assert(pstate->p_multiassign_exprs == NIL);
130 : :
131 : : /* Expand "something.*" in SELECT and RETURNING, but not UPDATE */
2702 132 : 233576 : expand_star = (exprKind != EXPR_KIND_UPDATE_SOURCE);
133 : :
7552 134 [ + + + + : 740506 : foreach(o_target, targetlist)
+ + ]
135 : : {
136 : 509318 : ResTarget *res = (ResTarget *) lfirst(o_target);
137 : :
138 : : /*
139 : : * Check for "something.*". Depending on the complexity of the
140 : : * "something", the star could appear as the last field in ColumnRef,
141 : : * or as the last indirection item in A_Indirection.
142 : : */
2702 143 [ + + ]: 509318 : if (expand_star)
144 : : {
145 [ + + ]: 499561 : if (IsA(res->val, ColumnRef))
146 : : {
147 : 268504 : ColumnRef *cref = (ColumnRef *) res->val;
148 : :
149 [ + + ]: 268504 : if (IsA(llast(cref->fields), A_Star))
150 : : {
151 : : /* It is something.*, expand into multiple items */
152 : 25814 : p_target = list_concat(p_target,
153 : 25817 : ExpandColumnRefStar(pstate,
154 : : cref,
155 : : true));
156 : 25814 : continue;
157 : : }
158 : : }
159 [ + + ]: 231057 : else if (IsA(res->val, A_Indirection))
160 : : {
161 : 1641 : A_Indirection *ind = (A_Indirection *) res->val;
162 : :
163 [ + + ]: 1641 : if (IsA(llast(ind->indirection), A_Star))
164 : : {
165 : : /* It is something.*, expand into multiple items */
166 : 608 : p_target = list_concat(p_target,
167 : 608 : ExpandIndirectionStar(pstate,
168 : : ind,
169 : : true,
170 : : exprKind));
171 : 608 : continue;
172 : : }
173 : : }
174 : : }
175 : :
176 : : /*
177 : : * Not "something.*", or we want to treat that as a plain whole-row
178 : : * variable, so transform as a single expression
179 : : */
7239 180 : 480508 : p_target = lappend(p_target,
181 : 482893 : transformTargetEntry(pstate,
182 : : res->val,
183 : : NULL,
184 : : exprKind,
185 : : res->name,
186 : : false));
187 : : }
188 : :
189 : : /*
190 : : * If any multiassign resjunk items were created, attach them to the end
191 : : * of the targetlist. This should only happen in an UPDATE tlist. We
192 : : * don't need to worry about numbering of these items; transformUpdateStmt
193 : : * will set their resnos.
194 : : */
3588 195 [ + + ]: 231188 : if (pstate->p_multiassign_exprs)
196 : : {
197 [ - + ]: 69 : Assert(exprKind == EXPR_KIND_UPDATE_SOURCE);
198 : 69 : p_target = list_concat(p_target, pstate->p_multiassign_exprs);
199 : 69 : pstate->p_multiassign_exprs = NIL;
200 : : }
201 : :
7257 202 : 231188 : return p_target;
203 : : }
204 : :
205 : :
206 : : /*
207 : : * transformExpressionList()
208 : : *
209 : : * This is the identical transformation to transformTargetList, except that
210 : : * the input list elements are bare expressions without ResTarget decoration,
211 : : * and the output elements are likewise just expressions without TargetEntry
212 : : * decoration. Also, we don't expect any multiassign constructs within the
213 : : * list, so there's nothing to do for that. We use this for ROW() and
214 : : * VALUES() constructs.
215 : : *
216 : : * exprKind is not enough to tell us whether to allow SetToDefault, so
217 : : * an additional flag is needed for that.
218 : : */
219 : : List *
4265 220 : 43991 : transformExpressionList(ParseState *pstate, List *exprlist,
221 : : ParseExprKind exprKind, bool allowDefault)
222 : : {
6465 mail@joeconway.com 223 : 43991 : List *result = NIL;
224 : : ListCell *lc;
225 : :
226 [ + + + + : 132371 : foreach(lc, exprlist)
+ + ]
227 : : {
228 : 88402 : Node *e = (Node *) lfirst(lc);
229 : :
230 : : /*
231 : : * Check for "something.*". Depending on the complexity of the
232 : : * "something", the star could appear as the last field in ColumnRef,
233 : : * or as the last indirection item in A_Indirection.
234 : : */
235 [ + + ]: 88402 : if (IsA(e, ColumnRef))
236 : : {
237 : 3837 : ColumnRef *cref = (ColumnRef *) e;
238 : :
5706 tgl@sss.pgh.pa.us 239 [ + + ]: 3837 : if (IsA(llast(cref->fields), A_Star))
240 : : {
241 : : /* It is something.*, expand into multiple items */
6465 mail@joeconway.com 242 : 144 : result = list_concat(result,
243 : 144 : ExpandColumnRefStar(pstate, cref,
244 : : false));
245 : 144 : continue;
246 : : }
247 : : }
248 [ + + ]: 84565 : else if (IsA(e, A_Indirection))
249 : : {
250 : 12 : A_Indirection *ind = (A_Indirection *) e;
251 : :
5706 tgl@sss.pgh.pa.us 252 [ - + ]: 12 : if (IsA(llast(ind->indirection), A_Star))
253 : : {
254 : : /* It is something.*, expand into multiple items */
6465 mail@joeconway.com 255 :UBC 0 : result = list_concat(result,
256 : 0 : ExpandIndirectionStar(pstate, ind,
257 : : false, exprKind));
258 : 0 : continue;
259 : : }
260 : : }
261 : :
262 : : /*
263 : : * Not "something.*", so transform as a single expression. If it's a
264 : : * SetToDefault node and we should allow that, pass it through
265 : : * unmodified. (transformExpr will throw the appropriate error if
266 : : * we're disallowing it.)
267 : : */
2700 tgl@sss.pgh.pa.us 268 [ + + + + ]:CBC 88258 : if (allowDefault && IsA(e, SetToDefault))
269 : : /* do nothing */ ;
270 : : else
271 : 87677 : e = transformExpr(pstate, e, exprKind);
272 : :
273 : 88236 : result = lappend(result, e);
274 : : }
275 : :
6465 mail@joeconway.com 276 : 43969 : return result;
277 : : }
278 : :
279 : :
280 : : /*
281 : : * resolveTargetListUnknowns()
282 : : * Convert any unknown-type targetlist entries to type TEXT.
283 : : *
284 : : * We do this after we've exhausted all other ways of identifying the output
285 : : * column types of a query.
286 : : */
287 : : void
2636 tgl@sss.pgh.pa.us 288 : 208060 : resolveTargetListUnknowns(ParseState *pstate, List *targetlist)
289 : : {
290 : : ListCell *l;
291 : :
292 [ + + + + : 734453 : foreach(l, targetlist)
+ + ]
293 : : {
294 : 526393 : TargetEntry *tle = (TargetEntry *) lfirst(l);
295 : 526393 : Oid restype = exprType((Node *) tle->expr);
296 : :
297 [ + + ]: 526393 : if (restype == UNKNOWNOID)
298 : : {
299 : 3791 : tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
300 : : restype, TEXTOID, -1,
301 : : COERCION_IMPLICIT,
302 : : COERCE_IMPLICIT_CAST,
303 : : -1);
304 : : }
305 : : }
306 : 208060 : }
307 : :
308 : :
309 : : /*
310 : : * markTargetListOrigins()
311 : : * Mark targetlist columns that are simple Vars with the source
312 : : * table's OID and column number.
313 : : *
314 : : * Currently, this is done only for SELECT targetlists and RETURNING lists,
315 : : * since we only need the info if we are going to send it to the frontend.
316 : : */
317 : : void
7649 318 : 220345 : markTargetListOrigins(ParseState *pstate, List *targetlist)
319 : : {
320 : : ListCell *l;
321 : :
322 [ + + + + : 777007 : foreach(l, targetlist)
+ + ]
323 : : {
324 : 556662 : TargetEntry *tle = (TargetEntry *) lfirst(l);
325 : :
6948 326 : 556662 : markTargetListOrigin(pstate, tle, (Var *) tle->expr, 0);
327 : : }
7649 328 : 220345 : }
329 : :
330 : : /*
331 : : * markTargetListOrigin()
332 : : * If 'var' is a Var of a plain relation, mark 'tle' with its origin
333 : : *
334 : : * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
335 : : *
336 : : * Note that we do not drill down into views, but report the view as the
337 : : * column owner. There's also no need to drill down into joins: if we see
338 : : * a join alias Var, it must be a merged JOIN USING column (or possibly a
339 : : * whole-row Var); that is not a direct reference to any plain table column,
340 : : * so we don't report it.
341 : : */
342 : : static void
6948 343 : 556662 : markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
344 : : Var *var, int levelsup)
345 : : {
346 : : int netlevelsup;
347 : : RangeTblEntry *rte;
348 : : AttrNumber attnum;
349 : :
7649 350 [ + - + + ]: 556662 : if (var == NULL || !IsA(var, Var))
351 : 233439 : return;
7031 352 : 323223 : netlevelsup = var->varlevelsup + levelsup;
353 : 323223 : rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);
7649 354 : 323223 : attnum = var->varattno;
355 : :
356 [ + + + + : 323223 : switch (rte->rtekind)
- ]
357 : : {
358 : 269919 : case RTE_RELATION:
359 : : /* It's a table or view, report it */
6948 360 : 269919 : tle->resorigtbl = rte->relid;
361 : 269919 : tle->resorigcol = attnum;
7649 362 : 269919 : break;
363 : 6831 : case RTE_SUBQUERY:
364 : : /* Subselect-in-FROM: copy up from the subselect */
6929 365 [ + + ]: 6831 : if (attnum != InvalidAttrNumber)
366 : : {
6948 367 : 6801 : TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
368 : : attnum);
369 : :
370 [ + - - + ]: 6801 : if (ste == NULL || ste->resjunk)
7575 tgl@sss.pgh.pa.us 371 [ # # ]:UBC 0 : elog(ERROR, "subquery %s does not have attribute %d",
372 : : rte->eref->aliasname, attnum);
6948 tgl@sss.pgh.pa.us 373 :CBC 6801 : tle->resorigtbl = ste->resorigtbl;
374 : 6801 : tle->resorigcol = ste->resorigcol;
375 : : }
7649 376 : 6831 : break;
377 : 42623 : case RTE_JOIN:
378 : : case RTE_FUNCTION:
379 : : case RTE_VALUES:
380 : : case RTE_TABLEFUNC:
381 : : case RTE_NAMEDTUPLESTORE:
382 : : case RTE_RESULT:
383 : : /* not a simple relation, leave it unmarked */
384 : 42623 : break;
5671 385 : 3850 : case RTE_CTE:
386 : :
387 : : /*
388 : : * CTE reference: copy up from the subquery, if possible. If the
389 : : * RTE is a recursive self-reference then we can't do anything
390 : : * because we haven't finished analyzing it yet. However, it's no
391 : : * big loss because we must be down inside the recursive term of a
392 : : * recursive CTE, and so any markings on the current targetlist
393 : : * are not going to affect the results anyway.
394 : : */
5670 395 [ + + + + ]: 3850 : if (attnum != InvalidAttrNumber && !rte->self_reference)
396 : : {
5669 397 : 3600 : CommonTableExpr *cte = GetCTEForRTE(pstate, rte, netlevelsup);
398 : : TargetEntry *ste;
1168 peter@eisentraut.org 399 [ - + + + ]: 3600 : List *tl = GetCTETargetList(cte);
400 : 3600 : int extra_cols = 0;
401 : :
402 : : /*
403 : : * RTE for CTE will already have the search and cycle columns
404 : : * added, but the subquery won't, so skip looking those up.
405 : : */
406 [ + + ]: 3600 : if (cte->search_clause)
407 : 147 : extra_cols += 1;
408 [ + + ]: 3600 : if (cte->cycle_clause)
409 : 144 : extra_cols += 2;
410 [ + + + + ]: 3855 : if (extra_cols &&
411 : 255 : attnum > list_length(tl) &&
412 [ + - ]: 93 : attnum <= list_length(tl) + extra_cols)
413 : 93 : break;
414 : :
415 : 3507 : ste = get_tle_by_resno(tl, attnum);
5671 tgl@sss.pgh.pa.us 416 [ + - - + ]: 3507 : if (ste == NULL || ste->resjunk)
1278 peter@eisentraut.org 417 [ # # ]:UBC 0 : elog(ERROR, "CTE %s does not have attribute %d",
418 : : rte->eref->aliasname, attnum);
5671 tgl@sss.pgh.pa.us 419 :CBC 3507 : tle->resorigtbl = ste->resorigtbl;
420 : 3507 : tle->resorigcol = ste->resorigcol;
421 : : }
422 : 3757 : break;
423 : : }
424 : : }
425 : :
426 : :
427 : : /*
428 : : * transformAssignedExpr()
429 : : * This is used in INSERT and UPDATE statements only. It prepares an
430 : : * expression for assignment to a column of the target table.
431 : : * This includes coercing the given value to the target column's type
432 : : * (if necessary), and dealing with any subfield names or subscripts
433 : : * attached to the target column itself. The input expression has
434 : : * already been through transformExpr().
435 : : *
436 : : * pstate parse state
437 : : * expr expression to be modified
438 : : * exprKind indicates which type of statement we're dealing with
439 : : * colname target column name (ie, name of attribute to be assigned to)
440 : : * attrno target attribute number
441 : : * indirection subscripts/field names for target column, if any
442 : : * location error cursor position for the target column, or -1
443 : : *
444 : : * Returns the modified expression.
445 : : *
446 : : * Note: location points at the target column name (SET target or INSERT
447 : : * column name list entry), and must therefore be -1 in an INSERT that
448 : : * omits the column name list. So we should usually prefer to use
449 : : * exprLocation(expr) for errors that can happen in a default INSERT.
450 : : */
451 : : Expr *
6465 mail@joeconway.com 452 : 89399 : transformAssignedExpr(ParseState *pstate,
453 : : Expr *expr,
454 : : ParseExprKind exprKind,
455 : : const char *colname,
456 : : int attrno,
457 : : List *indirection,
458 : : int location)
459 : : {
4265 tgl@sss.pgh.pa.us 460 : 89399 : Relation rd = pstate->p_target_relation;
461 : : Oid type_id; /* type of value provided */
462 : : Oid attrtype; /* type of target column */
463 : : int32 attrtypmod;
464 : : Oid attrcollation; /* collation of target column */
465 : : ParseExprKind sv_expr_kind;
466 : :
467 : : /*
468 : : * Save and restore identity of expression type we're parsing. We must
469 : : * set p_expr_kind here because we can parse subscripts without going
470 : : * through transformExpr().
471 : : */
472 [ - + ]: 89399 : Assert(exprKind != EXPR_KIND_NONE);
473 : 89399 : sv_expr_kind = pstate->p_expr_kind;
474 : 89399 : pstate->p_expr_kind = exprKind;
475 : :
9036 476 [ - + ]: 89399 : Assert(rd != NULL);
8931 477 [ - + ]: 89399 : if (attrno <= 0)
7575 tgl@sss.pgh.pa.us 478 [ # # ]:UBC 0 : ereport(ERROR,
479 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
480 : : errmsg("cannot assign to system column \"%s\"",
481 : : colname),
482 : : parser_errposition(pstate, location)));
8931 tgl@sss.pgh.pa.us 483 :CBC 89399 : attrtype = attnumTypeId(rd, attrno);
2429 andres@anarazel.de 484 : 89399 : attrtypmod = TupleDescAttr(rd->rd_att, attrno - 1)->atttypmod;
485 : 89399 : attrcollation = TupleDescAttr(rd->rd_att, attrno - 1)->attcollation;
486 : :
487 : : /*
488 : : * If the expression is a DEFAULT placeholder, insert the attribute's
489 : : * type/typmod/collation into it so that exprType etc will report the
490 : : * right things. (We expect that the eventually substituted default
491 : : * expression will in fact have this type and typmod. The collation
492 : : * likely doesn't matter, but let's set it correctly anyway.) Also,
493 : : * reject trying to update a subfield or array element with DEFAULT, since
494 : : * there can't be any default for portions of a column.
495 : : */
6465 mail@joeconway.com 496 [ + - + + ]: 89399 : if (expr && IsA(expr, SetToDefault))
497 : : {
498 : 660 : SetToDefault *def = (SetToDefault *) expr;
499 : :
7591 tgl@sss.pgh.pa.us 500 : 660 : def->typeId = attrtype;
501 : 660 : def->typeMod = attrtypmod;
4775 502 : 660 : def->collation = attrcollation;
7591 503 [ + + ]: 660 : if (indirection)
504 : : {
7249 505 [ + + ]: 12 : if (IsA(linitial(indirection), A_Indices))
506 [ + - ]: 6 : ereport(ERROR,
507 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
508 : : errmsg("cannot set an array element to DEFAULT"),
509 : : parser_errposition(pstate, location)));
510 : : else
511 [ + - ]: 6 : ereport(ERROR,
512 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
513 : : errmsg("cannot set a subfield to DEFAULT"),
514 : : parser_errposition(pstate, location)));
515 : : }
516 : : }
517 : :
518 : : /* Now we can use exprType() safely. */
6465 mail@joeconway.com 519 : 89387 : type_id = exprType((Node *) expr);
520 : :
521 : : /*
522 : : * If there is indirection on the target column, prepare an array or
523 : : * subfield assignment expression. This will generate a new column value
524 : : * that the source value has been inserted into, which can then be placed
525 : : * in the new tuple constructed by INSERT or UPDATE.
526 : : */
9036 tgl@sss.pgh.pa.us 527 [ + + ]: 89387 : if (indirection)
528 : : {
529 : : Node *colVar;
530 : :
531 [ + + ]: 915 : if (pstate->p_is_insert)
532 : : {
533 : : /*
534 : : * The command is INSERT INTO table (col.something) ... so there
535 : : * is not really a source value to work with. Insert a NULL
536 : : * constant as the source value.
537 : : */
4769 538 : 519 : colVar = (Node *) makeNullConst(attrtype, attrtypmod,
539 : : attrcollation);
540 : : }
541 : : else
542 : : {
543 : : /*
544 : : * Build a Var for the column to be updated.
545 : : */
546 : : Var *var;
547 : :
1564 548 : 396 : var = makeVar(pstate->p_target_nsitem->p_rtindex, attrno,
549 : : attrtype, attrtypmod, attrcollation, 0);
1571 550 : 396 : var->location = location;
551 : :
552 : 396 : colVar = (Node *) var;
553 : : }
554 : :
555 : : expr = (Expr *)
7249 556 : 915 : transformAssignmentIndirection(pstate,
557 : : colVar,
558 : : colname,
559 : : false,
560 : : attrtype,
561 : : attrtypmod,
562 : : attrcollation,
563 : : indirection,
564 : : list_head(indirection),
565 : : (Node *) expr,
566 : : COERCION_ASSIGNMENT,
567 : : location);
568 : : }
569 : : else
570 : : {
571 : : /*
572 : : * For normal non-qualified target column, do type checking and
573 : : * coercion.
574 : : */
5421 bruce@momjian.us 575 : 88472 : Node *orig_expr = (Node *) expr;
576 : :
577 : : expr = (Expr *)
7249 tgl@sss.pgh.pa.us 578 : 88472 : coerce_to_target_type(pstate,
579 : : orig_expr, type_id,
580 : : attrtype, attrtypmod,
581 : : COERCION_ASSIGNMENT,
582 : : COERCE_IMPLICIT_CAST,
583 : : -1);
6465 mail@joeconway.com 584 [ + + ]: 87962 : if (expr == NULL)
7249 tgl@sss.pgh.pa.us 585 [ + - ]: 71 : ereport(ERROR,
586 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
587 : : errmsg("column \"%s\" is of type %s"
588 : : " but expression is of type %s",
589 : : colname,
590 : : format_type_be(attrtype),
591 : : format_type_be(type_id)),
592 : : errhint("You will need to rewrite or cast the expression."),
593 : : parser_errposition(pstate, exprLocation(orig_expr))));
594 : : }
595 : :
4265 596 : 88797 : pstate->p_expr_kind = sv_expr_kind;
597 : :
6465 mail@joeconway.com 598 : 88797 : return expr;
599 : : }
600 : :
601 : :
602 : : /*
603 : : * updateTargetListEntry()
604 : : * This is used in UPDATE statements (and ON CONFLICT DO UPDATE)
605 : : * only. It prepares an UPDATE TargetEntry for assignment to a
606 : : * column of the target table. This includes coercing the given
607 : : * value to the target column's type (if necessary), and dealing with
608 : : * any subfield names or subscripts attached to the target column
609 : : * itself.
610 : : *
611 : : * pstate parse state
612 : : * tle target list entry to be modified
613 : : * colname target column name (ie, name of attribute to be assigned to)
614 : : * attrno target attribute number
615 : : * indirection subscripts/field names for target column, if any
616 : : * location error cursor position (should point at column name), or -1
617 : : */
618 : : void
619 : 9721 : updateTargetListEntry(ParseState *pstate,
620 : : TargetEntry *tle,
621 : : char *colname,
622 : : int attrno,
623 : : List *indirection,
624 : : int location)
625 : : {
626 : : /* Fix up expression as needed */
627 : 9721 : tle->expr = transformAssignedExpr(pstate,
628 : : tle->expr,
629 : : EXPR_KIND_UPDATE_TARGET,
630 : : colname,
631 : : attrno,
632 : : indirection,
633 : : location);
634 : :
635 : : /*
636 : : * Set the resno to identify the target column --- the rewriter and
637 : : * planner depend on this. We also set the resname to identify the target
638 : : * column, but this is only for debugging purposes; it should not be
639 : : * relied on. (In particular, it might be out of date in a stored rule.)
640 : : */
6948 tgl@sss.pgh.pa.us 641 : 9715 : tle->resno = (AttrNumber) attrno;
642 : 9715 : tle->resname = colname;
9036 643 : 9715 : }
644 : :
645 : :
646 : : /*
647 : : * Process indirection (field selection or subscripting) of the target
648 : : * column in INSERT/UPDATE/assignment. This routine recurses for multiple
649 : : * levels of indirection --- but note that several adjacent A_Indices nodes
650 : : * in the indirection list are treated as a single multidimensional subscript
651 : : * operation.
652 : : *
653 : : * In the initial call, basenode is a Var for the target column in UPDATE,
654 : : * or a null Const of the target's type in INSERT, or a Param for the target
655 : : * variable in PL/pgSQL assignment. In recursive calls, basenode is NULL,
656 : : * indicating that a substitute node should be consed up if needed.
657 : : *
658 : : * targetName is the name of the field or subfield we're assigning to, and
659 : : * targetIsSubscripting is true if we're subscripting it. These are just for
660 : : * error reporting.
661 : : *
662 : : * targetTypeId, targetTypMod, targetCollation indicate the datatype and
663 : : * collation of the object to be assigned to (initially the target column,
664 : : * later some subobject).
665 : : *
666 : : * indirection is the list of indirection nodes, and indirection_cell is the
667 : : * start of the sublist remaining to process. When it's NULL, we're done
668 : : * recursing and can just coerce and return the RHS.
669 : : *
670 : : * rhs is the already-transformed value to be assigned; note it has not been
671 : : * coerced to any particular type.
672 : : *
673 : : * ccontext is the coercion level to use while coercing the rhs. For
674 : : * normal statements it'll be COERCION_ASSIGNMENT, but PL/pgSQL uses
675 : : * a special value.
676 : : *
677 : : * location is the cursor error position for any errors. (Note: this points
678 : : * to the head of the target clause, eg "foo" in "foo.bar[baz]". Later we
679 : : * might want to decorate indirection cells with their own location info,
680 : : * in which case the location argument could probably be dropped.)
681 : : */
682 : : Node *
7249 683 : 2270 : transformAssignmentIndirection(ParseState *pstate,
684 : : Node *basenode,
685 : : const char *targetName,
686 : : bool targetIsSubscripting,
687 : : Oid targetTypeId,
688 : : int32 targetTypMod,
689 : : Oid targetCollation,
690 : : List *indirection,
691 : : ListCell *indirection_cell,
692 : : Node *rhs,
693 : : CoercionContext ccontext,
694 : : int location)
695 : : {
696 : : Node *result;
697 : 2270 : List *subscripts = NIL;
698 : : ListCell *i;
699 : :
1735 700 [ + + + + ]: 2270 : if (indirection_cell && !basenode)
701 : : {
702 : : /*
703 : : * Set up a substitution. We abuse CaseTestExpr for this. It's safe
704 : : * to do so because the only nodes that will be above the CaseTestExpr
705 : : * in the finished expression will be FieldStore and SubscriptingRef
706 : : * nodes. (There could be other stuff in the tree, but it will be
707 : : * within other child fields of those node types.)
708 : : */
7249 709 : 337 : CaseTestExpr *ctest = makeNode(CaseTestExpr);
710 : :
711 : 337 : ctest->typeId = targetTypeId;
712 : 337 : ctest->typeMod = targetTypMod;
4768 713 : 337 : ctest->collation = targetCollation;
7249 714 : 337 : basenode = (Node *) ctest;
715 : : }
716 : :
717 : : /*
718 : : * We have to split any field-selection operations apart from
719 : : * subscripting. Adjacent A_Indices nodes have to be treated as a single
720 : : * multidimensional subscript operation.
721 : : */
1735 722 [ + - + + : 3308 : for_each_cell(i, indirection, indirection_cell)
+ + ]
723 : : {
7168 bruce@momjian.us 724 : 1632 : Node *n = lfirst(i);
725 : :
7249 tgl@sss.pgh.pa.us 726 [ + + ]: 1632 : if (IsA(n, A_Indices))
727 : 1038 : subscripts = lappend(subscripts, n);
5706 728 [ - + ]: 594 : else if (IsA(n, A_Star))
729 : : {
5706 tgl@sss.pgh.pa.us 730 [ # # ]:UBC 0 : ereport(ERROR,
731 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
732 : : errmsg("row expansion via \"*\" is not supported here"),
733 : : parser_errposition(pstate, location)));
734 : : }
735 : : else
736 : : {
737 : : FieldStore *fstore;
738 : : Oid baseTypeId;
739 : : int32 baseTypeMod;
740 : : Oid typrelid;
741 : : AttrNumber attnum;
742 : : Oid fieldTypeId;
743 : : int32 fieldTypMod;
744 : : Oid fieldCollation;
745 : :
7249 tgl@sss.pgh.pa.us 746 [ - + ]:CBC 594 : Assert(IsA(n, String));
747 : :
748 : : /* process subscripts before this field selection */
749 [ + + ]: 594 : if (subscripts)
750 : : {
751 : : /* recurse, and then return because we're done */
4924 752 : 172 : return transformAssignmentSubscripts(pstate,
753 : : basenode,
754 : : targetName,
755 : : targetTypeId,
756 : : targetTypMod,
757 : : targetCollation,
758 : : subscripts,
759 : : indirection,
760 : : i,
761 : : rhs,
762 : : ccontext,
763 : : location);
764 : : }
765 : :
766 : : /* No subscripts, so can process field selection here */
767 : :
768 : : /*
769 : : * Look up the composite type, accounting for possibility that
770 : : * what we are given is a domain over composite.
771 : : */
2362 772 : 422 : baseTypeMod = targetTypMod;
773 : 422 : baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod);
774 : :
775 : 422 : typrelid = typeidTypeRelid(baseTypeId);
7249 776 [ + + ]: 422 : if (!typrelid)
777 [ + - ]: 1 : ereport(ERROR,
778 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
779 : : errmsg("cannot assign to field \"%s\" of column \"%s\" because its type %s is not a composite type",
780 : : strVal(n), targetName,
781 : : format_type_be(targetTypeId)),
782 : : parser_errposition(pstate, location)));
783 : :
784 : 421 : attnum = get_attnum(typrelid, strVal(n));
785 [ + + ]: 421 : if (attnum == InvalidAttrNumber)
786 [ + - ]: 2 : ereport(ERROR,
787 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
788 : : errmsg("cannot assign to field \"%s\" of column \"%s\" because there is no such column in data type %s",
789 : : strVal(n), targetName,
790 : : format_type_be(targetTypeId)),
791 : : parser_errposition(pstate, location)));
792 [ - + ]: 419 : if (attnum < 0)
7249 tgl@sss.pgh.pa.us 793 [ # # ]:UBC 0 : ereport(ERROR,
794 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
795 : : errmsg("cannot assign to system column \"%s\"",
796 : : strVal(n)),
797 : : parser_errposition(pstate, location)));
798 : :
4768 tgl@sss.pgh.pa.us 799 :CBC 419 : get_atttypetypmodcoll(typrelid, attnum,
800 : : &fieldTypeId, &fieldTypMod, &fieldCollation);
801 : :
802 : : /* recurse to create appropriate RHS for field assign */
7249 803 : 419 : rhs = transformAssignmentIndirection(pstate,
804 : : NULL,
805 : 419 : strVal(n),
806 : : false,
807 : : fieldTypeId,
808 : : fieldTypMod,
809 : : fieldCollation,
810 : : indirection,
811 : : lnext(indirection, i),
812 : : rhs,
813 : : ccontext,
814 : : location);
815 : :
816 : : /* and build a FieldStore node */
817 : 416 : fstore = makeNode(FieldStore);
818 : 416 : fstore->arg = (Expr *) basenode;
819 : 416 : fstore->newvals = list_make1(rhs);
820 : 416 : fstore->fieldnums = list_make1_int(attnum);
2362 821 : 416 : fstore->resulttype = baseTypeId;
822 : :
823 : : /*
824 : : * If target is a domain, apply constraints. Notice that this
825 : : * isn't totally right: the expression tree we build would check
826 : : * the domain's constraints on a composite value with only this
827 : : * one field populated or updated, possibly leading to an unwanted
828 : : * failure. The rewriter will merge together any subfield
829 : : * assignments to the same table column, resulting in the domain's
830 : : * constraints being checked only once after we've assigned to all
831 : : * the fields that the INSERT or UPDATE means to.
832 : : */
833 [ + + ]: 416 : if (baseTypeId != targetTypeId)
834 : 216 : return coerce_to_domain((Node *) fstore,
835 : : baseTypeId, baseTypeMod,
836 : : targetTypeId,
837 : : COERCION_IMPLICIT,
838 : : COERCE_IMPLICIT_CAST,
839 : : location,
840 : : false);
841 : :
7249 842 : 200 : return (Node *) fstore;
843 : : }
844 : : }
845 : :
846 : : /* process trailing subscripts, if any */
847 [ + + ]: 1676 : if (subscripts)
848 : : {
849 : : /* recurse, and then return because we're done */
4924 850 : 712 : return transformAssignmentSubscripts(pstate,
851 : : basenode,
852 : : targetName,
853 : : targetTypeId,
854 : : targetTypMod,
855 : : targetCollation,
856 : : subscripts,
857 : : indirection,
858 : : NULL,
859 : : rhs,
860 : : ccontext,
861 : : location);
862 : : }
863 : :
864 : : /* base case: just coerce RHS to match target type ID */
865 : :
7249 866 : 964 : result = coerce_to_target_type(pstate,
867 : : rhs, exprType(rhs),
868 : : targetTypeId, targetTypMod,
869 : : ccontext,
870 : : COERCE_IMPLICIT_CAST,
871 : : -1);
872 [ + + ]: 964 : if (result == NULL)
873 : : {
1899 alvherre@alvh.no-ip. 874 [ + + ]: 9 : if (targetIsSubscripting)
7249 tgl@sss.pgh.pa.us 875 [ + - ]: 6 : ereport(ERROR,
876 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
877 : : errmsg("subscripted assignment to \"%s\" requires type %s"
878 : : " but expression is of type %s",
879 : : targetName,
880 : : format_type_be(targetTypeId),
881 : : format_type_be(exprType(rhs))),
882 : : errhint("You will need to rewrite or cast the expression."),
883 : : parser_errposition(pstate, location)));
884 : : else
885 [ + - ]: 3 : ereport(ERROR,
886 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
887 : : errmsg("subfield \"%s\" is of type %s"
888 : : " but expression is of type %s",
889 : : targetName,
890 : : format_type_be(targetTypeId),
891 : : format_type_be(exprType(rhs))),
892 : : errhint("You will need to rewrite or cast the expression."),
893 : : parser_errposition(pstate, location)));
894 : : }
895 : :
896 : 955 : return result;
897 : : }
898 : :
899 : : /*
900 : : * helper for transformAssignmentIndirection: process container assignment
901 : : */
902 : : static Node *
4924 903 : 884 : transformAssignmentSubscripts(ParseState *pstate,
904 : : Node *basenode,
905 : : const char *targetName,
906 : : Oid targetTypeId,
907 : : int32 targetTypMod,
908 : : Oid targetCollation,
909 : : List *subscripts,
910 : : List *indirection,
911 : : ListCell *next_indirection,
912 : : Node *rhs,
913 : : CoercionContext ccontext,
914 : : int location)
915 : : {
916 : : Node *result;
917 : : SubscriptingRef *sbsref;
918 : : Oid containerType;
919 : : int32 containerTypMod;
920 : : Oid typeNeeded;
921 : : int32 typmodNeeded;
922 : : Oid collationNeeded;
923 : :
924 [ - + ]: 884 : Assert(subscripts != NIL);
925 : :
926 : : /* Identify the actual container type involved */
1899 alvherre@alvh.no-ip. 927 : 884 : containerType = targetTypeId;
928 : 884 : containerTypMod = targetTypMod;
1222 tgl@sss.pgh.pa.us 929 : 884 : transformContainerType(&containerType, &containerTypMod);
930 : :
931 : : /* Process subscripts and identify required type for RHS */
932 : 884 : sbsref = transformContainerSubscripts(pstate,
933 : : basenode,
934 : : containerType,
935 : : containerTypMod,
936 : : subscripts,
937 : : true);
938 : :
939 : 882 : typeNeeded = sbsref->refrestype;
940 : 882 : typmodNeeded = sbsref->reftypmod;
941 : :
942 : : /*
943 : : * Container normally has same collation as its elements, but there's an
944 : : * exception: we might be subscripting a domain over a container type. In
945 : : * that case use collation of the base type. (This is shaky for arbitrary
946 : : * subscripting semantics, but it doesn't matter all that much since we
947 : : * only use this to label the collation of a possible CaseTestExpr.)
948 : : */
1899 alvherre@alvh.no-ip. 949 [ + + ]: 882 : if (containerType == targetTypeId)
4768 tgl@sss.pgh.pa.us 950 : 731 : collationNeeded = targetCollation;
951 : : else
1899 alvherre@alvh.no-ip. 952 : 151 : collationNeeded = get_typcollation(containerType);
953 : :
954 : : /* recurse to create appropriate RHS for container assign */
4924 tgl@sss.pgh.pa.us 955 : 882 : rhs = transformAssignmentIndirection(pstate,
956 : : NULL,
957 : : targetName,
958 : : true,
959 : : typeNeeded,
960 : : typmodNeeded,
961 : : collationNeeded,
962 : : indirection,
963 : : next_indirection,
964 : : rhs,
965 : : ccontext,
966 : : location);
967 : :
968 : : /*
969 : : * Insert the already-properly-coerced RHS into the SubscriptingRef. Then
970 : : * set refrestype and reftypmod back to the container type's values.
971 : : */
1222 972 : 875 : sbsref->refassgnexpr = (Expr *) rhs;
973 : 875 : sbsref->refrestype = containerType;
974 : 875 : sbsref->reftypmod = containerTypMod;
975 : :
976 : 875 : result = (Node *) sbsref;
977 : :
978 : : /*
979 : : * If target was a domain over container, need to coerce up to the domain.
980 : : * As in transformAssignmentIndirection, this coercion is premature if the
981 : : * query assigns to multiple elements of the container; but we'll fix that
982 : : * during query rewrite.
983 : : */
1899 alvherre@alvh.no-ip. 984 [ + + ]: 875 : if (containerType != targetTypeId)
985 : : {
3795 tgl@sss.pgh.pa.us 986 : 151 : Oid resulttype = exprType(result);
987 : :
4924 988 : 151 : result = coerce_to_target_type(pstate,
989 : : result, resulttype,
990 : : targetTypeId, targetTypMod,
991 : : ccontext,
992 : : COERCE_IMPLICIT_CAST,
993 : : -1);
994 : : /* can fail if we had int2vector/oidvector, but not for true domains */
995 [ - + ]: 151 : if (result == NULL)
4924 tgl@sss.pgh.pa.us 996 [ # # ]:UBC 0 : ereport(ERROR,
997 : : (errcode(ERRCODE_CANNOT_COERCE),
998 : : errmsg("cannot cast type %s to %s",
999 : : format_type_be(resulttype),
1000 : : format_type_be(targetTypeId)),
1001 : : parser_errposition(pstate, location)));
1002 : : }
1003 : :
4924 tgl@sss.pgh.pa.us 1004 :CBC 875 : return result;
1005 : : }
1006 : :
1007 : :
1008 : : /*
1009 : : * checkInsertTargets -
1010 : : * generate a list of INSERT column targets if not supplied, or
1011 : : * test supplied column names to make sure they are in target table.
1012 : : * Also return an integer list of the columns' attribute numbers.
1013 : : */
1014 : : List *
8931 1015 : 35234 : checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
1016 : : {
1017 : 35234 : *attrnos = NIL;
1018 : :
9637 bruce@momjian.us 1019 [ + + ]: 35234 : if (cols == NIL)
1020 : : {
1021 : : /*
1022 : : * Generate default column list for INSERT.
1023 : : */
2199 teodor@sigaev.ru 1024 : 29061 : int numcol = RelationGetNumberOfAttributes(pstate->p_target_relation);
1025 : :
1026 : : int i;
1027 : :
9637 bruce@momjian.us 1028 [ + + ]: 84138 : for (i = 0; i < numcol; i++)
1029 : : {
1030 : : ResTarget *col;
1031 : : Form_pg_attribute attr;
1032 : :
2429 andres@anarazel.de 1033 : 55077 : attr = TupleDescAttr(pstate->p_target_relation->rd_att, i);
1034 : :
1035 [ + + ]: 55077 : if (attr->attisdropped)
7926 tgl@sss.pgh.pa.us 1036 : 138 : continue;
1037 : :
1038 : 54939 : col = makeNode(ResTarget);
2429 andres@anarazel.de 1039 : 54939 : col->name = pstrdup(NameStr(attr->attname));
8060 tgl@sss.pgh.pa.us 1040 : 54939 : col->indirection = NIL;
1041 : 54939 : col->val = NULL;
6597 1042 : 54939 : col->location = -1;
8060 1043 : 54939 : cols = lappend(cols, col);
7259 neilc@samurai.com 1044 : 54939 : *attrnos = lappend_int(*attrnos, i + 1);
1045 : : }
1046 : : }
1047 : : else
1048 : : {
1049 : : /*
1050 : : * Do initial validation of user-supplied INSERT column list.
1051 : : */
6959 tgl@sss.pgh.pa.us 1052 : 6173 : Bitmapset *wholecols = NULL;
1053 : 6173 : Bitmapset *partialcols = NULL;
1054 : : ListCell *tl;
1055 : :
9637 bruce@momjian.us 1056 [ + - + + : 19178 : foreach(tl, cols)
+ + ]
1057 : : {
7249 tgl@sss.pgh.pa.us 1058 : 13029 : ResTarget *col = (ResTarget *) lfirst(tl);
1059 : 13029 : char *name = col->name;
1060 : : int attrno;
1061 : :
1062 : : /* Lookup column name, ereport on failure */
7926 1063 : 13029 : attrno = attnameAttNum(pstate->p_target_relation, name, false);
6597 1064 [ + + ]: 13029 : if (attrno == InvalidAttrNumber)
1065 [ + - ]: 24 : ereport(ERROR,
1066 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
1067 : : errmsg("column \"%s\" of relation \"%s\" does not exist",
1068 : : name,
1069 : : RelationGetRelationName(pstate->p_target_relation)),
1070 : : parser_errposition(pstate, col->location)));
1071 : :
1072 : : /*
1073 : : * Check for duplicates, but only of whole columns --- we allow
1074 : : * INSERT INTO foo (col.subcol1, col.subcol2)
1075 : : */
7249 1076 [ + + ]: 13005 : if (col->indirection == NIL)
1077 : : {
1078 : : /* whole column; must not have any other assignment */
6959 1079 [ + - - + ]: 25296 : if (bms_is_member(attrno, wholecols) ||
1080 : 12648 : bms_is_member(attrno, partialcols))
7249 tgl@sss.pgh.pa.us 1081 [ # # ]:UBC 0 : ereport(ERROR,
1082 : : (errcode(ERRCODE_DUPLICATE_COLUMN),
1083 : : errmsg("column \"%s\" specified more than once",
1084 : : name),
1085 : : parser_errposition(pstate, col->location)));
6959 tgl@sss.pgh.pa.us 1086 :CBC 12648 : wholecols = bms_add_member(wholecols, attrno);
1087 : : }
1088 : : else
1089 : : {
1090 : : /* partial column; must not have any whole assignment */
1091 [ - + ]: 357 : if (bms_is_member(attrno, wholecols))
7249 tgl@sss.pgh.pa.us 1092 [ # # ]:UBC 0 : ereport(ERROR,
1093 : : (errcode(ERRCODE_DUPLICATE_COLUMN),
1094 : : errmsg("column \"%s\" specified more than once",
1095 : : name),
1096 : : parser_errposition(pstate, col->location)));
6959 tgl@sss.pgh.pa.us 1097 :CBC 357 : partialcols = bms_add_member(partialcols, attrno);
1098 : : }
1099 : :
7259 neilc@samurai.com 1100 : 13005 : *attrnos = lappend_int(*attrnos, attrno);
1101 : : }
1102 : : }
1103 : :
9637 bruce@momjian.us 1104 : 35210 : return cols;
1105 : : }
1106 : :
1107 : : /*
1108 : : * ExpandColumnRefStar()
1109 : : * Transforms foo.* into a list of expressions or targetlist entries.
1110 : : *
1111 : : * This handles the case where '*' appears as the last or only item in a
1112 : : * ColumnRef. The code is shared between the case of foo.* at the top level
1113 : : * in a SELECT target list (where we want TargetEntry nodes in the result)
1114 : : * and foo.* in a ROW() or VALUES() construct (where we want just bare
1115 : : * expressions).
1116 : : *
1117 : : * The referenced columns are marked as requiring SELECT access.
1118 : : */
1119 : : static List *
6502 tgl@sss.pgh.pa.us 1120 : 25961 : ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
1121 : : bool make_target_entry)
1122 : : {
7239 1123 : 25961 : List *fields = cref->fields;
1124 : 25961 : int numnames = list_length(fields);
1125 : :
1126 [ + + ]: 25961 : if (numnames == 1)
1127 : : {
1128 : : /*
1129 : : * Target item is a bare '*', expand all tables
1130 : : *
1131 : : * (e.g., SELECT * FROM emp, dept)
1132 : : *
1133 : : * Since the grammar only accepts bare '*' at top level of SELECT, we
1134 : : * need not handle the make_target_entry==false case here.
1135 : : */
4265 1136 [ - + ]: 24386 : Assert(make_target_entry);
5704 1137 : 24386 : return ExpandAllTables(pstate, cref->location);
1138 : : }
1139 : : else
1140 : : {
1141 : : /*
1142 : : * Target item is relation.*, expand that table
1143 : : *
1144 : : * (e.g., SELECT emp.*, dname FROM emp, dept)
1145 : : *
1146 : : * Note: this code is a lot like transformColumnRef; it's tempting to
1147 : : * call that instead and then replace the resulting whole-row Var with
1148 : : * a list of Vars. However, that would leave us with the relation's
1149 : : * selectedCols bitmap showing the whole row as needing select
1150 : : * permission, as well as the individual columns. That would be
1151 : : * incorrect (since columns added later shouldn't need select
1152 : : * permissions). We could try to remove the whole-row permission bit
1153 : : * after the fact, but duplicating code is less messy.
1154 : : */
5279 1155 : 1575 : char *nspname = NULL;
1156 : 1575 : char *relname = NULL;
1571 1157 : 1575 : ParseNamespaceItem *nsitem = NULL;
1158 : : int levels_up;
1159 : : enum
1160 : : {
1161 : : CRSERR_NO_RTE,
1162 : : CRSERR_WRONG_DB,
1163 : : CRSERR_TOO_MANY
5279 1164 : 1575 : } crserr = CRSERR_NO_RTE;
1165 : :
1166 : : /*
1167 : : * Give the PreParseColumnRefHook, if any, first shot. If it returns
1168 : : * non-null then we should use that expression.
1169 : : */
1170 [ + + ]: 1575 : if (pstate->p_pre_columnref_hook != NULL)
1171 : : {
1172 : : Node *node;
1173 : :
2411 peter_e@gmx.net 1174 : 29 : node = pstate->p_pre_columnref_hook(pstate, cref);
5279 tgl@sss.pgh.pa.us 1175 [ - + ]: 29 : if (node != NULL)
4265 tgl@sss.pgh.pa.us 1176 :UBC 0 : return ExpandRowReference(pstate, node, make_target_entry);
1177 : : }
1178 : :
7239 tgl@sss.pgh.pa.us 1179 [ + - - - ]:CBC 1575 : switch (numnames)
1180 : : {
1181 : 1575 : case 2:
1182 : 1575 : relname = strVal(linitial(fields));
1571 1183 : 1575 : nsitem = refnameNamespaceItem(pstate, nspname, relname,
1184 : : cref->location,
1185 : : &levels_up);
7239 1186 : 1575 : break;
7239 tgl@sss.pgh.pa.us 1187 :UBC 0 : case 3:
5279 1188 : 0 : nspname = strVal(linitial(fields));
7239 1189 : 0 : relname = strVal(lsecond(fields));
1571 1190 : 0 : nsitem = refnameNamespaceItem(pstate, nspname, relname,
1191 : : cref->location,
1192 : : &levels_up);
7239 1193 : 0 : break;
1194 : 0 : case 4:
1195 : : {
5161 bruce@momjian.us 1196 : 0 : char *catname = strVal(linitial(fields));
1197 : :
1198 : : /*
1199 : : * We check the catalog name and then ignore it.
1200 : : */
1201 [ # # ]: 0 : if (strcmp(catname, get_database_name(MyDatabaseId)) != 0)
1202 : : {
1203 : 0 : crserr = CRSERR_WRONG_DB;
1204 : 0 : break;
1205 : : }
1206 : 0 : nspname = strVal(lsecond(fields));
1207 : 0 : relname = strVal(lthird(fields));
1571 tgl@sss.pgh.pa.us 1208 : 0 : nsitem = refnameNamespaceItem(pstate, nspname, relname,
1209 : : cref->location,
1210 : : &levels_up);
7168 bruce@momjian.us 1211 : 0 : break;
1212 : : }
7239 tgl@sss.pgh.pa.us 1213 : 0 : default:
5279 1214 : 0 : crserr = CRSERR_TOO_MANY;
7239 1215 : 0 : break;
1216 : : }
1217 : :
1218 : : /*
1219 : : * Now give the PostParseColumnRefHook, if any, a chance. We cheat a
1220 : : * bit by passing the RangeTblEntry, not a Var, as the planned
1221 : : * translation. (A single Var wouldn't be strictly correct anyway.
1222 : : * This convention allows hooks that really care to know what is
1223 : : * happening. It might be better to pass the nsitem, but we'd have to
1224 : : * promote that struct to a full-fledged Node type so that callees
1225 : : * could identify its type.)
1226 : : */
5279 tgl@sss.pgh.pa.us 1227 [ + + ]:CBC 1575 : if (pstate->p_post_columnref_hook != NULL)
1228 : : {
1229 : : Node *node;
1230 : :
2411 peter_e@gmx.net 1231 [ + + ]: 62 : node = pstate->p_post_columnref_hook(pstate, cref,
1232 : : (Node *) (nsitem ? nsitem->p_rte : NULL));
5279 tgl@sss.pgh.pa.us 1233 [ + + ]: 62 : if (node != NULL)
1234 : : {
1571 1235 [ - + ]: 47 : if (nsitem != NULL)
5279 tgl@sss.pgh.pa.us 1236 [ # # ]:UBC 0 : ereport(ERROR,
1237 : : (errcode(ERRCODE_AMBIGUOUS_COLUMN),
1238 : : errmsg("column reference \"%s\" is ambiguous",
1239 : : NameListToString(cref->fields)),
1240 : : parser_errposition(pstate, cref->location)));
4265 tgl@sss.pgh.pa.us 1241 :CBC 47 : return ExpandRowReference(pstate, node, make_target_entry);
1242 : : }
1243 : : }
1244 : :
1245 : : /*
1246 : : * Throw error if no translation found.
1247 : : */
1571 1248 [ + + ]: 1528 : if (nsitem == NULL)
1249 : : {
5279 1250 [ + - - - ]: 3 : switch (crserr)
1251 : : {
1252 : 3 : case CRSERR_NO_RTE:
1253 : 3 : errorMissingRTE(pstate, makeRangeVar(nspname, relname,
1254 : : cref->location));
1255 : : break;
5279 tgl@sss.pgh.pa.us 1256 :UBC 0 : case CRSERR_WRONG_DB:
1257 [ # # ]: 0 : ereport(ERROR,
1258 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1259 : : errmsg("cross-database references are not implemented: %s",
1260 : : NameListToString(cref->fields)),
1261 : : parser_errposition(pstate, cref->location)));
1262 : : break;
1263 : 0 : case CRSERR_TOO_MANY:
1264 [ # # ]: 0 : ereport(ERROR,
1265 : : (errcode(ERRCODE_SYNTAX_ERROR),
1266 : : errmsg("improper qualified name (too many dotted names): %s",
1267 : : NameListToString(cref->fields)),
1268 : : parser_errposition(pstate, cref->location)));
1269 : : break;
1270 : : }
1271 : : }
1272 : :
1273 : : /*
1274 : : * OK, expand the nsitem into fields.
1275 : : */
1571 tgl@sss.pgh.pa.us 1276 :CBC 1525 : return ExpandSingleTable(pstate, nsitem, levels_up, cref->location,
1277 : : make_target_entry);
1278 : : }
1279 : : }
1280 : :
1281 : : /*
1282 : : * ExpandAllTables()
1283 : : * Transforms '*' (in the target list) into a list of targetlist entries.
1284 : : *
1285 : : * tlist entries are generated for each relation visible for unqualified
1286 : : * column name access. We do not consider qualified-name-only entries because
1287 : : * that would include input tables of aliasless JOINs, NEW/OLD pseudo-entries,
1288 : : * etc.
1289 : : *
1290 : : * The referenced relations/columns are marked as requiring SELECT access.
1291 : : */
1292 : : static List *
5704 1293 : 24386 : ExpandAllTables(ParseState *pstate, int location)
1294 : : {
9637 bruce@momjian.us 1295 : 24386 : List *target = NIL;
4267 tgl@sss.pgh.pa.us 1296 : 24386 : bool found_table = false;
1297 : : ListCell *l;
1298 : :
1299 [ + - + + : 52112 : foreach(l, pstate->p_namespace)
+ + ]
1300 : : {
4268 1301 : 27726 : ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l);
1302 : :
1303 : : /* Ignore table-only items */
4267 1304 [ + + ]: 27726 : if (!nsitem->p_cols_visible)
1305 : 2656 : continue;
1306 : : /* Should not have any lateral-only items when parsing targetlist */
4268 1307 [ - + ]: 25070 : Assert(!nsitem->p_lateral_only);
1308 : : /* Remember we found a p_cols_visible item */
4267 1309 : 25070 : found_table = true;
1310 : :
7178 1311 : 25070 : target = list_concat(target,
1571 1312 : 25070 : expandNSItemAttrs(pstate,
1313 : : nsitem,
1314 : : 0,
1315 : : true,
1316 : : location));
1317 : : }
1318 : :
1319 : : /*
1320 : : * Check for "SELECT *;". We do it this way, rather than checking for
1321 : : * target == NIL, because we want to allow SELECT * FROM a zero_column
1322 : : * table.
1323 : : */
4267 1324 [ - + ]: 24386 : if (!found_table)
4267 tgl@sss.pgh.pa.us 1325 [ # # ]:UBC 0 : ereport(ERROR,
1326 : : (errcode(ERRCODE_SYNTAX_ERROR),
1327 : : errmsg("SELECT * with no tables specified is not valid"),
1328 : : parser_errposition(pstate, location)));
1329 : :
9637 bruce@momjian.us 1330 :CBC 24386 : return target;
1331 : : }
1332 : :
1333 : : /*
1334 : : * ExpandIndirectionStar()
1335 : : * Transforms foo.* into a list of expressions or targetlist entries.
1336 : : *
1337 : : * This handles the case where '*' appears as the last item in A_Indirection.
1338 : : * The code is shared between the case of foo.* at the top level in a SELECT
1339 : : * target list (where we want TargetEntry nodes in the result) and foo.* in
1340 : : * a ROW() or VALUES() construct (where we want just bare expressions).
1341 : : * For robustness, we use a separate "make_target_entry" flag to control
1342 : : * this rather than relying on exprKind.
1343 : : */
1344 : : static List *
6502 tgl@sss.pgh.pa.us 1345 : 608 : ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind,
1346 : : bool make_target_entry, ParseExprKind exprKind)
1347 : : {
1348 : : Node *expr;
1349 : :
1350 : : /* Strip off the '*' to create a reference to the rowtype object */
7239 1351 : 608 : ind = copyObject(ind);
1352 : 608 : ind->indirection = list_truncate(ind->indirection,
1353 : 608 : list_length(ind->indirection) - 1);
1354 : :
1355 : : /* And transform that */
4265 1356 : 608 : expr = transformExpr(pstate, (Node *) ind, exprKind);
1357 : :
1358 : : /* Expand the rowtype expression into individual fields */
1359 : 608 : return ExpandRowReference(pstate, expr, make_target_entry);
1360 : : }
1361 : :
1362 : : /*
1363 : : * ExpandSingleTable()
1364 : : * Transforms foo.* into a list of expressions or targetlist entries.
1365 : : *
1366 : : * This handles the case where foo has been determined to be a simple
1367 : : * reference to an RTE, so we can just generate Vars for the expressions.
1368 : : *
1369 : : * The referenced columns are marked as requiring SELECT access.
1370 : : */
1371 : : static List *
1571 1372 : 1525 : ExpandSingleTable(ParseState *pstate, ParseNamespaceItem *nsitem,
1373 : : int sublevels_up, int location, bool make_target_entry)
1374 : : {
4265 1375 [ + + ]: 1525 : if (make_target_entry)
1376 : : {
1377 : : /* expandNSItemAttrs handles permissions marking */
748 alvherre@alvh.no-ip. 1378 : 1427 : return expandNSItemAttrs(pstate, nsitem, sublevels_up, true, location);
1379 : : }
1380 : : else
1381 : : {
1571 tgl@sss.pgh.pa.us 1382 : 98 : RangeTblEntry *rte = nsitem->p_rte;
495 alvherre@alvh.no-ip. 1383 : 98 : RTEPermissionInfo *perminfo = nsitem->p_perminfo;
1384 : : List *vars;
1385 : : ListCell *l;
1386 : :
440 tgl@sss.pgh.pa.us 1387 : 98 : vars = expandNSItemVars(pstate, nsitem, sublevels_up, location, NULL);
1388 : :
1389 : : /*
1390 : : * Require read access to the table. This is normally redundant with
1391 : : * the markVarForSelectPriv calls below, but not if the table has zero
1392 : : * columns. We need not do anything if the nsitem is for a join: its
1393 : : * component tables will have been marked ACL_SELECT when they were
1394 : : * added to the rangetable. (This step changes things only for the
1395 : : * target relation of UPDATE/DELETE, which cannot be under a join.)
1396 : : */
1161 1397 [ + + ]: 98 : if (rte->rtekind == RTE_RELATION)
1398 : : {
495 alvherre@alvh.no-ip. 1399 [ - + ]: 52 : Assert(perminfo != NULL);
1400 : 52 : perminfo->requiredPerms |= ACL_SELECT;
1401 : : }
1402 : :
1403 : : /* Require read access to each column */
5279 tgl@sss.pgh.pa.us 1404 [ + + + + : 256 : foreach(l, vars)
+ + ]
1405 : : {
1406 : 158 : Var *var = (Var *) lfirst(l);
1407 : :
1158 1408 : 158 : markVarForSelectPriv(pstate, var);
1409 : : }
1410 : :
5279 1411 : 98 : return vars;
1412 : : }
1413 : : }
1414 : :
1415 : : /*
1416 : : * ExpandRowReference()
1417 : : * Transforms foo.* into a list of expressions or targetlist entries.
1418 : : *
1419 : : * This handles the case where foo is an arbitrary expression of composite
1420 : : * type.
1421 : : */
1422 : : static List *
1423 : 655 : ExpandRowReference(ParseState *pstate, Node *expr,
1424 : : bool make_target_entry)
1425 : : {
1426 : 655 : List *result = NIL;
1427 : : TupleDesc tupleDesc;
1428 : : int numAttrs;
1429 : : int i;
1430 : :
1431 : : /*
1432 : : * If the rowtype expression is a whole-row Var, we can expand the fields
1433 : : * as simple Vars. Note: if the RTE is a relation, this case leaves us
1434 : : * with its RTEPermissionInfo's selectedCols bitmap showing the whole row
1435 : : * as needing select permission, as well as the individual columns.
1436 : : * However, we can only get here for weird notations like (table.*).*, so
1437 : : * it's not worth trying to clean up --- arguably, the permissions marking
1438 : : * is correct anyway for such cases.
1439 : : */
1440 [ + + ]: 655 : if (IsA(expr, Var) &&
1441 [ - + ]: 39 : ((Var *) expr)->varattno == InvalidAttrNumber)
1442 : : {
5279 tgl@sss.pgh.pa.us 1443 :UBC 0 : Var *var = (Var *) expr;
1444 : : ParseNamespaceItem *nsitem;
1445 : :
1571 1446 : 0 : nsitem = GetNSItemByRangeTablePosn(pstate, var->varno, var->varlevelsup);
1447 : 0 : return ExpandSingleTable(pstate, nsitem, var->varlevelsup, var->location, make_target_entry);
1448 : : }
1449 : :
1450 : : /*
1451 : : * Otherwise we have to do it the hard way. Our current implementation is
1452 : : * to generate multiple copies of the expression and do FieldSelects.
1453 : : * (This can be pretty inefficient if the expression involves nontrivial
1454 : : * computation :-(.)
1455 : : *
1456 : : * Verify it's a composite type, and get the tupdesc.
1457 : : * get_expr_result_tupdesc() handles this conveniently.
1458 : : *
1459 : : * If it's a Var of type RECORD, we have to work even harder: we have to
1460 : : * find what the Var refers to, and pass that to get_expr_result_tupdesc.
1461 : : * That task is handled by expandRecordVariable().
1462 : : */
6929 tgl@sss.pgh.pa.us 1463 [ + + ]:CBC 655 : if (IsA(expr, Var) &&
1464 [ + + ]: 39 : ((Var *) expr)->vartype == RECORDOID)
1465 : 3 : tupleDesc = expandRecordVariable(pstate, (Var *) expr, 0);
1466 : : else
2362 1467 : 652 : tupleDesc = get_expr_result_tupdesc(expr, false);
6929 1468 [ - + ]: 655 : Assert(tupleDesc);
1469 : :
1470 : : /* Generate a list of references to the individual fields */
7239 1471 : 655 : numAttrs = tupleDesc->natts;
1472 [ + + ]: 3131 : for (i = 0; i < numAttrs; i++)
1473 : : {
2429 andres@anarazel.de 1474 : 2476 : Form_pg_attribute att = TupleDescAttr(tupleDesc, i);
1475 : : FieldSelect *fselect;
1476 : :
7239 tgl@sss.pgh.pa.us 1477 [ + + ]: 2476 : if (att->attisdropped)
1478 : 4 : continue;
1479 : :
5279 1480 : 2472 : fselect = makeNode(FieldSelect);
1481 : 2472 : fselect->arg = (Expr *) copyObject(expr);
1482 : 2472 : fselect->fieldnum = i + 1;
1483 : 2472 : fselect->resulttype = att->atttypid;
1484 : 2472 : fselect->resulttypmod = att->atttypmod;
1485 : : /* save attribute's collation for parse_collate.c */
4775 1486 : 2472 : fselect->resultcollid = att->attcollation;
1487 : :
4265 1488 [ + + ]: 2472 : if (make_target_entry)
1489 : : {
1490 : : /* add TargetEntry decoration */
1491 : : TargetEntry *te;
1492 : :
5279 1493 : 4704 : te = makeTargetEntry((Expr *) fselect,
6502 1494 : 2352 : (AttrNumber) pstate->p_next_resno++,
1495 : 2352 : pstrdup(NameStr(att->attname)),
1496 : : false);
1497 : 2352 : result = lappend(result, te);
1498 : : }
1499 : : else
5279 1500 : 120 : result = lappend(result, fselect);
1501 : : }
1502 : :
6502 1503 : 655 : return result;
1504 : : }
1505 : :
1506 : : /*
1507 : : * expandRecordVariable
1508 : : * Get the tuple descriptor for a Var of type RECORD, if possible.
1509 : : *
1510 : : * Since no actual table or view column is allowed to have type RECORD, such
1511 : : * a Var must refer to a JOIN or FUNCTION RTE or to a subquery output. We
1512 : : * drill down to find the ultimate defining expression and attempt to infer
1513 : : * the tupdesc from it. We ereport if we can't determine the tupdesc.
1514 : : *
1515 : : * levelsup is an extra offset to interpret the Var's varlevelsup correctly
1516 : : * when recursing. Outside callers should pass zero.
1517 : : */
1518 : : TupleDesc
6929 1519 : 778 : expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
1520 : : {
1521 : : TupleDesc tupleDesc;
1522 : : int netlevelsup;
1523 : : RangeTblEntry *rte;
1524 : : AttrNumber attnum;
1525 : : Node *expr;
1526 : :
1527 : : /* Check my caller didn't mess up */
1528 [ - + ]: 778 : Assert(IsA(var, Var));
1529 [ - + ]: 778 : Assert(var->vartype == RECORDOID);
1530 : :
1531 : : /*
1532 : : * Note: it's tempting to use GetNSItemByRangeTablePosn here so that we
1533 : : * can use expandNSItemVars instead of expandRTE; but that does not work
1534 : : * for some of the recursion cases below, where we have consed up a
1535 : : * ParseState that lacks p_namespace data.
1536 : : */
1537 : 778 : netlevelsup = var->varlevelsup + levelsup;
1538 : 778 : rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);
1539 : 778 : attnum = var->varattno;
1540 : :
1541 [ + + ]: 778 : if (attnum == InvalidAttrNumber)
1542 : : {
1543 : : /* Whole-row reference to an RTE, so expand the known fields */
1544 : : List *names,
1545 : : *vars;
1546 : : ListCell *lname,
1547 : : *lvar;
1548 : : int i;
1549 : :
5704 1550 : 15 : expandRTE(rte, var->varno, 0, var->location, false,
1551 : : &names, &vars);
1552 : :
1972 andres@anarazel.de 1553 : 15 : tupleDesc = CreateTemplateTupleDesc(list_length(vars));
6929 tgl@sss.pgh.pa.us 1554 : 15 : i = 1;
1555 [ + - + + : 45 : forboth(lname, names, lvar, vars)
+ - + + +
+ + - +
+ ]
1556 : : {
1557 : 30 : char *label = strVal(lfirst(lname));
1558 : 30 : Node *varnode = (Node *) lfirst(lvar);
1559 : :
1560 : 30 : TupleDescInitEntry(tupleDesc, i,
1561 : : label,
1562 : : exprType(varnode),
1563 : : exprTypmod(varnode),
1564 : : 0);
4814 peter_e@gmx.net 1565 : 30 : TupleDescInitEntryCollation(tupleDesc, i,
1566 : : exprCollation(varnode));
6929 tgl@sss.pgh.pa.us 1567 : 30 : i++;
1568 : : }
1569 [ + - - + ]: 15 : Assert(lname == NULL && lvar == NULL); /* lists same length? */
1570 : :
1571 : 15 : return tupleDesc;
1572 : : }
1573 : :
1574 : 763 : expr = (Node *) var; /* default if we can't drill down */
1575 : :
1576 [ - + - - : 763 : switch (rte->rtekind)
- + - ]
1577 : : {
6929 tgl@sss.pgh.pa.us 1578 :UBC 0 : case RTE_RELATION:
1579 : : case RTE_VALUES:
1580 : : case RTE_NAMEDTUPLESTORE:
1581 : : case RTE_RESULT:
1582 : :
1583 : : /*
1584 : : * This case should not occur: a column of a table, values list,
1585 : : * or ENR shouldn't have type RECORD. Fall through and fail (most
1586 : : * likely) at the bottom.
1587 : : */
1588 : 0 : break;
6929 tgl@sss.pgh.pa.us 1589 :CBC 736 : case RTE_SUBQUERY:
1590 : : {
1591 : : /* Subselect-in-FROM: examine sub-select's output expr */
1592 : 736 : TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
1593 : : attnum);
1594 : :
1595 [ + - - + ]: 736 : if (ste == NULL || ste->resjunk)
6929 tgl@sss.pgh.pa.us 1596 [ # # ]:UBC 0 : elog(ERROR, "subquery %s does not have attribute %d",
1597 : : rte->eref->aliasname, attnum);
6929 tgl@sss.pgh.pa.us 1598 :CBC 736 : expr = (Node *) ste->expr;
1599 [ + + ]: 736 : if (IsA(expr, Var))
1600 : : {
1601 : : /*
1602 : : * Recurse into the sub-select to see what its Var refers
1603 : : * to. We have to build an additional level of ParseState
1604 : : * to keep in step with varlevelsup in the subselect;
1605 : : * furthermore, the subquery RTE might be from an outer
1606 : : * query level, in which case the ParseState for the
1607 : : * subselect must have that outer level as parent.
1608 : : */
638 peter@eisentraut.org 1609 : 18 : ParseState mypstate = {0};
1610 : : Index levelsup;
1611 : :
1612 : : /* this loop must work, since GetRTEByRangeTablePosn did */
212 tgl@sss.pgh.pa.us 1613 [ + + ]: 27 : for (levelsup = 0; levelsup < netlevelsup; levelsup++)
1614 : 9 : pstate = pstate->parentParseState;
6929 1615 : 18 : mypstate.parentParseState = pstate;
1616 : 18 : mypstate.p_rtable = rte->subquery->rtable;
1617 : : /* don't bother filling the rest of the fake pstate */
1618 : :
1619 : 18 : return expandRecordVariable(&mypstate, (Var *) expr, 0);
1620 : : }
1621 : : /* else fall through to inspect the expression */
1622 : : }
1623 : 718 : break;
6929 tgl@sss.pgh.pa.us 1624 :UBC 0 : case RTE_JOIN:
1625 : : /* Join RTE --- recursively inspect the alias variable */
1626 [ # # # # ]: 0 : Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
1627 : 0 : expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
3918 1628 [ # # ]: 0 : Assert(expr != NULL);
1629 : : /* We intentionally don't strip implicit coercions here */
6929 1630 [ # # ]: 0 : if (IsA(expr, Var))
1631 : 0 : return expandRecordVariable(pstate, (Var *) expr, netlevelsup);
1632 : : /* else fall through to inspect the expression */
1633 : 0 : break;
1634 : 0 : case RTE_FUNCTION:
1635 : :
1636 : : /*
1637 : : * We couldn't get here unless a function is declared with one of
1638 : : * its result columns as RECORD, which is not allowed.
1639 : : */
1640 : 0 : break;
2594 alvherre@alvh.no-ip. 1641 : 0 : case RTE_TABLEFUNC:
1642 : :
1643 : : /*
1644 : : * Table function cannot have columns with RECORD type.
1645 : : */
1646 : 0 : break;
5671 tgl@sss.pgh.pa.us 1647 :CBC 27 : case RTE_CTE:
1648 : : /* CTE reference: examine subquery's output expr */
5670 1649 [ + - ]: 27 : if (!rte->self_reference)
1650 : : {
5669 1651 : 27 : CommonTableExpr *cte = GetCTEForRTE(pstate, rte, netlevelsup);
1652 : : TargetEntry *ste;
1653 : :
4797 1654 [ - + + - ]: 27 : ste = get_tle_by_resno(GetCTETargetList(cte), attnum);
5671 1655 [ + - - + ]: 27 : if (ste == NULL || ste->resjunk)
1278 peter@eisentraut.org 1656 [ # # ]:UBC 0 : elog(ERROR, "CTE %s does not have attribute %d",
1657 : : rte->eref->aliasname, attnum);
5671 tgl@sss.pgh.pa.us 1658 :CBC 27 : expr = (Node *) ste->expr;
1659 [ + + ]: 27 : if (IsA(expr, Var))
1660 : : {
1661 : : /*
1662 : : * Recurse into the CTE to see what its Var refers to. We
1663 : : * have to build an additional level of ParseState to keep
1664 : : * in step with varlevelsup in the CTE; furthermore it
1665 : : * could be an outer CTE (compare SUBQUERY case above).
1666 : : */
212 1667 : 15 : ParseState mypstate = {0};
1668 : : Index levelsup;
1669 : :
1670 : : /* this loop must work, since GetCTEForRTE did */
5669 1671 : 15 : for (levelsup = 0;
1672 [ + + ]: 33 : levelsup < rte->ctelevelsup + netlevelsup;
1673 : 18 : levelsup++)
5671 1674 : 18 : pstate = pstate->parentParseState;
1675 : 15 : mypstate.parentParseState = pstate;
1676 : 15 : mypstate.p_rtable = ((Query *) cte->ctequery)->rtable;
1677 : : /* don't bother filling the rest of the fake pstate */
1678 : :
1679 : 15 : return expandRecordVariable(&mypstate, (Var *) expr, 0);
1680 : : }
1681 : : /* else fall through to inspect the expression */
1682 : : }
1683 : 12 : break;
1684 : : }
1685 : :
1686 : : /*
1687 : : * We now have an expression we can't expand any more, so see if
1688 : : * get_expr_result_tupdesc() can do anything with it.
1689 : : */
2362 1690 : 730 : return get_expr_result_tupdesc(expr, false);
1691 : : }
1692 : :
1693 : :
1694 : : /*
1695 : : * FigureColname -
1696 : : * if the name of the resulting column is not specified in the target
1697 : : * list, we have to guess a suitable name. The SQL spec provides some
1698 : : * guidance, but not much...
1699 : : *
1700 : : * Note that the argument is the *untransformed* parse tree for the target
1701 : : * item. This is a shade easier to work with than the transformed tree.
1702 : : */
1703 : : char *
8245 1704 : 398878 : FigureColname(Node *node)
1705 : : {
8207 bruce@momjian.us 1706 : 398878 : char *name = NULL;
1707 : :
5226 tgl@sss.pgh.pa.us 1708 : 398878 : (void) FigureColnameInternal(node, &name);
8224 1709 [ + + ]: 398878 : if (name != NULL)
1710 : 363100 : return name;
1711 : : /* default result if we can't guess anything */
1712 : 35778 : return "?column?";
1713 : : }
1714 : :
1715 : : /*
1716 : : * FigureIndexColname -
1717 : : * choose the name for an expression column in an index
1718 : : *
1719 : : * This is actually just like FigureColname, except we return NULL if
1720 : : * we can't pick a good name.
1721 : : */
1722 : : char *
5226 1723 : 435 : FigureIndexColname(Node *node)
1724 : : {
1725 : 435 : char *name = NULL;
1726 : :
1727 : 435 : (void) FigureColnameInternal(node, &name);
1728 : 435 : return name;
1729 : : }
1730 : :
1731 : : /*
1732 : : * FigureColnameInternal -
1733 : : * internal workhorse for FigureColname
1734 : : *
1735 : : * Return value indicates strength of confidence in result:
1736 : : * 0 - no information
1737 : : * 1 - second-best name choice
1738 : : * 2 - good name choice
1739 : : * The return value is actually only used internally.
1740 : : * If the result isn't zero, *name is set to the chosen name.
1741 : : */
1742 : : static int
8224 1743 : 437608 : FigureColnameInternal(Node *node, char **name)
1744 : : {
8207 bruce@momjian.us 1745 : 437608 : int strength = 0;
1746 : :
8245 tgl@sss.pgh.pa.us 1747 [ + + ]: 437608 : if (node == NULL)
8224 1748 : 195 : return strength;
1749 : :
8245 1750 [ + + + + : 437413 : switch (nodeTag(node))
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + ]
1751 : : {
8060 1752 : 235549 : case T_ColumnRef:
1753 : : {
7249 1754 : 235549 : char *fname = NULL;
1755 : : ListCell *l;
1756 : :
1757 : : /* find last field name, if any, ignoring "*" */
1758 [ + - + + : 587787 : foreach(l, ((ColumnRef *) node)->fields)
+ + ]
1759 : : {
7168 bruce@momjian.us 1760 : 352238 : Node *i = lfirst(l);
1761 : :
5706 tgl@sss.pgh.pa.us 1762 [ + + ]: 352238 : if (IsA(i, String))
7249 1763 : 352178 : fname = strVal(i);
1764 : : }
1765 [ + - ]: 235549 : if (fname)
1766 : : {
1767 : 235549 : *name = fname;
8224 1768 : 235549 : return 2;
1769 : : }
1770 : : }
9637 bruce@momjian.us 1771 :UBC 0 : break;
7249 tgl@sss.pgh.pa.us 1772 :CBC 857 : case T_A_Indirection:
1773 : : {
1774 : 857 : A_Indirection *ind = (A_Indirection *) node;
1775 : 857 : char *fname = NULL;
1776 : : ListCell *l;
1777 : :
1778 : : /* find last field name, if any, ignoring "*" and subscripts */
1779 [ + - + + : 1859 : foreach(l, ind->indirection)
+ + ]
1780 : : {
7168 bruce@momjian.us 1781 : 1002 : Node *i = lfirst(l);
1782 : :
5706 tgl@sss.pgh.pa.us 1783 [ + + ]: 1002 : if (IsA(i, String))
7249 1784 : 260 : fname = strVal(i);
1785 : : }
1786 [ + + ]: 857 : if (fname)
1787 : : {
1788 : 249 : *name = fname;
1789 : 249 : return 2;
1790 : : }
1791 : 608 : return FigureColnameInternal(ind->arg, name);
1792 : : }
1793 : : break;
8245 1794 : 105374 : case T_FuncCall:
8041 1795 : 105374 : *name = strVal(llast(((FuncCall *) node)->funcname));
8224 1796 : 105374 : return 2;
7728 1797 : 15515 : case T_A_Expr:
1798 [ + + ]: 15515 : if (((A_Expr *) node)->kind == AEXPR_NULLIF)
1799 : : {
1800 : : /* make nullif() act like a regular function */
1801 : 19 : *name = "nullif";
1802 : 19 : return 2;
1803 : : }
1804 : 15496 : break;
8207 bruce@momjian.us 1805 : 21947 : case T_TypeCast:
8224 tgl@sss.pgh.pa.us 1806 : 21947 : strength = FigureColnameInternal(((TypeCast *) node)->arg,
1807 : : name);
1808 [ + + ]: 21947 : if (strength <= 1)
1809 : : {
5386 peter_e@gmx.net 1810 [ + - ]: 6632 : if (((TypeCast *) node)->typeName != NULL)
1811 : : {
1812 : 6632 : *name = strVal(llast(((TypeCast *) node)->typeName->names));
8041 tgl@sss.pgh.pa.us 1813 : 6632 : return 1;
1814 : : }
1815 : : }
8234 lockhart@fourpalms.o 1816 : 15315 : break;
4814 peter_e@gmx.net 1817 : 47 : case T_CollateClause:
4783 tgl@sss.pgh.pa.us 1818 : 47 : return FigureColnameInternal(((CollateClause *) node)->arg, name);
3256 andres@anarazel.de 1819 : 136 : case T_GroupingFunc:
1820 : : /* make GROUPING() act like a regular function */
1821 : 136 : *name = "grouping";
1822 : 136 : return 2;
28 dean.a.rasheed@gmail 1823 :GNC 54 : case T_MergeSupportFunc:
1824 : : /* make MERGE_ACTION() act like a regular function */
1825 : 54 : *name = "merge_action";
1826 : 54 : return 2;
4579 tgl@sss.pgh.pa.us 1827 :CBC 2856 : case T_SubLink:
1828 [ + + + + : 2856 : switch (((SubLink *) node)->subLinkType)
- ]
1829 : : {
1830 : 38 : case EXISTS_SUBLINK:
1831 : 38 : *name = "exists";
1832 : 38 : return 2;
1833 : 36 : case ARRAY_SUBLINK:
1834 : 36 : *name = "array";
1835 : 36 : return 2;
1836 : 2758 : case EXPR_SUBLINK:
1837 : : {
1838 : : /* Get column name of the subquery's single target */
4326 bruce@momjian.us 1839 : 2758 : SubLink *sublink = (SubLink *) node;
4579 tgl@sss.pgh.pa.us 1840 : 2758 : Query *query = (Query *) sublink->subselect;
1841 : :
1842 : : /*
1843 : : * The subquery has probably already been transformed,
1844 : : * but let's be careful and check that. (The reason
1845 : : * we can see a transformed subquery here is that
1846 : : * transformSubLink is lazy and modifies the SubLink
1847 : : * node in-place.)
1848 : : */
1849 [ + - ]: 2758 : if (IsA(query, Query))
1850 : : {
1851 : 2758 : TargetEntry *te = (TargetEntry *) linitial(query->targetList);
1852 : :
1853 [ + - ]: 2758 : if (te->resname)
1854 : : {
1855 : 2758 : *name = te->resname;
1856 : 2758 : return 2;
1857 : : }
1858 : : }
1859 : : }
4579 tgl@sss.pgh.pa.us 1860 :UBC 0 : break;
1861 : : /* As with other operator-like nodes, these have no names */
3588 tgl@sss.pgh.pa.us 1862 :CBC 24 : case MULTIEXPR_SUBLINK:
1863 : : case ALL_SUBLINK:
1864 : : case ANY_SUBLINK:
1865 : : case ROWCOMPARE_SUBLINK:
1866 : : case CTE_SUBLINK:
4579 1867 : 24 : break;
1868 : : }
1869 : 24 : break;
9254 lockhart@fourpalms.o 1870 : 15693 : case T_CaseExpr:
7794 tgl@sss.pgh.pa.us 1871 : 15693 : strength = FigureColnameInternal((Node *) ((CaseExpr *) node)->defresult,
1872 : : name);
8224 1873 [ + + ]: 15693 : if (strength <= 1)
1874 : : {
1875 : 10623 : *name = "case";
1876 : 10623 : return 1;
1877 : : }
9254 lockhart@fourpalms.o 1878 : 5070 : break;
5869 tgl@sss.pgh.pa.us 1879 : 357 : case T_A_ArrayExpr:
1880 : : /* make ARRAY[] act like a function */
7677 1881 : 357 : *name = "array";
1882 : 357 : return 2;
7279 1883 : 249 : case T_RowExpr:
1884 : : /* make ROW() act like a function */
1885 : 249 : *name = "row";
1886 : 249 : return 2;
7728 1887 : 116 : case T_CoalesceExpr:
1888 : : /* make coalesce() act like a regular function */
1889 : 116 : *name = "coalesce";
1890 : 116 : return 2;
6867 1891 : 82 : case T_MinMaxExpr:
1892 : : /* make greatest/least act like a regular function */
6756 bruce@momjian.us 1893 [ + + - ]: 82 : switch (((MinMaxExpr *) node)->op)
1894 : : {
6867 tgl@sss.pgh.pa.us 1895 : 30 : case IS_GREATEST:
1896 : 30 : *name = "greatest";
1897 : 30 : return 2;
1898 : 52 : case IS_LEAST:
1899 : 52 : *name = "least";
1900 : 52 : return 2;
1901 : : }
6867 tgl@sss.pgh.pa.us 1902 :UBC 0 : break;
333 michael@paquier.xyz 1903 :CBC 95 : case T_SQLValueFunction:
1904 : : /* make these act like a function or variable */
1905 [ + + + + : 95 : switch (((SQLValueFunction *) node)->op)
+ + + + +
+ + - ]
1906 : : {
1907 : 9 : case SVFOP_CURRENT_DATE:
1908 : 9 : *name = "current_date";
1909 : 9 : return 2;
1910 : 6 : case SVFOP_CURRENT_TIME:
1911 : : case SVFOP_CURRENT_TIME_N:
1912 : 6 : *name = "current_time";
1913 : 6 : return 2;
1914 : 11 : case SVFOP_CURRENT_TIMESTAMP:
1915 : : case SVFOP_CURRENT_TIMESTAMP_N:
1916 : 11 : *name = "current_timestamp";
1917 : 11 : return 2;
1918 : 6 : case SVFOP_LOCALTIME:
1919 : : case SVFOP_LOCALTIME_N:
1920 : 6 : *name = "localtime";
1921 : 6 : return 2;
1922 : 9 : case SVFOP_LOCALTIMESTAMP:
1923 : : case SVFOP_LOCALTIMESTAMP_N:
1924 : 9 : *name = "localtimestamp";
1925 : 9 : return 2;
1926 : 3 : case SVFOP_CURRENT_ROLE:
1927 : 3 : *name = "current_role";
1928 : 3 : return 2;
1929 : 15 : case SVFOP_CURRENT_USER:
1930 : 15 : *name = "current_user";
1931 : 15 : return 2;
1932 : 3 : case SVFOP_USER:
1933 : 3 : *name = "user";
1934 : 3 : return 2;
1935 : 18 : case SVFOP_SESSION_USER:
1936 : 18 : *name = "session_user";
1937 : 18 : return 2;
1938 : 3 : case SVFOP_CURRENT_CATALOG:
1939 : 3 : *name = "current_catalog";
1940 : 3 : return 2;
1941 : 12 : case SVFOP_CURRENT_SCHEMA:
1942 : 12 : *name = "current_schema";
1943 : 12 : return 2;
1944 : : }
333 michael@paquier.xyz 1945 :UBC 0 : break;
6324 peter_e@gmx.net 1946 :CBC 225 : case T_XmlExpr:
1947 : : /* make SQL/XML functions act like a regular function */
5995 bruce@momjian.us 1948 [ + + + + : 225 : switch (((XmlExpr *) node)->op)
+ + - +
- ]
1949 : : {
6324 peter_e@gmx.net 1950 : 24 : case IS_XMLCONCAT:
1951 : 24 : *name = "xmlconcat";
1952 : 24 : return 2;
1953 : 54 : case IS_XMLELEMENT:
1954 : 54 : *name = "xmlelement";
1955 : 54 : return 2;
1956 : 3 : case IS_XMLFOREST:
1957 : 3 : *name = "xmlforest";
1958 : 3 : return 2;
6321 tgl@sss.pgh.pa.us 1959 : 69 : case IS_XMLPARSE:
1960 : 69 : *name = "xmlparse";
1961 : 69 : return 2;
1962 : 39 : case IS_XMLPI:
1963 : 39 : *name = "xmlpi";
1964 : 39 : return 2;
1965 : 30 : case IS_XMLROOT:
1966 : 30 : *name = "xmlroot";
1967 : 30 : return 2;
6280 peter_e@gmx.net 1968 :UBC 0 : case IS_XMLSERIALIZE:
1969 : 0 : *name = "xmlserialize";
1970 : 0 : return 2;
6300 peter_e@gmx.net 1971 :CBC 6 : case IS_DOCUMENT:
1972 : : /* nothing */
1973 : 6 : break;
1974 : : }
6324 1975 : 6 : break;
6280 1976 : 81 : case T_XmlSerialize:
1977 : : /* make XMLSERIALIZE act like a regular function */
1978 : 81 : *name = "xmlserialize";
1979 : 81 : return 2;
269 amitlan@postgresql.o 1980 :GNC 53 : case T_JsonParseExpr:
1981 : : /* make JSON act like a regular function */
1982 : 53 : *name = "json";
1983 : 53 : return 2;
1984 : 49 : case T_JsonScalarExpr:
1985 : : /* make JSON_SCALAR act like a regular function */
1986 : 49 : *name = "json_scalar";
1987 : 49 : return 2;
1988 : 32 : case T_JsonSerializeExpr:
1989 : : /* make JSON_SERIALIZE act like a regular function */
1990 : 32 : *name = "json_serialize";
1991 : 32 : return 2;
382 alvherre@alvh.no-ip. 1992 :CBC 143 : case T_JsonObjectConstructor:
1993 : : /* make JSON_OBJECT act like a regular function */
1994 : 143 : *name = "json_object";
1995 : 143 : return 2;
1996 : 86 : case T_JsonArrayConstructor:
1997 : : case T_JsonArrayQueryConstructor:
1998 : : /* make JSON_ARRAY act like a regular function */
1999 : 86 : *name = "json_array";
2000 : 86 : return 2;
2001 : 72 : case T_JsonObjectAgg:
2002 : : /* make JSON_OBJECTAGG act like a regular function */
2003 : 72 : *name = "json_objectagg";
2004 : 72 : return 2;
2005 : 57 : case T_JsonArrayAgg:
2006 : : /* make JSON_ARRAYAGG act like a regular function */
2007 : 57 : *name = "json_arrayagg";
2008 : 57 : return 2;
24 amitlan@postgresql.o 2009 :GNC 657 : case T_JsonFuncExpr:
2010 : : /* make SQL/JSON functions act like a regular function */
2011 [ + + + - ]: 657 : switch (((JsonFuncExpr *) node)->op)
2012 : : {
2013 : 78 : case JSON_EXISTS_OP:
2014 : 78 : *name = "json_exists";
2015 : 78 : return 2;
2016 : 366 : case JSON_QUERY_OP:
2017 : 366 : *name = "json_query";
2018 : 366 : return 2;
2019 : 213 : case JSON_VALUE_OP:
2020 : 213 : *name = "json_value";
2021 : 213 : return 2;
2022 : : /* JSON_TABLE_OP can't happen here. */
24 amitlan@postgresql.o 2023 :UNC 0 : default:
2024 [ # # ]: 0 : elog(ERROR, "unrecognized JsonExpr op: %d",
2025 : : (int) ((JsonFuncExpr *) node)->op);
2026 : : }
2027 : : break;
9637 bruce@momjian.us 2028 :CBC 37031 : default:
2029 : 37031 : break;
2030 : : }
2031 : :
8224 tgl@sss.pgh.pa.us 2032 : 72942 : return strength;
2033 : : }
|