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

Commit71db302

Browse files
committed
Prevent multicolumn expansion of "foo.*" in an UPDATE source expression.
Because we use transformTargetList() for UPDATE as well as SELECTtlists, the code accidentally tried to expand a "*" reference intoseveral columns. This is nonsensical, because the UPDATE syntaxprovides exactly one target column to put the value into. Theimmediate result was that transformUpdateTargetList() got confusedand reported "UPDATE target count mismatch --- internal error".It seems better to treat such a reference as a plain whole-rowvariable, as it would be in other contexts. (This could produceuseful results when the target column is of composite type.)Fix by tweaking transformTargetList() to perform *-expansion onlyconditionally, depending on its exprKind parameter.Back-patch to 9.3. The problem exists further back, but a fix would bemuch more invasive before that, because transformTargetList() wasn'ttold what kind of list it was working on. Doesn't seem worth thetrouble given the lack of field reports. (I only noticed it becauseI was checking the code while trying to improve the documentation abouthow we handle "foo.*".)Discussion: <4308.1479595330@sss.pgh.pa.us>
1 parent46b6f3f commit71db302

File tree

3 files changed

+46
-24
lines changed

3 files changed

+46
-24
lines changed

‎src/backend/parser/parse_target.c

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,21 @@ transformTargetEntry(ParseState *pstate,
113113
* transformTargetList()
114114
* Turns a list of ResTarget's into a list of TargetEntry's.
115115
*
116-
*At this point, we don't care whether we are doingSELECT, UPDATE,
117-
*or RETURNING; we just transform the given expressions (the "val" fields).
118-
*However, our subroutines care, so we need the exprKind parameter.
116+
*This code acts mostly the same forSELECT, UPDATE, or RETURNING lists;
117+
*the main thing is to transform the given expressions (the "val" fields).
118+
*The exprKind parameter distinguishes these cases when necessary.
119119
*/
120120
List*
121121
transformTargetList(ParseState*pstate,List*targetlist,
122122
ParseExprKindexprKind)
123123
{
124124
List*p_target=NIL;
125+
boolexpand_star;
125126
ListCell*o_target;
126127

128+
/* Expand "something.*" in SELECT and RETURNING, but not UPDATE */
129+
expand_star= (exprKind!=EXPR_KIND_UPDATE_SOURCE);
130+
127131
foreach(o_target,targetlist)
128132
{
129133
ResTarget*res= (ResTarget*)lfirst(o_target);
@@ -133,35 +137,42 @@ transformTargetList(ParseState *pstate, List *targetlist,
133137
* "something", the star could appear as the last field in ColumnRef,
134138
* or as the last indirection item in A_Indirection.
135139
*/
136-
if (IsA(res->val,ColumnRef))
140+
if (expand_star)
137141
{
138-
ColumnRef*cref= (ColumnRef*)res->val;
139-
140-
if (IsA(llast(cref->fields),A_Star))
142+
if (IsA(res->val,ColumnRef))
141143
{
142-
/* It is something.*, expand into multiple items */
143-
p_target=list_concat(p_target,
144-
ExpandColumnRefStar(pstate,cref,
145-
true));
146-
continue;
147-
}
148-
}
149-
elseif (IsA(res->val,A_Indirection))
150-
{
151-
A_Indirection*ind= (A_Indirection*)res->val;
144+
ColumnRef*cref= (ColumnRef*)res->val;
152145

153-
if (IsA(llast(ind->indirection),A_Star))
146+
if (IsA(llast(cref->fields),A_Star))
147+
{
148+
/* It is something.*, expand into multiple items */
149+
p_target=list_concat(p_target,
150+
ExpandColumnRefStar(pstate,
151+
cref,
152+
true));
153+
continue;
154+
}
155+
}
156+
elseif (IsA(res->val,A_Indirection))
154157
{
155-
/* It is something.*, expand into multiple items */
156-
p_target=list_concat(p_target,
157-
ExpandIndirectionStar(pstate,ind,
158-
true,exprKind));
159-
continue;
158+
A_Indirection*ind= (A_Indirection*)res->val;
159+
160+
if (IsA(llast(ind->indirection),A_Star))
161+
{
162+
/* It is something.*, expand into multiple items */
163+
p_target=list_concat(p_target,
164+
ExpandIndirectionStar(pstate,
165+
ind,
166+
true,
167+
exprKind));
168+
continue;
169+
}
160170
}
161171
}
162172

163173
/*
164-
* Not "something.*", so transform as a single expression
174+
* Not "something.*", or we want to treat that as a plain whole-row
175+
* variable, so transform as a single expression
165176
*/
166177
p_target=lappend(p_target,
167178
transformTargetEntry(pstate,

‎src/test/regress/expected/update.out

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ SELECT * FROM update_test;
5252
100 | 20 |
5353
(2 rows)
5454

55+
-- fail, wrong data type:
56+
UPDATE update_test SET a = v.* FROM (VALUES(100, 20)) AS v(i, j)
57+
WHERE update_test.b = v.j;
58+
ERROR: column "a" is of type integer but expression is of type record
59+
LINE 1: UPDATE update_test SET a = v.* FROM (VALUES(100, 20)) AS v(i...
60+
^
61+
HINT: You will need to rewrite or cast the expression.
5562
--
5663
-- Test multiple-set-clause syntax
5764
--

‎src/test/regress/sql/update.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ UPDATE update_test SET a=v.i FROM (VALUES(100, 20)) AS v(i, j)
3535

3636
SELECT*FROM update_test;
3737

38+
-- fail, wrong data type:
39+
UPDATE update_testSET a= v.*FROM (VALUES(100,20))AS v(i, j)
40+
WHEREupdate_test.b=v.j;
41+
3842
--
3943
-- Test multiple-set-clause syntax
4044
--

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp