back to listing index

postgres/postgres

[web search]
Original source (github.com)
Tags: postgres postgresql c parsers clean-architecture clean-code
Clipped on: 2019-07-30

Skip to content
Branch: master

postgres / src / backend / parser / parse_target.c

Find file Copy path
Image (Asset 3/14) alt= Open this file in GitHub Desktop
1 /*-------------------------------------------------------------------------
2 *
3 * parse_target.c
4 * handle target lists
5 *
6 * Portions Copyright (c) 1996-2019, 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/pg_type.h"
18 #include "commands/dbcommands.h"
19 #include "funcapi.h"
20 #include "miscadmin.h"
21 #include "nodes/makefuncs.h"
22 #include "nodes/nodeFuncs.h"
23 #include "parser/parsetree.h"
24 #include "parser/parse_coerce.h"
25 #include "parser/parse_expr.h"
26 #include "parser/parse_func.h"
27 #include "parser/parse_relation.h"
28 #include "parser/parse_target.h"
29 #include "parser/parse_type.h"
30 #include "utils/builtins.h"
31 #include "utils/lsyscache.h"
32 #include "utils/rel.h"
33 #include "utils/typcache.h"
34
35
36 static void markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
37 Var *var, int levelsup);
38 static Node *transformAssignmentIndirection(ParseState *pstate,
39 Node *basenode,
40 const char *targetName,
41 bool targetIsSubscripting,
42 Oid targetTypeId,
43 int32 targetTypMod,
44 Oid targetCollation,
45 List *indirection,
46 ListCell *indirection_cell,
47 Node *rhs,
48 int location);
49 static Node *transformAssignmentSubscripts(ParseState *pstate,
50 Node *basenode,
51 const char *targetName,
52 Oid targetTypeId,
53 int32 targetTypMod,
54 Oid targetCollation,
55 List *subscripts,
56 bool isSlice,
57 List *indirection,
58 ListCell *next_indirection,
59 Node *rhs,
60 int location);
61 static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
62 bool make_target_entry);
63 static List *ExpandAllTables(ParseState *pstate, int location);
64 static List *ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind,
65 bool make_target_entry, ParseExprKind exprKind);
66 static List *ExpandSingleTable(ParseState *pstate, RangeTblEntry *rte,
67 int location, bool make_target_entry);
68 static List *ExpandRowReference(ParseState *pstate, Node *expr,
69 bool make_target_entry);
70 static int FigureColnameInternal(Node *node, char **name);
71
72
73 /*
74 * transformTargetEntry()
75 * Transform any ordinary "expression-type" node into a targetlist entry.
76 * This is exported so that parse_clause.c can generate targetlist entries
77 * for ORDER/GROUP BY items that are not already in the targetlist.
78 *
79 * node the (untransformed) parse tree for the value expression.
80 * expr the transformed expression, or NULL if caller didn't do it yet.
81 * exprKind expression kind (EXPR_KIND_SELECT_TARGET, etc)
82 * colname the column name to be assigned, or NULL if none yet set.
83 * resjunk true if the target should be marked resjunk, ie, it is not
84 * wanted in the final projected tuple.
85 */
86 TargetEntry *
87 transformTargetEntry(ParseState *pstate,
88 Node *node,
89 Node *expr,
90 ParseExprKind exprKind,
91 char *colname,
92 bool resjunk)
93 {
94 /* Transform the node if caller didn't do it already */
95 if (expr == NULL)
96 {
97 /*
98 * If it's a SetToDefault node and we should allow that, pass it
99 * through unmodified. (transformExpr will throw the appropriate
100 * error if we're disallowing it.)
101 */
102 if (exprKind == EXPR_KIND_UPDATE_SOURCE && IsA(node, SetToDefault))
103 expr = node;
104 else
105 expr = transformExpr(pstate, node, exprKind);
106 }
107
108 if (colname == NULL && !resjunk)
109 {
110 /*
111 * Generate a suitable column name for a column without any explicit
112 * 'AS ColumnName' clause.
113 */
114 colname = FigureColname(node);
115 }
116
117 return makeTargetEntry((Expr *) expr,
118 (AttrNumber) pstate->p_next_resno++,
119 colname,
120 resjunk);
121 }
122
123
124 /*
125 * transformTargetList()
126 * Turns a list of ResTarget's into a list of TargetEntry's.
127 *
128 * This code acts mostly the same for SELECT, UPDATE, or RETURNING lists;
129 * the main thing is to transform the given expressions (the "val" fields).
130 * The exprKind parameter distinguishes these cases when necessary.
131 */
132 List *
133 transformTargetList(ParseState *pstate, List *targetlist,
134 ParseExprKind exprKind)
135 {
136 List *p_target = NIL;
137 bool expand_star;
138 ListCell *o_target;
139
140 /* Shouldn't have any leftover multiassign items at start */
141 Assert(pstate->p_multiassign_exprs == NIL);
142
143 /* Expand "something.*" in SELECT and RETURNING, but not UPDATE */
144 expand_star = (exprKind != EXPR_KIND_UPDATE_SOURCE);
145
146 foreach(o_target, targetlist)
147 {
148 ResTarget *res = (ResTarget *) lfirst(o_target);
149
150 /*
151 * Check for "something.*". Depending on the complexity of the
152 * "something", the star could appear as the last field in ColumnRef,
153 * or as the last indirection item in A_Indirection.
154 */
155 if (expand_star)
156 {
157 if (IsA(res->val, ColumnRef))
158 {
159 ColumnRef *cref = (ColumnRef *) res->val;
160
161 if (IsA(llast(cref->fields), A_Star))
162 {
163 /* It is something.*, expand into multiple items */
164 p_target = list_concat(p_target,
165 ExpandColumnRefStar(pstate,
166 cref,
167 true));
168 continue;
169 }
170 }
171 else if (IsA(res->val, A_Indirection))
172 {
173 A_Indirection *ind = (A_Indirection *) res->val;
174
175 if (IsA(llast(ind->indirection), A_Star))
176 {
177 /* It is something.*, expand into multiple items */
178 p_target = list_concat(p_target,
179 ExpandIndirectionStar(pstate,
180 ind,
181 true,
182 exprKind));
183 continue;
184 }
185 }
186 }
187
188 /*
189 * Not "something.*", or we want to treat that as a plain whole-row
190 * variable, so transform as a single expression
191 */
192 p_target = lappend(p_target,
193 transformTargetEntry(pstate,
194 res->val,
195 NULL,
196 exprKind,
197 res->name,
198 false));
199 }
200
201 /*
202 * If any multiassign resjunk items were created, attach them to the end
203 * of the targetlist. This should only happen in an UPDATE tlist. We
204 * don't need to worry about numbering of these items; transformUpdateStmt
205 * will set their resnos.
206 */
207 if (pstate->p_multiassign_exprs)
208 {
209 Assert(exprKind == EXPR_KIND_UPDATE_SOURCE);
210 p_target = list_concat(p_target, pstate->p_multiassign_exprs);
211 pstate->p_multiassign_exprs = NIL;
212 }
213
214 return p_target;
215 }
216
217
218 /*
219 * transformExpressionList()
220 *
221 * This is the identical transformation to transformTargetList, except that
222 * the input list elements are bare expressions without ResTarget decoration,
223 * and the output elements are likewise just expressions without TargetEntry
224 * decoration. We use this for ROW() and VALUES() constructs.
225 *
226 * exprKind is not enough to tell us whether to allow SetToDefault, so
227 * an additional flag is needed for that.
228 */
229 List *
230 transformExpressionList(ParseState *pstate, List *exprlist,
231 ParseExprKind exprKind, bool allowDefault)
232 {
233 List *result = NIL;
234 ListCell *lc;
235
236 foreach(lc, exprlist)
237 {
238 Node *e = (Node *) lfirst(lc);
239
240 /*
241 * Check for "something.*". Depending on the complexity of the
242 * "something", the star could appear as the last field in ColumnRef,
243 * or as the last indirection item in A_Indirection.
244 */
245 if (IsA(e, ColumnRef))
246 {
247 ColumnRef *cref = (ColumnRef *) e;
248
249 if (IsA(llast(cref->fields), A_Star))
250 {
251 /* It is something.*, expand into multiple items */
252 result = list_concat(result,
253 ExpandColumnRefStar(pstate, cref,
254 false));
255 continue;
256 }
257 }
258 else if (IsA(e, A_Indirection))
259 {
260 A_Indirection *ind = (A_Indirection *) e;
261
262 if (IsA(llast(ind->indirection), A_Star))
263 {
264 /* It is something.*, expand into multiple items */
265 result = list_concat(result,
266 ExpandIndirectionStar(pstate, ind,
267 false, exprKind));
268 continue;
269 }
270 }
271
272 /*
273 * Not "something.*", so transform as a single expression. If it's a
274 * SetToDefault node and we should allow that, pass it through
275 * unmodified. (transformExpr will throw the appropriate error if
276 * we're disallowing it.)
277 */
278 if (allowDefault && IsA(e, SetToDefault))
279 /* do nothing */ ;
280 else
281 e = transformExpr(pstate, e, exprKind);
282
283 result = lappend(result, e);
284 }
285
286 /* Shouldn't have any multiassign items here */
287 Assert(pstate->p_multiassign_exprs == NIL);
288
289 return result;
290 }
291
292
293 /*
294 * resolveTargetListUnknowns()
295 * Convert any unknown-type targetlist entries to type TEXT.
296 *
297 * We do this after we've exhausted all other ways of identifying the output
298 * column types of a query.
299 */
300 void
301 resolveTargetListUnknowns(ParseState *pstate, List *targetlist)
302 {
303 ListCell *l;
304
305 foreach(l, targetlist)
306 {
307 TargetEntry *tle = (TargetEntry *) lfirst(l);
308 Oid restype = exprType((Node *) tle->expr);
309
310 if (restype == UNKNOWNOID)
311 {
312 tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
313 restype, TEXTOID, -1,
314 COERCION_IMPLICIT,
315 COERCE_IMPLICIT_CAST,
316 -1);
317 }
318 }
319 }
320
321
322 /*
323 * markTargetListOrigins()
324 * Mark targetlist columns that are simple Vars with the source
325 * table's OID and column number.
326 *
327 * Currently, this is done only for SELECT targetlists and RETURNING lists,
328 * since we only need the info if we are going to send it to the frontend.
329 */
330 void
331 markTargetListOrigins(ParseState *pstate, List *targetlist)
332 {
333 ListCell *l;
334
335 foreach(l, targetlist)
336 {
337 TargetEntry *tle = (TargetEntry *) lfirst(l);
338
339 markTargetListOrigin(pstate, tle, (Var *) tle->expr, 0);
340 }
341 }
342
343 /*
344 * markTargetListOrigin()
345 * If 'var' is a Var of a plain relation, mark 'tle' with its origin
346 *
347 * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
348 *
349 * This is split out so it can recurse for join references. Note that we
350 * do not drill down into views, but report the view as the column owner.
351 */
352 static void
353 markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
354 Var *var, int levelsup)
355 {
356 int netlevelsup;
357 RangeTblEntry *rte;
358 AttrNumber attnum;
359
360 if (var == NULL || !IsA(var, Var))
361 return;
362 netlevelsup = var->varlevelsup + levelsup;
363 rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);
364 attnum = var->varattno;
365
366 switch (rte->rtekind)
367 {
368 case RTE_RELATION:
369 /* It's a table or view, report it */
370 tle->resorigtbl = rte->relid;
371 tle->resorigcol = attnum;
372 break;
373 case RTE_SUBQUERY:
374 /* Subselect-in-FROM: copy up from the subselect */
375 if (attnum != InvalidAttrNumber)
376 {
377 TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
378 attnum);
379
380 if (ste == NULL || ste->resjunk)
381 elog(ERROR, "subquery %s does not have attribute %d",
382 rte->eref->aliasname, attnum);
383 tle->resorigtbl = ste->resorigtbl;
384 tle->resorigcol = ste->resorigcol;
385 }
386 break;
387 case RTE_JOIN:
388 /* Join RTE --- recursively inspect the alias variable */
389 if (attnum != InvalidAttrNumber)
390 {
391 Var *aliasvar;
392
393 Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
394 aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
395 /* We intentionally don't strip implicit coercions here */
396 markTargetListOrigin(pstate, tle, aliasvar, netlevelsup);
397 }
398 break;
399 case RTE_FUNCTION:
400 case RTE_VALUES:
401 case RTE_TABLEFUNC:
402 case RTE_NAMEDTUPLESTORE:
403 case RTE_RESULT:
404 /* not a simple relation, leave it unmarked */
405 break;
406 case RTE_CTE:
407
408 /*
409 * CTE reference: copy up from the subquery, if possible. If the
410 * RTE is a recursive self-reference then we can't do anything
411 * because we haven't finished analyzing it yet. However, it's no
412 * big loss because we must be down inside the recursive term of a
413 * recursive CTE, and so any markings on the current targetlist
414 * are not going to affect the results anyway.
415 */
416 if (attnum != InvalidAttrNumber && !rte->self_reference)
417 {
418 CommonTableExpr *cte = GetCTEForRTE(pstate, rte, netlevelsup);
419 TargetEntry *ste;
420
421 ste = get_tle_by_resno(GetCTETargetList(cte), attnum);
422 if (ste == NULL || ste->resjunk)
423 elog(ERROR, "subquery %s does not have attribute %d",
424 rte->eref->aliasname, attnum);
425 tle->resorigtbl = ste->resorigtbl;
426 tle->resorigcol = ste->resorigcol;
427 }
428 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 * colname target column name (ie, name of attribute to be assigned to)
446 * attrno target attribute number
447 * indirection subscripts/field names for target column, if any
448 * location error cursor position for the target column, or -1
449 *
450 * Returns the modified expression.
451 *
452 * Note: location points at the target column name (SET target or INSERT
453 * column name list entry), and must therefore be -1 in an INSERT that
454 * omits the column name list. So we should usually prefer to use
455 * exprLocation(expr) for errors that can happen in a default INSERT.
456 */
457 Expr *
458 transformAssignedExpr(ParseState *pstate,
459 Expr *expr,
460 ParseExprKind exprKind,
461 const char *colname,
462 int attrno,
463 List *indirection,
464 int location)
465 {
466 Relation rd = pstate->p_target_relation;
467 Oid type_id; /* type of value provided */
468 Oid attrtype; /* type of target column */
469 int32 attrtypmod;
470 Oid attrcollation; /* collation of target column */
471 ParseExprKind sv_expr_kind;
472
473 /*
474 * Save and restore identity of expression type we're parsing. We must
475 * set p_expr_kind here because we can parse subscripts without going
476 * through transformExpr().
477 */
478 Assert(exprKind != EXPR_KIND_NONE);
479 sv_expr_kind = pstate->p_expr_kind;
480 pstate->p_expr_kind = exprKind;
481
482 Assert(rd != NULL);
483 if (attrno <= 0)
484 ereport(ERROR,
485 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
486 errmsg("cannot assign to system column \"%s\"",
487 colname),
488 parser_errposition(pstate, location)));
489 attrtype = attnumTypeId(rd, attrno);
490 attrtypmod = TupleDescAttr(rd->rd_att, attrno - 1)->atttypmod;
491 attrcollation = TupleDescAttr(rd->rd_att, attrno - 1)->attcollation;
492
493 /*
494 * If the expression is a DEFAULT placeholder, insert the attribute's
495 * type/typmod/collation into it so that exprType etc will report the
496 * right things. (We expect that the eventually substituted default
497 * expression will in fact have this type and typmod. The collation
498 * likely doesn't matter, but let's set it correctly anyway.) Also,
499 * reject trying to update a subfield or array element with DEFAULT, since
500 * there can't be any default for portions of a column.
501 */
502 if (expr && IsA(expr, SetToDefault))
503 {
504 SetToDefault *def = (SetToDefault *) expr;
505
506 def->typeId = attrtype;
507 def->typeMod = attrtypmod;
508 def->collation = attrcollation;
509 if (indirection)
510 {
511 if (IsA(linitial(indirection), A_Indices))
512 ereport(ERROR,
513 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
514 errmsg("cannot set an array element to DEFAULT"),
515 parser_errposition(pstate, location)));
516 else
517 ereport(ERROR,
518 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
519 errmsg("cannot set a subfield to DEFAULT"),
520 parser_errposition(pstate, location)));
521 }
522 }
523
524 /* Now we can use exprType() safely. */
525 type_id = exprType((Node *) expr);
526
527 /*
528 * If there is indirection on the target column, prepare an array or
529 * subfield assignment expression. This will generate a new column value
530 * that the source value has been inserted into, which can then be placed
531 * in the new tuple constructed by INSERT or UPDATE.
532 */
533 if (indirection)
534 {
535 Node *colVar;
536
537 if (pstate->p_is_insert)
538 {
539 /*
540 * The command is INSERT INTO table (col.something) ... so there
541 * is not really a source value to work with. Insert a NULL
542 * constant as the source value.
543 */
544 colVar = (Node *) makeNullConst(attrtype, attrtypmod,
545 attrcollation);
546 }
547 else
548 {
549 /*
550 * Build a Var for the column to be updated.
551 */
552 colVar = (Node *) make_var(pstate,
553 pstate->p_target_rangetblentry,
554 attrno,
555 location);
556 }
557
558 expr = (Expr *)
559 transformAssignmentIndirection(pstate,
560 colVar,
561 colname,
562 false,
563 attrtype,
564 attrtypmod,
565 attrcollation,
566 indirection,
567 list_head(indirection),
568 (Node *) expr,
569 location);
570 }
571 else
572 {
573 /*
574 * For normal non-qualified target column, do type checking and
575 * coercion.
576 */
577 Node *orig_expr = (Node *) expr;
578
579 expr = (Expr *)
580 coerce_to_target_type(pstate,
581 orig_expr, type_id,
582 attrtype, attrtypmod,
583 COERCION_ASSIGNMENT,
584 COERCE_IMPLICIT_CAST,
585 -1);
586 if (expr == NULL)
587 ereport(ERROR,
588 (errcode(ERRCODE_DATATYPE_MISMATCH),
589 errmsg("column \"%s\" is of type %s"
590 " but expression is of type %s",
591 colname,
592 format_type_be(attrtype),
593 format_type_be(type_id)),
594 errhint("You will need to rewrite or cast the expression."),
595 parser_errposition(pstate, exprLocation(orig_expr))));
596 }
597
598 pstate->p_expr_kind = sv_expr_kind;
599
600 return expr;
601 }
602
603
604 /*
605 * updateTargetListEntry()
606 * This is used in UPDATE statements (and ON CONFLICT DO UPDATE)
607 * only. It prepares an UPDATE TargetEntry for assignment to a
608 * column of the target table. This includes coercing the given
609 * value to the target column's type (if necessary), and dealing with
610 * any subfield names or subscripts attached to the target column
611 * itself.
612 *
613 * pstate parse state
614 * tle target list entry to be modified
615 * colname target column name (ie, name of attribute to be assigned to)
616 * attrno target attribute number
617 * indirection subscripts/field names for target column, if any
618 * location error cursor position (should point at column name), or -1
619 */
620 void
621 updateTargetListEntry(ParseState *pstate,
622 TargetEntry *tle,
623 char *colname,
624 int attrno,
625 List *indirection,
626 int location)
627 {
628 /* Fix up expression as needed */
629 tle->expr = transformAssignedExpr(pstate,
630 tle->expr,
631 EXPR_KIND_UPDATE_TARGET,
632 colname,
633 attrno,
634 indirection,
635 location);
636
637 /*
638 * Set the resno to identify the target column --- the rewriter and
639 * planner depend on this. We also set the resname to identify the target
640 * column, but this is only for debugging purposes; it should not be
641 * relied on. (In particular, it might be out of date in a stored rule.)
642 */
643 tle->resno = (AttrNumber) attrno;
644 tle->resname = colname;
645 }
646
647
648 /*
649 * Process indirection (field selection or subscripting) of the target
650 * column in INSERT/UPDATE. This routine recurses for multiple levels
651 * of indirection --- but note that several adjacent A_Indices nodes in
652 * the indirection list are treated as a single multidimensional subscript
653 * operation.
654 *
655 * In the initial call, basenode is a Var for the target column in UPDATE,
656 * or a null Const of the target's type in INSERT. In recursive calls,
657 * basenode is NULL, indicating that a substitute node should be consed up if
658 * needed.
659 *
660 * targetName is the name of the field or subfield we're assigning to, and
661 * targetIsSubscripting is true if we're subscripting it. These are just for
662 * error reporting.
663 *
664 * targetTypeId, targetTypMod, targetCollation indicate the datatype and
665 * collation of the object to be assigned to (initially the target column,
666 * later some subobject).
667 *
668 * indirection is the list of indirection nodes, and indirection_cell is the
669 * start of the sublist remaining to process. When it's NULL, we're done
670 * recursing and can just coerce and return the RHS.
671 *
672 * rhs is the already-transformed value to be assigned; note it has not been
673 * coerced to any particular type.
674 *
675 * location is the cursor error position for any errors. (Note: this points
676 * to the head of the target clause, eg "foo" in "foo.bar[baz]". Later we
677 * might want to decorate indirection cells with their own location info,
678 * in which case the location argument could probably be dropped.)
679 */
680 static Node *
681 transformAssignmentIndirection(ParseState *pstate,
682 Node *basenode,
683 const char *targetName,
684 bool targetIsSubscripting,
685 Oid targetTypeId,
686 int32 targetTypMod,
687 Oid targetCollation,
688 List *indirection,
689 ListCell *indirection_cell,
690 Node *rhs,
691 int location)
692 {
693 Node *result;
694 List *subscripts = NIL;
695 bool isSlice = false;
696 ListCell *i;
697
698 if (indirection_cell && !basenode)
699 {
700 /*
701 * Set up a substitution. We abuse CaseTestExpr for this. It's safe
702 * to do so because the only nodes that will be above the CaseTestExpr
703 * in the finished expression will be FieldStore and SubscriptingRef
704 * nodes. (There could be other stuff in the tree, but it will be
705 * within other child fields of those node types.)
706 */
707 CaseTestExpr *ctest = makeNode(CaseTestExpr);
708
709 ctest->typeId = targetTypeId;
710 ctest->typeMod = targetTypMod;
711 ctest->collation = targetCollation;
712 basenode = (Node *) ctest;
713 }
714
715 /*
716 * We have to split any field-selection operations apart from
717 * subscripting. Adjacent A_Indices nodes have to be treated as a single
718 * multidimensional subscript operation.
719 */
720 for_each_cell(i, indirection, indirection_cell)
721 {
722 Node *n = lfirst(i);
723
724 if (IsA(n, A_Indices))
725 {
726 subscripts = lappend(subscripts, n);
727 if (((A_Indices *) n)->is_slice)
728 isSlice = true;
729 }
730 else if (IsA(n, A_Star))
731 {
732 ereport(ERROR,
733 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
734 errmsg("row expansion via \"*\" is not supported here"),
735 parser_errposition(pstate, location)));
736 }
737 else
738 {
739 FieldStore *fstore;
740 Oid baseTypeId;
741 int32 baseTypeMod;
742 Oid typrelid;
743 AttrNumber attnum;
744 Oid fieldTypeId;
745 int32 fieldTypMod;
746 Oid fieldCollation;
747
748 Assert(IsA(n, String));
749
750 /* process subscripts before this field selection */
751 if (subscripts)
752 {
753 /* recurse, and then return because we're done */
754 return transformAssignmentSubscripts(pstate,
755 basenode,
756 targetName,
757 targetTypeId,
758 targetTypMod,
759 targetCollation,
760 subscripts,
761 isSlice,
762 indirection,
763 i,
764 rhs,
765 location);
766 }
767
768 /* No subscripts, so can process field selection here */
769
770 /*
771 * Look up the composite type, accounting for possibility that
772 * what we are given is a domain over composite.
773 */
774 baseTypeMod = targetTypMod;
775 baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod);
776
777 typrelid = typeidTypeRelid(baseTypeId);
778 if (!typrelid)
779 ereport(ERROR,
780 (errcode(ERRCODE_DATATYPE_MISMATCH),
781 errmsg("cannot assign to field \"%s\" of column \"%s\" because its type %s is not a composite type",
782 strVal(n), targetName,
783 format_type_be(targetTypeId)),
784 parser_errposition(pstate, location)));
785
786 attnum = get_attnum(typrelid, strVal(n));
787 if (attnum == InvalidAttrNumber)
788 ereport(ERROR,
789 (errcode(ERRCODE_UNDEFINED_COLUMN),
790 errmsg("cannot assign to field \"%s\" of column \"%s\" because there is no such column in data type %s",
791 strVal(n), targetName,
792 format_type_be(targetTypeId)),
793 parser_errposition(pstate, location)));
794 if (attnum < 0)
795 ereport(ERROR,
796 (errcode(ERRCODE_UNDEFINED_COLUMN),
797 errmsg("cannot assign to system column \"%s\"",
798 strVal(n)),
799 parser_errposition(pstate, location)));
800
801 get_atttypetypmodcoll(typrelid, attnum,
802 &fieldTypeId, &fieldTypMod, &fieldCollation);
803
804 /* recurse to create appropriate RHS for field assign */
805 rhs = transformAssignmentIndirection(pstate,
806 NULL,
807 strVal(n),
808 false,
809 fieldTypeId,
810 fieldTypMod,
811 fieldCollation,
812 indirection,
813 lnext(indirection, i),
814 rhs,
815 location);
816
817 /* and build a FieldStore node */
818 fstore = makeNode(FieldStore);
819 fstore->arg = (Expr *) basenode;
820 fstore->newvals = list_make1(rhs);
821 fstore->fieldnums = list_make1_int(attnum);
822 fstore->resulttype = baseTypeId;
823
824 /* If target is a domain, apply constraints */
825 if (baseTypeId != targetTypeId)
826 return coerce_to_domain((Node *) fstore,
827 baseTypeId, baseTypeMod,
828 targetTypeId,
829 COERCION_IMPLICIT,
830 COERCE_IMPLICIT_CAST,
831 location,
832 false);
833
834 return (Node *) fstore;
835 }
836 }
837
838 /* process trailing subscripts, if any */
839 if (subscripts)
840 {
841 /* recurse, and then return because we're done */
842 return transformAssignmentSubscripts(pstate,
843 basenode,
844 targetName,
845 targetTypeId,
846 targetTypMod,
847 targetCollation,
848 subscripts,
849 isSlice,
850 indirection,
851 NULL,
852 rhs,
853 location);
854 }
855
856 /* base case: just coerce RHS to match target type ID */
857
858 result = coerce_to_target_type(pstate,
859 rhs, exprType(rhs),
860 targetTypeId, targetTypMod,
861 COERCION_ASSIGNMENT,
862 COERCE_IMPLICIT_CAST,
863 -1);
864 if (result == NULL)
865 {
866 if (targetIsSubscripting)
867 ereport(ERROR,
868 (errcode(ERRCODE_DATATYPE_MISMATCH),
869 errmsg("array assignment to \"%s\" requires type %s"
870 " but expression is of type %s",
871 targetName,
872 format_type_be(targetTypeId),
873 format_type_be(exprType(rhs))),
874 errhint("You will need to rewrite or cast the expression."),
875 parser_errposition(pstate, location)));
876 else
877 ereport(ERROR,
878 (errcode(ERRCODE_DATATYPE_MISMATCH),
879 errmsg("subfield \"%s\" is of type %s"
880 " but expression is of type %s",
881 targetName,
882 format_type_be(targetTypeId),
883 format_type_be(exprType(rhs))),
884 errhint("You will need to rewrite or cast the expression."),
885 parser_errposition(pstate, location)));
886 }
887
888 return result;
889 }
890
891 /*
892 * helper for transformAssignmentIndirection: process container assignment
893 */
894 static Node *
895 transformAssignmentSubscripts(ParseState *pstate,
896 Node *basenode,
897 const char *targetName,
898 Oid targetTypeId,
899 int32 targetTypMod,
900 Oid targetCollation,
901 List *subscripts,
902 bool isSlice,
903 List *indirection,
904 ListCell *next_indirection,
905 Node *rhs,
906 int location)
907 {
908 Node *result;
909 Oid containerType;
910 int32 containerTypMod;
911 Oid elementTypeId;
912 Oid typeNeeded;
913 Oid collationNeeded;
914
915 Assert(subscripts != NIL);
916
917 /* Identify the actual array type and element type involved */
918 containerType = targetTypeId;
919 containerTypMod = targetTypMod;
920 elementTypeId = transformContainerType(&containerType, &containerTypMod);
921
922 /* Identify type that RHS must provide */
923 typeNeeded = isSlice ? containerType : elementTypeId;
924
925 /*
926 * container normally has same collation as elements, but there's an
927 * exception: we might be subscripting a domain over a container type. In
928 * that case use collation of the base type.
929 */
930 if (containerType == targetTypeId)
931 collationNeeded = targetCollation;
932 else
933 collationNeeded = get_typcollation(containerType);
934
935 /* recurse to create appropriate RHS for container assign */
936 rhs = transformAssignmentIndirection(pstate,
937 NULL,
938 targetName,
939 true,
940 typeNeeded,
941 containerTypMod,
942 collationNeeded,
943 indirection,
944 next_indirection,
945 rhs,
946 location);
947
948 /* process subscripts */
949 result = (Node *) transformContainerSubscripts(pstate,
950 basenode,
951 containerType,
952 elementTypeId,
953 containerTypMod,
954 subscripts,
955 rhs);
956
957 /* If target was a domain over container, need to coerce up to the domain */
958 if (containerType != targetTypeId)
959 {
960 Oid resulttype = exprType(result);
961
962 result = coerce_to_target_type(pstate,
963 result, resulttype,
964 targetTypeId, targetTypMod,
965 COERCION_ASSIGNMENT,
966 COERCE_IMPLICIT_CAST,
967 -1);
968 /* can fail if we had int2vector/oidvector, but not for true domains */
969 if (result == NULL)
970 ereport(ERROR,
971 (errcode(ERRCODE_CANNOT_COERCE),
972 errmsg("cannot cast type %s to %s",
973 format_type_be(resulttype),
974 format_type_be(targetTypeId)),
975 parser_errposition(pstate, location)));
976 }
977
978 return result;
979 }
980
981
982 /*