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