Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb9ae55f

Browse files
committed
Undo not-so-hot decision to postpone insertion of default values into
INSERT statements to the planner. Taking it out of the parser was right(so that defaults don't get into stored rules), but it has to happenbefore rewrite rule expansion, else references to NEW.field behaveincorrectly. Accordingly, add a step to the rewriter to insert defaultsjust before rewrite-rule expansion.
1 parentc9d70e2 commitb9ae55f

File tree

2 files changed

+348
-265
lines changed

2 files changed

+348
-265
lines changed

‎src/backend/optimizer/prep/preptlist.c

Lines changed: 49 additions & 263 deletions
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.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 $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -27,19 +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"
34-
#include"utils/lsyscache.h"
3530

3631

3732
staticList*expand_targetlist(List*tlist,intcommand_type,
3833
Indexresult_relation,List*range_table);
39-
staticTargetEntry*process_matched_tle(TargetEntry*src_tle,
40-
TargetEntry*prior_tle,
41-
intattrno);
42-
staticNode*build_column_default(Relationrel,intattrno);
4334

4435

4536
/*
@@ -119,31 +110,25 @@ preprocess_targetlist(List *tlist,
119110
/*
120111
* expand_targetlist
121112
* 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.
124118
*/
125119
staticList*
126120
expand_targetlist(List*tlist,intcommand_type,
127121
Indexresult_relation,List*range_table)
128122
{
129-
intold_tlist_len=length(tlist);
130123
List*new_tlist=NIL;
131-
bool*tlistentry_used;
132124
Relationrel;
133125
intattrno,
134-
numattrs,
135-
old_tlist_index;
136-
List*temp;
126+
numattrs;
137127

138128
/*
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.
140131
*
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-
/*
147132
* Scan the tuple description in the relation's relcache entry to make
148133
* sure we have all the user attributes in the right order.
149134
*/
@@ -154,36 +139,29 @@ expand_targetlist(List *tlist, int command_type,
154139
for (attrno=1;attrno <=numattrs;attrno++)
155140
{
156141
Form_pg_attributeatt_tup=rel->rd_att->attrs[attrno-1];
157-
char*attrname=NameStr(att_tup->attname);
158142
TargetEntry*new_tle=NULL;
159143

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)
166145
{
167-
TargetEntry*old_tle= (TargetEntry*)lfirst(temp);
146+
TargetEntry*old_tle= (TargetEntry*)lfirst(tlist);
168147
Resdom*resdom=old_tle->resdom;
169148

170-
if (!tlistentry_used[old_tlist_index]&&
171-
!resdom->resjunk&&
172-
strcmp(resdom->resname,attrname)==0)
149+
if (!resdom->resjunk&&resdom->resno==attrno)
173150
{
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);
177155
}
178-
old_tlist_index++;
179156
}
180157

181158
if (new_tle==NULL)
182159
{
183160
/*
184161
* Didn't find a matching tlist entry, so make one.
185162
*
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.)
187165
*
188166
* For UPDATE, generate a Var reference to the existing value of
189167
* the attribute, so that it gets copied to the new tuple.
@@ -195,14 +173,20 @@ expand_targetlist(List *tlist, int command_type,
195173
switch (command_type)
196174
{
197175
caseCMD_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);
199183
break;
200184
caseCMD_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);
206190
break;
207191
default:
208192
elog(ERROR,"expand_targetlist: unexpected command_type");
@@ -213,7 +197,7 @@ expand_targetlist(List *tlist, int command_type,
213197
new_tle=makeTargetEntry(makeResdom(attrno,
214198
atttype,
215199
atttypmod,
216-
pstrdup(attrname),
200+
pstrdup(NameStr(att_tup->attname)),
217201
false),
218202
new_expr);
219203
}
@@ -222,230 +206,32 @@ expand_targetlist(List *tlist, int command_type,
222206
}
223207

224208
/*
225-
*Copy all unprocessedtlist entriesto 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 remainingtlist entriesshould 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.)
230214
*/
231-
old_tlist_index=0;
232-
foreach(temp,tlist)
215+
while (tlist)
233216
{
234-
TargetEntry*old_tle= (TargetEntry*)lfirst(temp);
217+
TargetEntry*old_tle= (TargetEntry*)lfirst(tlist);
218+
Resdom*resdom=old_tle->resdom;
235219

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)
237224
{
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);
252228
}
253-
old_tlist_index++;
229+
new_tlist=lappend(new_tlist,old_tle);
230+
attrno++;
231+
tlist=lnext(tlist);
254232
}
255233

256234
heap_close(rel,AccessShareLock);
257235

258-
pfree(tlistentry_used);
259-
260236
returnnew_tlist;
261237
}
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-
staticTargetEntry*
275-
process_matched_tle(TargetEntry*src_tle,
276-
TargetEntry*prior_tle,
277-
intattrno)
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-
returnsrc_tle;
295-
resdom= (Resdom*)copyObject((Node*)resdom);
296-
resdom->resno=attrno;
297-
returnmakeTargetEntry(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-
returnmakeTargetEntry(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-
staticNode*
347-
build_column_default(Relationrel,intattrno)
348-
{
349-
TupleDescrd_att=rel->rd_att;
350-
Form_pg_attributeatt_tup=rd_att->attrs[attrno-1];
351-
Oidatttype=att_tup->atttypid;
352-
int32atttypmod=att_tup->atttypmod;
353-
int16typlen=att_tup->attlen;
354-
booltypbyval=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-
intndef=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-
Oidexprtype;
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-
returnexpr;
451-
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp