1 /*-------------------------------------------------------------------------
4 * Routines to preprocess the parse tree target list
6 * This module takes care of altering the query targetlist as needed for
7 * INSERT, UPDATE, and DELETE queries. For INSERT and UPDATE queries,
8 * the targetlist must contain an entry for each attribute of the target
9 * relation in the correct order. For both UPDATE and DELETE queries,
10 * we need a junk targetlist entry holding the CTID attribute --- the
11 * executor relies on this to find the tuple to be replaced/deleted.
12 * We may also need junk tlist entries for Vars used in the RETURNING list.
15 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
16 * Portions Copyright (c) 1994, Regents of the University of California
21 *-------------------------------------------------------------------------
26 #include "access/heapam.h"
27 #include "access/sysattr.h"
28 #include "catalog/pg_type.h"
29 #include "nodes/makefuncs.h"
30 #include "optimizer/prep.h"
31 #include "optimizer/subselect.h"
32 #include "optimizer/tlist.h"
33 #include "optimizer/var.h"
34 #include "parser/analyze.h"
35 #include "parser/parsetree.h"
36 #include "parser/parse_coerce.h"
37 #include "utils/rel.h"
40 static List
*expand_targetlist(List
*tlist
, int command_type
,
41 Index result_relation
, List
*range_table
);
45 * preprocess_targetlist
46 * Driver for preprocessing the parse tree targetlist.
48 * Returns the new targetlist.
51 preprocess_targetlist(PlannerInfo
*root
, List
*tlist
)
53 Query
*parse
= root
->parse
;
54 int result_relation
= parse
->resultRelation
;
55 List
*range_table
= parse
->rtable
;
56 CmdType command_type
= parse
->commandType
;
59 * Sanity check: if there is a result relation, it'd better be a real
60 * relation not a subquery. Else parser or rewriter messed up.
64 RangeTblEntry
*rte
= rt_fetch(result_relation
, range_table
);
66 if (rte
->subquery
!= NULL
|| rte
->relid
== InvalidOid
)
67 elog(ERROR
, "subquery cannot be result relation");
71 * for heap_form_tuple to work, the targetlist must match the exact order
72 * of the attributes. We also need to fill in any missing attributes. -ay
75 if (command_type
== CMD_INSERT
|| command_type
== CMD_UPDATE
)
76 tlist
= expand_targetlist(tlist
, command_type
,
77 result_relation
, range_table
);
80 * for "update" and "delete" queries, add ctid of the result relation into
81 * the target list so that the ctid will propagate through execution and
82 * ExecutePlan() will be able to identify the right tuple to replace or
83 * delete. This extra field is marked "junk" so that it is not stored
84 * back into the tuple.
86 if (command_type
== CMD_UPDATE
|| command_type
== CMD_DELETE
)
91 var
= makeVar(result_relation
, SelfItemPointerAttributeNumber
,
94 tle
= makeTargetEntry((Expr
*) var
,
95 list_length(tlist
) + 1,
100 * For an UPDATE, expand_targetlist already created a fresh tlist. For
101 * DELETE, better do a listCopy so that we don't destructively modify
102 * the original tlist (is this really necessary?).
104 if (command_type
== CMD_DELETE
)
105 tlist
= list_copy(tlist
);
107 tlist
= lappend(tlist
, tle
);
111 * Add TID targets for rels selected FOR UPDATE/SHARE. The executor uses
112 * the TID to know which rows to lock, much as for UPDATE or DELETE.
119 * We've got trouble if the FOR UPDATE/SHARE appears inside grouping,
120 * since grouping renders a reference to individual tuple CTIDs
121 * invalid. This is also checked at parse time, but that's
122 * insufficient because of rule substitution, query pullup, etc.
124 CheckSelectLocking(parse
);
127 * Currently the executor only supports FOR UPDATE/SHARE at top level
129 if (root
->query_level
> 1)
131 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
132 errmsg("SELECT FOR UPDATE/SHARE is not allowed in subqueries")));
134 foreach(l
, parse
->rowMarks
)
136 RowMarkClause
*rc
= (RowMarkClause
*) lfirst(l
);
141 var
= makeVar(rc
->rti
,
142 SelfItemPointerAttributeNumber
,
147 resname
= (char *) palloc(32);
148 snprintf(resname
, 32, "ctid%u", rc
->rti
);
150 tle
= makeTargetEntry((Expr
*) var
,
151 list_length(tlist
) + 1,
155 tlist
= lappend(tlist
, tle
);
160 * If the query has a RETURNING list, add resjunk entries for any Vars
161 * used in RETURNING that belong to other relations. We need to do this
162 * to make these Vars available for the RETURNING calculation. Vars that
163 * belong to the result rel don't need to be added, because they will be
164 * made to refer to the actual heap tuple.
166 if (parse
->returningList
&& list_length(parse
->rtable
) > 1)
171 vars
= pull_var_clause((Node
*) parse
->returningList
, true);
174 Var
*var
= (Var
*) lfirst(l
);
178 var
->varno
== result_relation
)
179 continue; /* don't need it */
181 if (tlist_member((Node
*) var
, tlist
))
182 continue; /* already got it */
184 tle
= makeTargetEntry((Expr
*) var
,
185 list_length(tlist
) + 1,
189 tlist
= lappend(tlist
, tle
);
197 /*****************************************************************************
199 * TARGETLIST EXPANSION
201 *****************************************************************************/
205 * Given a target list as generated by the parser and a result relation,
206 * add targetlist entries for any missing attributes, and ensure the
207 * non-junk attributes appear in proper field order.
209 * NOTE: if you are tempted to put more processing here, consider whether
210 * it shouldn't go in the rewriter's rewriteTargetList() instead.
213 expand_targetlist(List
*tlist
, int command_type
,
214 Index result_relation
, List
*range_table
)
216 List
*new_tlist
= NIL
;
217 ListCell
*tlist_item
;
222 tlist_item
= list_head(tlist
);
225 * The rewriter should have already ensured that the TLEs are in correct
226 * order; but we have to insert TLEs for any missing attributes.
228 * Scan the tuple description in the relation's relcache entry to make
229 * sure we have all the user attributes in the right order. We assume
230 * that the rewriter already acquired at least AccessShareLock on the
231 * relation, so we need no lock here.
233 rel
= heap_open(getrelid(result_relation
, range_table
), NoLock
);
235 numattrs
= RelationGetNumberOfAttributes(rel
);
237 for (attrno
= 1; attrno
<= numattrs
; attrno
++)
239 Form_pg_attribute att_tup
= rel
->rd_att
->attrs
[attrno
- 1];
240 TargetEntry
*new_tle
= NULL
;
242 if (tlist_item
!= NULL
)
244 TargetEntry
*old_tle
= (TargetEntry
*) lfirst(tlist_item
);
246 if (!old_tle
->resjunk
&& old_tle
->resno
== attrno
)
249 tlist_item
= lnext(tlist_item
);
256 * Didn't find a matching tlist entry, so make one.
258 * For INSERT, generate a NULL constant. (We assume the rewriter
259 * would have inserted any available default value.) Also, if the
260 * column isn't dropped, apply any domain constraints that might
261 * exist --- this is to catch domain NOT NULL.
263 * For UPDATE, generate a Var reference to the existing value of
264 * the attribute, so that it gets copied to the new tuple. But
265 * generate a NULL for dropped columns (we want to drop any old
268 * When generating a NULL constant for a dropped column, we label
269 * it INT4 (any other guaranteed-to-exist datatype would do as
270 * well). We can't label it with the dropped column's datatype
271 * since that might not exist anymore. It does not really matter
272 * what we claim the type is, since NULL is NULL --- its
273 * representation is datatype-independent. This could perhaps
274 * confuse code comparing the finished plan to the target
277 Oid atttype
= att_tup
->atttypid
;
278 int32 atttypmod
= att_tup
->atttypmod
;
281 switch (command_type
)
284 if (!att_tup
->attisdropped
)
286 new_expr
= (Node
*) makeConst(atttype
,
292 new_expr
= coerce_to_domain(new_expr
,
295 COERCE_IMPLICIT_CAST
,
302 /* Insert NULL for dropped column */
303 new_expr
= (Node
*) makeConst(INT4OID
,
312 if (!att_tup
->attisdropped
)
314 new_expr
= (Node
*) makeVar(result_relation
,
322 /* Insert NULL for dropped column */
323 new_expr
= (Node
*) makeConst(INT4OID
,
332 elog(ERROR
, "unrecognized command_type: %d",
334 new_expr
= NULL
; /* keep compiler quiet */
338 new_tle
= makeTargetEntry((Expr
*) new_expr
,
340 pstrdup(NameStr(att_tup
->attname
)),
344 new_tlist
= lappend(new_tlist
, new_tle
);
348 * The remaining tlist entries should be resjunk; append them all to the
349 * end of the new tlist, making sure they have resnos higher than the last
350 * real attribute. (Note: although the rewriter already did such
351 * renumbering, we have to do it again here in case we are doing an UPDATE
352 * in a table with dropped columns, or an inheritance child table with
357 TargetEntry
*old_tle
= (TargetEntry
*) lfirst(tlist_item
);
359 if (!old_tle
->resjunk
)
360 elog(ERROR
, "targetlist is not sorted correctly");
361 /* Get the resno right, but don't copy unnecessarily */
362 if (old_tle
->resno
!= attrno
)
364 old_tle
= flatCopyTargetEntry(old_tle
);
365 old_tle
->resno
= attrno
;
367 new_tlist
= lappend(new_tlist
, old_tle
);
369 tlist_item
= lnext(tlist_item
);
372 heap_close(rel
, NoLock
);