15
15
* Portions Copyright (c) 1994, Regents of the University of California
16
16
*
17
17
* IDENTIFICATION
18
- * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.51 2002/04/02 08:51:51 inoue Exp $
18
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.52 2002/04/05 05:47:05 tgl Exp $
19
19
*
20
20
*-------------------------------------------------------------------------
21
21
*/
27
27
#include "nodes/makefuncs.h"
28
28
#include "optimizer/prep.h"
29
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
30
36
31
37
32
static List * expand_targetlist (List * tlist , int command_type ,
38
33
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
34
44
35
45
36
/*
@@ -119,31 +110,25 @@ preprocess_targetlist(List *tlist,
119
110
/*
120
111
* expand_targetlist
121
112
* 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.
113
+ * add targetlist entries for any missing attributes, and ensure the
114
+ * non-junk attributes appear in proper field order.
115
+ *
116
+ * NOTE: if you are tempted to put more processing here, consider whether
117
+ * it shouldn't go in the rewriter's rewriteTargetList() instead.
124
118
*/
125
119
static List *
126
120
expand_targetlist (List * tlist , int command_type ,
127
121
Index result_relation , List * range_table )
128
122
{
129
- int old_tlist_len = length (tlist );
130
123
List * new_tlist = NIL ;
131
- bool * tlistentry_used ;
132
124
Relation rel ;
133
125
int attrno ,
134
- numattrs ,
135
- old_tlist_index ;
136
- List * temp ;
126
+ numattrs ;
137
127
138
128
/*
139
- * Keep a map of which tlist items we have transferred to new list.
129
+ * The rewriter should have already ensured that the TLEs are in
130
+ * correct order; but we have to insert TLEs for any missing attributes.
140
131
*
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
132
* Scan the tuple description in the relation's relcache entry to make
148
133
* sure we have all the user attributes in the right order.
149
134
*/
@@ -154,36 +139,29 @@ expand_targetlist(List *tlist, int command_type,
154
139
for (attrno = 1 ; attrno <= numattrs ; attrno ++ )
155
140
{
156
141
Form_pg_attribute att_tup = rel -> rd_att -> attrs [attrno - 1 ];
157
- char * attrname = NameStr (att_tup -> attname );
158
142
TargetEntry * new_tle = NULL ;
159
143
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 )
144
+ if (tlist != NIL )
166
145
{
167
- TargetEntry * old_tle = (TargetEntry * ) lfirst (temp );
146
+ TargetEntry * old_tle = (TargetEntry * ) lfirst (tlist );
168
147
Resdom * resdom = old_tle -> resdom ;
169
148
170
- if (!tlistentry_used [old_tlist_index ] &&
171
- !resdom -> resjunk &&
172
- strcmp (resdom -> resname , attrname ) == 0 )
149
+ if (!resdom -> resjunk && resdom -> resno == attrno )
173
150
{
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 */
151
+ Assert (strcmp (resdom -> resname ,
152
+ NameStr (att_tup -> attname )) == 0 );
153
+ new_tle = old_tle ;
154
+ tlist = lnext (tlist );
177
155
}
178
- old_tlist_index ++ ;
179
156
}
180
157
181
158
if (new_tle == NULL )
182
159
{
183
160
/*
184
161
* Didn't find a matching tlist entry, so make one.
185
162
*
186
- * For INSERT, generate an appropriate default value.
163
+ * For INSERT, generate a NULL constant. (We assume the
164
+ * rewriter would have inserted any available default value.)
187
165
*
188
166
* For UPDATE, generate a Var reference to the existing value of
189
167
* the attribute, so that it gets copied to the new tuple.
@@ -195,14 +173,20 @@ expand_targetlist(List *tlist, int command_type,
195
173
switch (command_type )
196
174
{
197
175
case CMD_INSERT :
198
- new_expr = build_column_default (rel , attrno );
176
+ new_expr = (Node * ) makeConst (atttype ,
177
+ att_tup -> attlen ,
178
+ (Datum ) 0 ,
179
+ true, /* isnull */
180
+ att_tup -> attbyval ,
181
+ false, /* not a set */
182
+ false);
199
183
break ;
200
184
case CMD_UPDATE :
201
- new_expr = (Node * ) makeVar (result_relation ,
202
- attrno ,
203
- atttype ,
204
- atttypmod ,
205
- 0 );
185
+ new_expr = (Node * ) makeVar (result_relation ,
186
+ attrno ,
187
+ atttype ,
188
+ atttypmod ,
189
+ 0 );
206
190
break ;
207
191
default :
208
192
elog (ERROR , "expand_targetlist: unexpected command_type" );
@@ -213,7 +197,7 @@ expand_targetlist(List *tlist, int command_type,
213
197
new_tle = makeTargetEntry (makeResdom (attrno ,
214
198
atttype ,
215
199
atttypmod ,
216
- pstrdup (attrname ),
200
+ pstrdup (NameStr ( att_tup -> attname ) ),
217
201
false),
218
202
new_expr );
219
203
}
@@ -222,230 +206,32 @@ expand_targetlist(List *tlist, int command_type,
222
206
}
223
207
224
208
/*
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.
209
+ * The remaining tlist entries should be resjunk; append them all to
210
+ * the end of the new tlist, making sure they have resnos higher than
211
+ * the last real attribute. (Note: although the rewriter already did
212
+ * such renumbering, we have to do it again here in case we are doing
213
+ * an UPDATE in an inheritance child table with more columns.)
230
214
*/
231
- old_tlist_index = 0 ;
232
- foreach (temp , tlist )
215
+ while (tlist )
233
216
{
234
- TargetEntry * old_tle = (TargetEntry * ) lfirst (temp );
217
+ TargetEntry * old_tle = (TargetEntry * ) lfirst (tlist );
218
+ Resdom * resdom = old_tle -> resdom ;
235
219
236
- if (!tlistentry_used [old_tlist_index ])
220
+ if (!resdom -> resjunk )
221
+ elog (ERROR , "expand_targetlist: targetlist is not sorted correctly" );
222
+ /* Get the resno right, but don't copy unnecessarily */
223
+ if (resdom -> resno != attrno )
237
224
{
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 ++ ;
225
+ resdom = (Resdom * ) copyObject ((Node * ) resdom );
226
+ resdom -> resno = attrno ;
227
+ old_tle = makeTargetEntry (resdom , old_tle -> expr );
252
228
}
253
- old_tlist_index ++ ;
229
+ new_tlist = lappend (new_tlist , old_tle );
230
+ attrno ++ ;
231
+ tlist = lnext (tlist );
254
232
}
255
233
256
234
heap_close (rel , AccessShareLock );
257
235
258
- pfree (tlistentry_used );
259
-
260
236
return new_tlist ;
261
237
}
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
- }
0 commit comments