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.44 2001/10/25 05:49:33 momjian Exp $
18
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.45 2001/11/02 20:23:02 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"
30
34
#include "utils/lsyscache.h"
31
35
32
36
@@ -35,6 +39,7 @@ static List *expand_targetlist(List *tlist, int command_type,
35
39
static TargetEntry * process_matched_tle (TargetEntry * src_tle ,
36
40
TargetEntry * prior_tle ,
37
41
int attrno );
42
+ static Node * build_column_default (Relation rel , int attrno );
38
43
39
44
40
45
/*
@@ -168,6 +173,7 @@ expand_targetlist(List *tlist, int command_type,
168
173
{
169
174
new_tle = process_matched_tle (old_tle , new_tle , attrno );
170
175
tlistentry_used [old_tlist_index ] = true;
176
+ /* keep scanning to detect multiple assignments to attr */
171
177
}
172
178
old_tlist_index ++ ;
173
179
}
@@ -177,97 +183,44 @@ expand_targetlist(List *tlist, int command_type,
177
183
/*
178
184
* Didn't find a matching tlist entry, so make one.
179
185
*
180
- * For INSERT, generate a constant of the default value for the
181
- * attribute type, or NULL if no default value.
186
+ * For INSERT, generate an appropriate default value.
182
187
*
183
188
* For UPDATE, generate a Var reference to the existing value of
184
189
* the attribute, so that it gets copied to the new tuple.
185
190
*/
186
191
Oid atttype = att_tup -> atttypid ;
187
192
int32 atttypmod = att_tup -> atttypmod ;
193
+ Node * new_expr ;
188
194
189
195
switch (command_type )
190
196
{
191
197
case CMD_INSERT :
192
- {
193
- bool hasdefault ;
194
- Datum typedefault ;
195
- int16 typlen ;
196
- bool typbyval ;
197
- Const * def_const ;
198
-
199
- if (att_tup -> attisset )
200
- {
201
- /*
202
- * Set attributes are represented as OIDs no
203
- * matter what the set element type is, and
204
- * the element type's default is irrelevant
205
- * too.
206
- */
207
- hasdefault = false;
208
- typedefault = (Datum ) 0 ;
209
- typlen = sizeof (Oid );
210
- typbyval = true;
211
- }
212
- else
213
- {
214
- #ifdef _DROP_COLUMN_HACK__
215
- if (COLUMN_IS_DROPPED (att_tup ))
216
- {
217
- hasdefault = false;
218
- typedefault = (Datum ) 0 ;
219
- }
220
- else
221
- #endif /* _DROP_COLUMN_HACK__ */
222
- hasdefault = get_typdefault (atttype ,
223
- & typedefault );
224
-
225
- get_typlenbyval (atttype , & typlen , & typbyval );
226
- }
227
-
228
- def_const = makeConst (atttype ,
229
- typlen ,
230
- typedefault ,
231
- !hasdefault ,
232
- typbyval ,
233
- false, /* not a set */
234
- false);
235
-
236
- new_tle = makeTargetEntry (makeResdom (attrno ,
237
- atttype ,
238
- -1 ,
239
- pstrdup (attrname ),
240
- false),
241
- (Node * ) def_const );
242
- break ;
243
- }
198
+ new_expr = build_column_default (rel , attrno );
199
+ break ;
244
200
case CMD_UPDATE :
245
- {
246
- Var * temp_var ;
247
-
248
201
#ifdef _DROP_COLUMN_HACK__
249
- if (COLUMN_IS_DROPPED (att_tup ))
250
- temp_var = (Var * ) makeNullConst (atttype );
251
- else
202
+ if (COLUMN_IS_DROPPED (att_tup ))
203
+ new_expr = (Node * ) makeNullConst (atttype );
204
+ else
252
205
#endif /* _DROP_COLUMN_HACK__ */
253
- temp_var = makeVar (result_relation ,
254
- attrno ,
255
- atttype ,
256
- atttypmod ,
257
- 0 );
258
-
259
- new_tle = makeTargetEntry (makeResdom (attrno ,
260
- atttype ,
261
- atttypmod ,
262
- pstrdup (attrname ),
263
- false),
264
- (Node * ) temp_var );
265
- break ;
266
- }
206
+ new_expr = (Node * ) makeVar (result_relation ,
207
+ attrno ,
208
+ atttype ,
209
+ atttypmod ,
210
+ 0 );
211
+ break ;
267
212
default :
268
213
elog (ERROR , "expand_targetlist: unexpected command_type" );
214
+ new_expr = NULL ; /* keep compiler quiet */
269
215
break ;
270
216
}
217
+
218
+ new_tle = makeTargetEntry (makeResdom (attrno ,
219
+ atttype ,
220
+ atttypmod ,
221
+ pstrdup (attrname ),
222
+ false),
223
+ new_expr );
271
224
}
272
225
273
226
new_tlist = lappend (new_tlist , new_tle );
@@ -385,3 +338,129 @@ process_matched_tle(TargetEntry *src_tle,
385
338
resdom -> resno = attrno ;
386
339
return makeTargetEntry (resdom , (Node * ) newexpr );
387
340
}
341
+
342
+
343
+ /*
344
+ * Make an expression tree for the default value for a column.
345
+ *
346
+ * This is used to fill in missing attributes in an INSERT targetlist.
347
+ * We look first to see if the column has a default value expression.
348
+ * If not, generate a constant of the default value for the attribute type,
349
+ * or a NULL if the type has no default value either.
350
+ */
351
+ static Node *
352
+ build_column_default (Relation rel , int attrno )
353
+ {
354
+ TupleDesc rd_att = rel -> rd_att ;
355
+ Form_pg_attribute att_tup = rd_att -> attrs [attrno - 1 ];
356
+ Oid atttype = att_tup -> atttypid ;
357
+ int32 atttypmod = att_tup -> atttypmod ;
358
+ bool hasdefault ;
359
+ Datum typedefault ;
360
+ int16 typlen ;
361
+ bool typbyval ;
362
+ Node * expr ;
363
+
364
+ /*
365
+ * Scan to see if relation has a default for this column.
366
+ */
367
+ if (rd_att -> constr && rd_att -> constr -> num_defval > 0 )
368
+ {
369
+ AttrDefault * defval = rd_att -> constr -> defval ;
370
+ int ndef = rd_att -> constr -> num_defval ;
371
+
372
+ while (-- ndef >= 0 )
373
+ {
374
+ if (attrno == defval [ndef ].adnum )
375
+ {
376
+ Oid type_id ;
377
+
378
+ /*
379
+ * Found it, convert string representation to node tree.
380
+ */
381
+ expr = stringToNode (defval [ndef ].adbin );
382
+
383
+ /*
384
+ * Make sure the value is coerced to the target column type
385
+ * (might not be right type yet if it's not a constant!)
386
+ * This should match the parser's processing of non-defaulted
387
+ * expressions --- see updateTargetListEntry().
388
+ */
389
+ type_id = exprType (expr );
390
+
391
+ if (type_id != atttype )
392
+ {
393
+ expr = CoerceTargetExpr (NULL , expr , type_id ,
394
+ atttype , atttypmod );
395
+ /*
396
+ * This really shouldn't fail; should have checked the
397
+ * default's type when it was created ...
398
+ */
399
+ if (expr == NULL )
400
+ elog (ERROR , "Column \"%s\" is of type %s"
401
+ " but default expression is of type %s"
402
+ "\n\tYou will need to rewrite or cast the expression" ,
403
+ NameStr (att_tup -> attname ),
404
+ format_type_be (atttype ),
405
+ format_type_be (type_id ));
406
+ }
407
+
408
+ /*
409
+ * If the column is a fixed-length type, it may need a
410
+ * length coercion as well as a type coercion.
411
+ */
412
+ expr = coerce_type_typmod (NULL , expr ,
413
+ atttype , atttypmod );
414
+ return expr ;
415
+ }
416
+ }
417
+ }
418
+
419
+ /*
420
+ * No per-column default, so look for a default for the type itself.
421
+ * If there isn't one, we generate a NULL constant of the correct type.
422
+ */
423
+ if (att_tup -> attisset )
424
+ {
425
+ /*
426
+ * Set attributes are represented as OIDs no matter what the set
427
+ * element type is, and the element type's default is irrelevant too.
428
+ */
429
+ hasdefault = false;
430
+ typedefault = (Datum ) 0 ;
431
+ typlen = sizeof (Oid );
432
+ typbyval = true;
433
+ }
434
+ else
435
+ {
436
+ #ifdef _DROP_COLUMN_HACK__
437
+ if (COLUMN_IS_DROPPED (att_tup ))
438
+ {
439
+ hasdefault = false;
440
+ typedefault = (Datum ) 0 ;
441
+ }
442
+ else
443
+ #endif /* _DROP_COLUMN_HACK__ */
444
+ hasdefault = get_typdefault (atttype , & typedefault );
445
+
446
+ get_typlenbyval (atttype , & typlen , & typbyval );
447
+ }
448
+
449
+ expr = (Node * ) makeConst (atttype ,
450
+ typlen ,
451
+ typedefault ,
452
+ !hasdefault ,
453
+ typbyval ,
454
+ false, /* not a set */
455
+ false);
456
+
457
+ /*
458
+ * If the column is a fixed-length type, it may need a length coercion
459
+ * as well as a type coercion. But NULLs don't need that.
460
+ */
461
+ if (hasdefault )
462
+ expr = coerce_type_typmod (NULL , expr ,
463
+ atttype , atttypmod );
464
+
465
+ return expr ;
466
+ }
0 commit comments