Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9685afb

Browse files
committed
Add default expressions to INSERTs during planning, not during parse
analysis. This keeps stored rules from prematurely absorbing default information, which is necessary for ALTER TABLE SET DEFAULT to work unsurprisingly with rules. See pgsql-bugs discussion 24-Oct-01.
1 parent a9b6691 commit 9685afb

File tree

3 files changed

+161
-135
lines changed

3 files changed

+161
-135
lines changed

src/backend/catalog/heap.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.179 2001/10/25 05:49:22 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.180 2001/11/02 20:23:02 tgl Exp $
1212
*
1313
*
1414
* INTERFACE ROUTINES
@@ -1651,9 +1651,9 @@ AddRelationRawConstraints(Relation rel,
16511651
* column's type. We store the expression without coercion,
16521652
* however, to avoid premature coercion in cases like
16531653
*
1654-
* CREATE TABLE tbl (fld datetime DEFAULT 'now');
1654+
* CREATE TABLE tbl (fld datetime DEFAULT 'now'::text);
16551655
*
1656-
* NB: this should match the code in updateTargetListEntry() that
1656+
* NB: this should match the code in optimizer/prep/preptlist.c that
16571657
* will actually do the coercion, to ensure we don't accept an
16581658
* unusable default expression.
16591659
*/

src/backend/optimizer/prep/preptlist.c

+154-75
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* Portions Copyright (c) 1994, Regents of the University of California
1616
*
1717
* 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 $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -27,6 +27,10 @@
2727
#include "nodes/makefuncs.h"
2828
#include "optimizer/prep.h"
2929
#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"
3034
#include "utils/lsyscache.h"
3135

3236

@@ -35,6 +39,7 @@ static List *expand_targetlist(List *tlist, int command_type,
3539
static TargetEntry *process_matched_tle(TargetEntry *src_tle,
3640
TargetEntry *prior_tle,
3741
int attrno);
42+
static Node *build_column_default(Relation rel, int attrno);
3843

3944

4045
/*
@@ -168,6 +173,7 @@ expand_targetlist(List *tlist, int command_type,
168173
{
169174
new_tle = process_matched_tle(old_tle, new_tle, attrno);
170175
tlistentry_used[old_tlist_index] = true;
176+
/* keep scanning to detect multiple assignments to attr */
171177
}
172178
old_tlist_index++;
173179
}
@@ -177,97 +183,44 @@ expand_targetlist(List *tlist, int command_type,
177183
/*
178184
* Didn't find a matching tlist entry, so make one.
179185
*
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.
182187
*
183188
* For UPDATE, generate a Var reference to the existing value of
184189
* the attribute, so that it gets copied to the new tuple.
185190
*/
186191
Oid atttype = att_tup->atttypid;
187192
int32 atttypmod = att_tup->atttypmod;
193+
Node *new_expr;
188194

189195
switch (command_type)
190196
{
191197
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;
244200
case CMD_UPDATE:
245-
{
246-
Var *temp_var;
247-
248201
#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
252205
#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;
267212
default:
268213
elog(ERROR, "expand_targetlist: unexpected command_type");
214+
new_expr = NULL; /* keep compiler quiet */
269215
break;
270216
}
217+
218+
new_tle = makeTargetEntry(makeResdom(attrno,
219+
atttype,
220+
atttypmod,
221+
pstrdup(attrname),
222+
false),
223+
new_expr);
271224
}
272225

273226
new_tlist = lappend(new_tlist, new_tle);
@@ -385,3 +338,129 @@ process_matched_tle(TargetEntry *src_tle,
385338
resdom->resno = attrno;
386339
return makeTargetEntry(resdom, (Node *) newexpr);
387340
}
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

Comments
 (0)