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

Commita5a1288

Browse files
committed
Make update lists like 'UPDATE tab SET foo[1] = bar, foo[3] = baz'
work as expected. THe underlying implementation is essentially'SET foo = array_set(foo, 1, bar)', so we have to turn the itemsinto nested invocations of array_set() to make it work correctly.Side effect: we now complain about 'UPDATE tab SET foo = bar, foo = baz'which is illegal per SQL92 but we didn't detect it before.
1 parent2019e24 commita5a1288

File tree

1 file changed

+101
-49
lines changed

1 file changed

+101
-49
lines changed

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

Lines changed: 101 additions & 49 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.36 2000/04/12 17:15:23 momjian Exp $
18+
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.37 2000/07/22 06:19:04 tgl Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -32,6 +32,9 @@
3232

3333
staticList*expand_targetlist(List*tlist,intcommand_type,
3434
Indexresult_relation,List*range_table);
35+
staticTargetEntry*process_matched_tle(TargetEntry*src_tle,
36+
TargetEntry*prior_tle,
37+
intattrno);
3538

3639

3740
/*
@@ -119,8 +122,9 @@ expand_targetlist(List *tlist, int command_type,
119122
List*temp;
120123

121124
/*
122-
* Keep a map of which tlist items we have transferred to new list. +1
123-
* here keeps palloc from complaining if old_tlist_len=0.
125+
* Keep a map of which tlist items we have transferred to new list.
126+
*
127+
* +1 here just keeps palloc from complaining if old_tlist_len==0.
124128
*/
125129
tlistentry_used= (bool*)palloc((old_tlist_len+1)*sizeof(bool));
126130
memset(tlistentry_used,0, (old_tlist_len+1)*sizeof(bool));
@@ -141,6 +145,7 @@ expand_targetlist(List *tlist, int command_type,
141145

142146
/*
143147
* We match targetlist entries to attributes using the resname.
148+
* Junk attributes are not candidates to be matched.
144149
*/
145150
old_tlist_index=0;
146151
foreach(temp,tlist)
@@ -149,26 +154,11 @@ expand_targetlist(List *tlist, int command_type,
149154
Resdom*resdom=old_tle->resdom;
150155

151156
if (!tlistentry_used[old_tlist_index]&&
152-
strcmp(resdom->resname,attrname)==0&&
153-
!resdom->resjunk)
157+
!resdom->resjunk&&
158+
strcmp(resdom->resname,attrname)==0)
154159
{
155-
156-
/*
157-
* We can recycle the old TLE+resdom if right resno; else
158-
* make a new one to avoid modifying the old tlist
159-
* structure. (Is preserving old tlist actually
160-
* necessary?)
161-
*/
162-
if (resdom->resno==attrno)
163-
new_tle=old_tle;
164-
else
165-
{
166-
resdom= (Resdom*)copyObject((Node*)resdom);
167-
resdom->resno=attrno;
168-
new_tle=makeTargetEntry(resdom,old_tle->expr);
169-
}
160+
new_tle=process_matched_tle(old_tle,new_tle,attrno);
170161
tlistentry_used[old_tlist_index]= true;
171-
break;
172162
}
173163
old_tlist_index++;
174164
}
@@ -192,22 +182,15 @@ expand_targetlist(List *tlist, int command_type,
192182
{
193183
caseCMD_INSERT:
194184
{
195-
#ifdef_DROP_COLUMN_HACK__
196-
Datumtypedefault;
197-
198-
#else
199185
Datumtypedefault=get_typdefault(atttype);
200-
201-
#endif/* _DROP_COLUMN_HACK__ */
202186
inttyplen;
203187
Const*temp_const;
204188

205189
#ifdef_DROP_COLUMN_HACK__
206190
if (COLUMN_IS_DROPPED(att_tup))
207191
typedefault=PointerGetDatum(NULL);
208-
else
209-
typedefault=get_typdefault(atttype);
210192
#endif/* _DROP_COLUMN_HACK__ */
193+
211194
if (typedefault==PointerGetDatum(NULL))
212195
typlen=0;
213196
else
@@ -247,11 +230,9 @@ expand_targetlist(List *tlist, int command_type,
247230
Var*temp_var;
248231

249232
#ifdef_DROP_COLUMN_HACK__
250-
Node*temp_node= (Node*)NULL;
251-
252233
if (COLUMN_IS_DROPPED(att_tup))
253234
{
254-
temp_node= (Node*)makeConst(atttype,0,
235+
temp_var= (Var*)makeConst(atttype,0,
255236
PointerGetDatum(NULL),
256237
true,
257238
false,
@@ -260,25 +241,20 @@ expand_targetlist(List *tlist, int command_type,
260241
}
261242
else
262243
#endif/* _DROP_COLUMN_HACK__ */
263-
temp_var=makeVar(result_relation,attrno,atttype,
264-
atttypmod,0);
265-
#ifdef_DROP_COLUMN_HACK__
266-
if (!temp_node)
267-
temp_node= (Node*)temp_var;
268-
#endif/* _DROP_COLUMN_HACK__ */
244+
temp_var=makeVar(result_relation,
245+
attrno,
246+
atttype,
247+
atttypmod,
248+
0);
269249

270250
new_tle=makeTargetEntry(makeResdom(attrno,
271251
atttype,
272252
atttypmod,
273-
pstrdup(attrname),
253+
pstrdup(attrname),
274254
0,
275255
(Oid)0,
276256
false),
277-
#ifdef_DROP_COLUMN_HACK__
278-
temp_node);
279-
#else
280257
(Node*)temp_var);
281-
#endif/* _DROP_COLUMN_HACK__ */
282258
break;
283259
}
284260
default:
@@ -304,13 +280,20 @@ expand_targetlist(List *tlist, int command_type,
304280

305281
if (!tlistentry_used[old_tlist_index])
306282
{
307-
Resdom*resdom;
283+
Resdom*resdom=old_tle->resdom;
308284

309-
resdom= (Resdom*)copyObject((Node*)old_tle->resdom);
310-
resdom->resno=attrno++;
311-
resdom->resjunk= true;
312-
new_tlist=lappend(new_tlist,
313-
makeTargetEntry(resdom,old_tle->expr));
285+
if (!resdom->resjunk)
286+
elog(ERROR,"Unexpected assignment to attribute \"%s\"",
287+
resdom->resname);
288+
/* Get the resno right, but don't copy unnecessarily */
289+
if (resdom->resno!=attrno)
290+
{
291+
resdom= (Resdom*)copyObject((Node*)resdom);
292+
resdom->resno=attrno;
293+
old_tle=makeTargetEntry(resdom,old_tle->expr);
294+
}
295+
new_tlist=lappend(new_tlist,old_tle);
296+
attrno++;
314297
}
315298
old_tlist_index++;
316299
}
@@ -321,3 +304,72 @@ expand_targetlist(List *tlist, int command_type,
321304

322305
returnnew_tlist;
323306
}
307+
308+
309+
/*
310+
* Convert a matched TLE from the original tlist into a correct new TLE.
311+
*
312+
* This routine checks for multiple assignments to the same target attribute,
313+
* such as "UPDATE table SET foo = 42, foo = 43". This is OK only if they
314+
* are array assignments, ie, "UPDATE table SET foo[2] = 42, foo[4] = 43".
315+
* If so, we need to merge the operations into a single assignment op.
316+
* Essentially, the expression we want to produce in this case is like
317+
*foo = array_set(array_set(foo, 2, 42), 4, 43)
318+
*/
319+
staticTargetEntry*process_matched_tle(TargetEntry*src_tle,
320+
TargetEntry*prior_tle,
321+
intattrno)
322+
{
323+
Resdom*resdom=src_tle->resdom;
324+
Node*priorbottom;
325+
ArrayRef*newexpr;
326+
327+
if (prior_tle==NULL)
328+
{
329+
/*
330+
* Normal case where this is the first assignment to the attribute.
331+
*
332+
* We can recycle the old TLE+resdom if right resno; else make a
333+
* new one to avoid modifying the old tlist structure. (Is preserving
334+
* old tlist actually necessary? Not sure, be safe.)
335+
*/
336+
if (resdom->resno==attrno)
337+
returnsrc_tle;
338+
resdom= (Resdom*)copyObject((Node*)resdom);
339+
resdom->resno=attrno;
340+
returnmakeTargetEntry(resdom,src_tle->expr);
341+
}
342+
343+
/*
344+
* Multiple assignments to same attribute. Allow only if all are
345+
* array-assign operators with same bottom array object.
346+
*/
347+
if (src_tle->expr==NULL|| !IsA(src_tle->expr,ArrayRef)||
348+
((ArrayRef*)src_tle->expr)->refassgnexpr==NULL||
349+
prior_tle->expr==NULL|| !IsA(prior_tle->expr,ArrayRef)||
350+
((ArrayRef*)prior_tle->expr)->refassgnexpr==NULL||
351+
((ArrayRef*)src_tle->expr)->refelemtype!=
352+
((ArrayRef*)prior_tle->expr)->refelemtype)
353+
elog(ERROR,"Multiple assignments to same attribute \"%s\"",
354+
resdom->resname);
355+
/*
356+
* Prior TLE could be a nest of ArrayRefs if we do this more than once.
357+
*/
358+
priorbottom= ((ArrayRef*)prior_tle->expr)->refexpr;
359+
while (priorbottom!=NULL&&IsA(priorbottom,ArrayRef)&&
360+
((ArrayRef*)priorbottom)->refassgnexpr!=NULL)
361+
priorbottom= ((ArrayRef*)priorbottom)->refexpr;
362+
if (!equal(priorbottom, ((ArrayRef*)src_tle->expr)->refexpr))
363+
elog(ERROR,"Multiple assignments to same attribute \"%s\"",
364+
resdom->resname);
365+
/*
366+
* Looks OK to nest 'em.
367+
*/
368+
newexpr=makeNode(ArrayRef);
369+
memcpy(newexpr,src_tle->expr,sizeof(ArrayRef));
370+
newexpr->refexpr=prior_tle->expr;
371+
372+
resdom= (Resdom*)copyObject((Node*)resdom);
373+
resdom->resno=attrno;
374+
returnmakeTargetEntry(resdom, (Node*)newexpr);
375+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp