]> granicus.if.org Git - postgresql/blob - src/backend/optimizer/prep/preptlist.c
Removed obsolete DROP_COLUMN_HACK stuff.
[postgresql] / src / backend / optimizer / prep / preptlist.c
1 /*-------------------------------------------------------------------------
2  *
3  * preptlist.c
4  *        Routines to preprocess the parse tree target list
5  *
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  *
13  *
14  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
15  * Portions Copyright (c) 1994, Regents of the University of California
16  *
17  * IDENTIFICATION
18  *        $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.51 2002/04/02 08:51:51 inoue Exp $
19  *
20  *-------------------------------------------------------------------------
21  */
22
23 #include "postgres.h"
24
25 #include "access/heapam.h"
26 #include "catalog/pg_type.h"
27 #include "nodes/makefuncs.h"
28 #include "optimizer/prep.h"
29 #include "parser/parsetree.h"
30 #include "parser/parse_coerce.h"
31 #include "parser/parse_expr.h"
32 #include "parser/parse_target.h"
33 #include "utils/builtins.h"
34 #include "utils/lsyscache.h"
35
36
37 static List *expand_targetlist(List *tlist, int command_type,
38                                   Index result_relation, List *range_table);
39 static TargetEntry *process_matched_tle(TargetEntry *src_tle,
40                                         TargetEntry *prior_tle,
41                                         int attrno);
42 static Node *build_column_default(Relation rel, int attrno);
43
44
45 /*
46  * preprocess_targetlist
47  *        Driver for preprocessing the parse tree targetlist.
48  *
49  *        Returns the new targetlist.
50  */
51 List *
52 preprocess_targetlist(List *tlist,
53                                           int command_type,
54                                           Index result_relation,
55                                           List *range_table)
56 {
57         /*
58          * Sanity check: if there is a result relation, it'd better be a real
59          * relation not a subquery.  Else parser or rewriter messed up.
60          */
61         if (result_relation)
62         {
63                 RangeTblEntry *rte = rt_fetch(result_relation, range_table);
64
65                 if (rte->subquery != NULL || rte->relid == InvalidOid)
66                         elog(ERROR, "preprocess_targetlist: subquery cannot be result relation");
67         }
68
69         /*
70          * for heap_formtuple to work, the targetlist must match the exact
71          * order of the attributes. We also need to fill in any missing
72          * attributes.                                                  -ay 10/94
73          */
74         if (command_type == CMD_INSERT || command_type == CMD_UPDATE)
75                 tlist = expand_targetlist(tlist, command_type,
76                                                                   result_relation, range_table);
77
78         /*
79          * for "update" and "delete" queries, add ctid of the result relation
80          * into the target list so that the ctid will propagate through
81          * execution and ExecutePlan() will be able to identify the right
82          * tuple to replace or delete.  This extra field is marked "junk" so
83          * that it is not stored back into the tuple.
84          */
85         if (command_type == CMD_UPDATE || command_type == CMD_DELETE)
86         {
87                 Resdom     *resdom;
88                 Var                *var;
89
90                 resdom = makeResdom(length(tlist) + 1,
91                                                         TIDOID,
92                                                         -1,
93                                                         pstrdup("ctid"),
94                                                         true);
95
96                 var = makeVar(result_relation, SelfItemPointerAttributeNumber,
97                                           TIDOID, -1, 0);
98
99                 /*
100                  * For an UPDATE, expand_targetlist already created a fresh tlist.
101                  * For DELETE, better do a listCopy so that we don't destructively
102                  * modify the original tlist (is this really necessary?).
103                  */
104                 if (command_type == CMD_DELETE)
105                         tlist = listCopy(tlist);
106
107                 tlist = lappend(tlist, makeTargetEntry(resdom, (Node *) var));
108         }
109
110         return tlist;
111 }
112
113 /*****************************************************************************
114  *
115  *              TARGETLIST EXPANSION
116  *
117  *****************************************************************************/
118
119 /*
120  * expand_targetlist
121  *        Given a target list as generated by the parser and a result relation,
122  *        add targetlist entries for any missing attributes, and order the
123  *        non-junk attributes in proper field order.
124  */
125 static List *
126 expand_targetlist(List *tlist, int command_type,
127                                   Index result_relation, List *range_table)
128 {
129         int                     old_tlist_len = length(tlist);
130         List       *new_tlist = NIL;
131         bool       *tlistentry_used;
132         Relation        rel;
133         int                     attrno,
134                                 numattrs,
135                                 old_tlist_index;
136         List       *temp;
137
138         /*
139          * Keep a map of which tlist items we have transferred to new list.
140          *
141          * +1 here just keeps palloc from complaining if old_tlist_len==0.
142          */
143         tlistentry_used = (bool *) palloc((old_tlist_len + 1) * sizeof(bool));
144         memset(tlistentry_used, 0, (old_tlist_len + 1) * sizeof(bool));
145
146         /*
147          * Scan the tuple description in the relation's relcache entry to make
148          * sure we have all the user attributes in the right order.
149          */
150         rel = heap_open(getrelid(result_relation, range_table), AccessShareLock);
151
152         numattrs = RelationGetNumberOfAttributes(rel);
153
154         for (attrno = 1; attrno <= numattrs; attrno++)
155         {
156                 Form_pg_attribute att_tup = rel->rd_att->attrs[attrno - 1];
157                 char       *attrname = NameStr(att_tup->attname);
158                 TargetEntry *new_tle = NULL;
159
160                 /*
161                  * We match targetlist entries to attributes using the resname.
162                  * Junk attributes are not candidates to be matched.
163                  */
164                 old_tlist_index = 0;
165                 foreach(temp, tlist)
166                 {
167                         TargetEntry *old_tle = (TargetEntry *) lfirst(temp);
168                         Resdom     *resdom = old_tle->resdom;
169
170                         if (!tlistentry_used[old_tlist_index] &&
171                                 !resdom->resjunk &&
172                                 strcmp(resdom->resname, attrname) == 0)
173                         {
174                                 new_tle = process_matched_tle(old_tle, new_tle, attrno);
175                                 tlistentry_used[old_tlist_index] = true;
176                                 /* keep scanning to detect multiple assignments to attr */
177                         }
178                         old_tlist_index++;
179                 }
180
181                 if (new_tle == NULL)
182                 {
183                         /*
184                          * Didn't find a matching tlist entry, so make one.
185                          *
186                          * For INSERT, generate an appropriate default value.
187                          *
188                          * For UPDATE, generate a Var reference to the existing value of
189                          * the attribute, so that it gets copied to the new tuple.
190                          */
191                         Oid                     atttype = att_tup->atttypid;
192                         int32           atttypmod = att_tup->atttypmod;
193                         Node       *new_expr;
194
195                         switch (command_type)
196                         {
197                                 case CMD_INSERT:
198                                         new_expr = build_column_default(rel, attrno);
199                                         break;
200                                 case CMD_UPDATE:
201                                                 new_expr = (Node *) makeVar(result_relation,
202                                                                                                         attrno,
203                                                                                                         atttype,
204                                                                                                         atttypmod,
205                                                                                                         0);
206                                         break;
207                                 default:
208                                         elog(ERROR, "expand_targetlist: unexpected command_type");
209                                         new_expr = NULL;        /* keep compiler quiet */
210                                         break;
211                         }
212
213                         new_tle = makeTargetEntry(makeResdom(attrno,
214                                                                                                  atttype,
215                                                                                                  atttypmod,
216                                                                                                  pstrdup(attrname),
217                                                                                                  false),
218                                                                           new_expr);
219                 }
220
221                 new_tlist = lappend(new_tlist, new_tle);
222         }
223
224         /*
225          * Copy all unprocessed tlist entries to the end of the new tlist,
226          * making sure they are marked resjunk = true.  Typical junk entries
227          * include ORDER BY or GROUP BY expressions (are these actually
228          * possible in an INSERT or UPDATE?), system attribute references,
229          * etc.
230          */
231         old_tlist_index = 0;
232         foreach(temp, tlist)
233         {
234                 TargetEntry *old_tle = (TargetEntry *) lfirst(temp);
235
236                 if (!tlistentry_used[old_tlist_index])
237                 {
238                         Resdom     *resdom = old_tle->resdom;
239
240                         if (!resdom->resjunk)
241                                 elog(ERROR, "Unexpected assignment to attribute \"%s\"",
242                                          resdom->resname);
243                         /* Get the resno right, but don't copy unnecessarily */
244                         if (resdom->resno != attrno)
245                         {
246                                 resdom = (Resdom *) copyObject((Node *) resdom);
247                                 resdom->resno = attrno;
248                                 old_tle = makeTargetEntry(resdom, old_tle->expr);
249                         }
250                         new_tlist = lappend(new_tlist, old_tle);
251                         attrno++;
252                 }
253                 old_tlist_index++;
254         }
255
256         heap_close(rel, AccessShareLock);
257
258         pfree(tlistentry_used);
259
260         return new_tlist;
261 }
262
263
264 /*
265  * Convert a matched TLE from the original tlist into a correct new TLE.
266  *
267  * This routine checks for multiple assignments to the same target attribute,
268  * such as "UPDATE table SET foo = 42, foo = 43".  This is OK only if they
269  * are array assignments, ie, "UPDATE table SET foo[2] = 42, foo[4] = 43".
270  * If so, we need to merge the operations into a single assignment op.
271  * Essentially, the expression we want to produce in this case is like
272  *              foo = array_set(array_set(foo, 2, 42), 4, 43)
273  */
274 static TargetEntry *
275 process_matched_tle(TargetEntry *src_tle,
276                                         TargetEntry *prior_tle,
277                                         int attrno)
278 {
279         Resdom     *resdom = src_tle->resdom;
280         Node       *priorbottom;
281         ArrayRef   *newexpr;
282
283         if (prior_tle == NULL)
284         {
285                 /*
286                  * Normal case where this is the first assignment to the
287                  * attribute.
288                  *
289                  * We can recycle the old TLE+resdom if right resno; else make a new
290                  * one to avoid modifying the old tlist structure. (Is preserving
291                  * old tlist actually necessary?  Not sure, be safe.)
292                  */
293                 if (resdom->resno == attrno)
294                         return src_tle;
295                 resdom = (Resdom *) copyObject((Node *) resdom);
296                 resdom->resno = attrno;
297                 return makeTargetEntry(resdom, src_tle->expr);
298         }
299
300         /*
301          * Multiple assignments to same attribute.      Allow only if all are
302          * array-assign operators with same bottom array object.
303          */
304         if (src_tle->expr == NULL || !IsA(src_tle->expr, ArrayRef) ||
305                 ((ArrayRef *) src_tle->expr)->refassgnexpr == NULL ||
306                 prior_tle->expr == NULL || !IsA(prior_tle->expr, ArrayRef) ||
307                 ((ArrayRef *) prior_tle->expr)->refassgnexpr == NULL ||
308                 ((ArrayRef *) src_tle->expr)->refelemtype !=
309                 ((ArrayRef *) prior_tle->expr)->refelemtype)
310                 elog(ERROR, "Multiple assignments to same attribute \"%s\"",
311                          resdom->resname);
312
313         /*
314          * Prior TLE could be a nest of ArrayRefs if we do this more than
315          * once.
316          */
317         priorbottom = ((ArrayRef *) prior_tle->expr)->refexpr;
318         while (priorbottom != NULL && IsA(priorbottom, ArrayRef) &&
319                    ((ArrayRef *) priorbottom)->refassgnexpr != NULL)
320                 priorbottom = ((ArrayRef *) priorbottom)->refexpr;
321         if (!equal(priorbottom, ((ArrayRef *) src_tle->expr)->refexpr))
322                 elog(ERROR, "Multiple assignments to same attribute \"%s\"",
323                          resdom->resname);
324
325         /*
326          * Looks OK to nest 'em.
327          */
328         newexpr = makeNode(ArrayRef);
329         memcpy(newexpr, src_tle->expr, sizeof(ArrayRef));
330         newexpr->refexpr = prior_tle->expr;
331
332         resdom = (Resdom *) copyObject((Node *) resdom);
333         resdom->resno = attrno;
334         return makeTargetEntry(resdom, (Node *) newexpr);
335 }
336
337
338 /*
339  * Make an expression tree for the default value for a column.
340  *
341  * This is used to fill in missing attributes in an INSERT targetlist.
342  * We look first to see if the column has a default value expression.
343  * If not, generate a constant of the default value for the attribute type,
344  * or a NULL if the type has no default value either.
345  */
346 static Node *
347 build_column_default(Relation rel, int attrno)
348 {
349         TupleDesc       rd_att = rel->rd_att;
350         Form_pg_attribute att_tup = rd_att->attrs[attrno - 1];
351         Oid                     atttype = att_tup->atttypid;
352         int32           atttypmod = att_tup->atttypmod;
353         int16           typlen = att_tup->attlen;
354         bool            typbyval = att_tup->attbyval;
355         Node       *expr = NULL;
356
357         /*
358          * Scan to see if relation has a default for this column.
359          */
360         if (rd_att->constr && rd_att->constr->num_defval > 0)
361         {
362                 AttrDefault *defval = rd_att->constr->defval;
363                 int                     ndef = rd_att->constr->num_defval;
364
365                 while (--ndef >= 0)
366                 {
367                         if (attrno == defval[ndef].adnum)
368                         {
369                                 /*
370                                  * Found it, convert string representation to node tree.
371                                  */
372                                 expr = stringToNode(defval[ndef].adbin);
373                                 break;
374                         }
375                 }
376         }
377
378         if (expr == NULL)
379         {
380                 /*
381                  * No per-column default, so look for a default for the type itself.
382                  */
383                 if (att_tup->attisset)
384                 {
385                         /*
386                          * Set attributes are represented as OIDs no matter what the set
387                          * element type is, and the element type's default is irrelevant
388                          * too.
389                          */
390                         typlen = sizeof(Oid);
391                         typbyval = true;
392                 }
393                 else
394                 {
395                         expr = get_typdefault(atttype);
396                 }
397         }
398
399         if (expr == NULL)
400         {
401                 /*
402                  * No default anywhere, so generate a NULL constant.
403                  */
404                 expr = (Node *) makeConst(atttype,
405                                                                   typlen,
406                                                                   (Datum) 0,
407                                                                   true,                 /* isnull */
408                                                                   typbyval,
409                                                                   false,                /* not a set */
410                                                                   false);
411         }
412         else
413         {
414                 Oid                     exprtype;
415
416                 /*
417                  * Make sure the value is coerced to the target column
418                  * type (might not be right type yet if it's not a
419                  * constant!)  This should match the parser's processing of
420                  * non-defaulted expressions --- see
421                  * updateTargetListEntry().
422                  */
423                 exprtype = exprType(expr);
424
425                 if (exprtype != atttype)
426                 {
427                         expr = CoerceTargetExpr(NULL, expr, exprtype,
428                                                                         atttype, atttypmod);
429
430                         /*
431                          * This really shouldn't fail; should have checked the
432                          * default's type when it was created ...
433                          */
434                         if (expr == NULL)
435                                 elog(ERROR, "Column \"%s\" is of type %s"
436                                          " but default expression is of type %s"
437                                          "\n\tYou will need to rewrite or cast the expression",
438                                          NameStr(att_tup->attname),
439                                          format_type_be(atttype),
440                                          format_type_be(exprtype));
441                 }
442
443                 /*
444                  * If the column is a fixed-length type, it may need a
445                  * length coercion as well as a type coercion.
446                  */
447                 expr = coerce_type_typmod(NULL, expr, atttype, atttypmod);
448         }
449
450         return expr;
451 }