Skip to content

Commit c1ca3a1

Browse files
committed
Fix bug around assignment expressions containing indirections.
Handling of assigned-to expressions with indirection (e.g. set f1[1] = 3) was broken for ON CONFLICT DO UPDATE. The problem was that ParseState was consulted to determine if an INSERT-appropriate or UPDATE-appropriate behavior should be used when transforming expressions with indirections. When the wrong path was taken the old row was substituted with NULL, leading to wrong results.. To fix remove p_is_update and only use p_is_insert to decide how to transform the assignment expression, and uset p_is_insert while parsing the on conflict statement. This isn't particularly pretty, but it's not any worse than before. Author: Peter Geoghegan, slightly edited by me Discussion: CAM3SWZS8RPvA=KFxADZWw3wAHnnbxMxDzkEC6fNaFc7zSm411w@mail.gmail.com Backpatch: 9.5, where the feature was introduced
1 parent 16c33c5 commit c1ca3a1

File tree

4 files changed

+41
-2
lines changed

4 files changed

+41
-2
lines changed

src/backend/parser/analyze.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,12 @@ transformOnConflictClause(ParseState *pstate,
891891
/* Process DO UPDATE */
892892
if (onConflictClause->action == ONCONFLICT_UPDATE)
893893
{
894+
/*
895+
* All INSERT expressions have been parsed, get ready for potentially
896+
* existing SET statements that need to be processed like an UPDATE.
897+
*/
898+
pstate->p_is_insert = false;
899+
894900
exclRte = addRangeTableEntryForRelation(pstate,
895901
pstate->p_target_relation,
896902
makeAlias("excluded", NIL),
@@ -1999,7 +2005,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
19992005
Node *qual;
20002006

20012007
qry->commandType = CMD_UPDATE;
2002-
pstate->p_is_update = true;
2008+
pstate->p_is_insert = false;
20032009

20042010
/* process the WITH clause independently of all else */
20052011
if (stmt->withClause)

src/include/parser/parse_node.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,6 @@ struct ParseState
152152
bool p_hasSubLinks;
153153
bool p_hasModifyingCTE;
154154
bool p_is_insert;
155-
bool p_is_update;
156155
bool p_locked_from_parent;
157156
Relation p_target_relation;
158157
RangeTblEntry *p_target_rangetblentry;

src/test/regress/expected/arrays.out

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,27 @@ select * from arr_tbl where f1 >= '{1,2,3}' and f1 < '{1,5,3}';
11161116
{1,2,10}
11171117
(2 rows)
11181118

1119+
-- test ON CONFLICT DO UPDATE with arrays
1120+
create temp table arr_pk_tbl (pk int4 primary key, f1 int[]);
1121+
insert into arr_pk_tbl values (1, '{1,2,3}');
1122+
insert into arr_pk_tbl values (1, '{3,4,5}') on conflict (pk)
1123+
do update set f1[1] = excluded.f1[1], f1[3] = excluded.f1[3]
1124+
returning pk, f1;
1125+
pk | f1
1126+
----+---------
1127+
1 | {3,2,5}
1128+
(1 row)
1129+
1130+
insert into arr_pk_tbl(pk, f1[1:2]) values (1, '{6,7,8}') on conflict (pk)
1131+
do update set f1[1] = excluded.f1[1],
1132+
f1[2] = excluded.f1[2],
1133+
f1[3] = excluded.f1[3]
1134+
returning pk, f1;
1135+
pk | f1
1136+
----+------------
1137+
1 | {6,7,NULL}
1138+
(1 row)
1139+
11191140
-- note: if above selects don't produce the expected tuple order,
11201141
-- then you didn't get an indexscan plan, and something is busted.
11211142
reset enable_seqscan;

src/test/regress/sql/arrays.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,19 @@ set enable_seqscan to off;
306306
set enable_bitmapscan to off;
307307
select * from arr_tbl where f1 > '{1,2,3}' and f1 <= '{1,5,3}';
308308
select * from arr_tbl where f1 >= '{1,2,3}' and f1 < '{1,5,3}';
309+
310+
-- test ON CONFLICT DO UPDATE with arrays
311+
create temp table arr_pk_tbl (pk int4 primary key, f1 int[]);
312+
insert into arr_pk_tbl values (1, '{1,2,3}');
313+
insert into arr_pk_tbl values (1, '{3,4,5}') on conflict (pk)
314+
do update set f1[1] = excluded.f1[1], f1[3] = excluded.f1[3]
315+
returning pk, f1;
316+
insert into arr_pk_tbl(pk, f1[1:2]) values (1, '{6,7,8}') on conflict (pk)
317+
do update set f1[1] = excluded.f1[1],
318+
f1[2] = excluded.f1[2],
319+
f1[3] = excluded.f1[3]
320+
returning pk, f1;
321+
309322
-- note: if above selects don't produce the expected tuple order,
310323
-- then you didn't get an indexscan plan, and something is busted.
311324
reset enable_seqscan;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy