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

Commit1d0399b

Browse files
committed
Fix infer_arbiter_indexes() to not assume resultRelation is 1.
infer_arbiter_indexes failed to renumber varnos in index expressionsor predicates that it got from the catalogs. This escaped detectionup to now because the stored varnos in such trees will be 1, and anINSERT's result relation is usually the first rangetable entry,so that that was fine. However, in cases such as inserting throughan updatable view, it's not fine, leading to failure to match theexpressions to the query with ensuing "there is no unique or exclusionconstraint matching the ON CONFLICT specification" errors.Fix by copy-and-paste from get_relation_info().Per bug #18502 from Michael Wang. Back-patch to all supportedversions.Discussion:https://postgr.es/m/18502-545b53f5b81e54e0@postgresql.org
1 parent03c8cdb commit1d0399b

File tree

3 files changed

+27
-1
lines changed

3 files changed

+27
-1
lines changed

‎src/backend/optimizer/util/plancat.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,7 @@ infer_arbiter_indexes(PlannerInfo *root)
632632
OnConflictExpr*onconflict=root->parse->onConflict;
633633

634634
/* Iteration state */
635+
Indexvarno;
635636
RangeTblEntry*rte;
636637
Relationrelation;
637638
OidindexOidFromConstraint=InvalidOid;
@@ -660,7 +661,8 @@ infer_arbiter_indexes(PlannerInfo *root)
660661
* the rewriter or when expand_inherited_rtentry() added it to the query's
661662
* rangetable.
662663
*/
663-
rte=rt_fetch(root->parse->resultRelation,root->parse->rtable);
664+
varno=root->parse->resultRelation;
665+
rte=rt_fetch(varno,root->parse->rtable);
664666

665667
relation=table_open(rte->relid,NoLock);
666668

@@ -794,6 +796,9 @@ infer_arbiter_indexes(PlannerInfo *root)
794796

795797
/* Expression attributes (if any) must match */
796798
idxExprs=RelationGetIndexExpressions(idxRel);
799+
if (idxExprs&&varno!=1)
800+
ChangeVarNodes((Node*)idxExprs,1,varno,0);
801+
797802
foreach(el,onconflict->arbiterElems)
798803
{
799804
InferenceElem*elem= (InferenceElem*)lfirst(el);
@@ -845,6 +850,8 @@ infer_arbiter_indexes(PlannerInfo *root)
845850
* CONFLICT's WHERE clause.
846851
*/
847852
predExprs=RelationGetIndexPredicate(idxRel);
853+
if (predExprs&&varno!=1)
854+
ChangeVarNodes((Node*)predExprs,1,varno,0);
848855

849856
if (!predicate_implied_by(predExprs, (List*)onconflict->arbiterWhere, false))
850857
gotonext;

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
-- insert...on conflict do unique index inference
33
--
44
create table insertconflicttest(key int4, fruit text);
5+
-- These things should work through a view, as well
6+
create view insertconflictview as select * from insertconflicttest;
57
--
68
-- Test unique index inference with operator class specifications and
79
-- named collations
@@ -43,6 +45,15 @@ explain (costs off) insert into insertconflicttest values(0, 'Crowberry') on con
4345
-> Result
4446
(4 rows)
4547

48+
explain (costs off) insert into insertconflictview values(0, 'Crowberry') on conflict (lower(fruit), key, lower(fruit), key) do nothing;
49+
QUERY PLAN
50+
-------------------------------------------------
51+
Insert on insertconflicttest
52+
Conflict Resolution: NOTHING
53+
Conflict Arbiter Indexes: both_index_expr_key
54+
-> Result
55+
(4 rows)
56+
4657
explain (costs off) insert into insertconflicttest values(0, 'Crowberry') on conflict (key, fruit) do update set fruit = excluded.fruit
4758
where exists (select 1 from insertconflicttest ii where ii.key = excluded.key);
4859
QUERY PLAN
@@ -374,6 +385,7 @@ create unique index partial_key_index on insertconflicttest(key) where fruit lik
374385
-- Succeeds
375386
insert into insertconflicttest values (23, 'Blackberry') on conflict (key) where fruit like '%berry' do update set fruit = excluded.fruit;
376387
insert into insertconflicttest as t values (23, 'Blackberry') on conflict (key) where fruit like '%berry' and t.fruit = 'inconsequential' do nothing;
388+
insert into insertconflictview as t values (23, 'Blackberry') on conflict (key) where fruit like '%berry' and t.fruit = 'inconsequential' do nothing;
377389
-- fails
378390
insert into insertconflicttest values (23, 'Blackberry') on conflict (key) do update set fruit = excluded.fruit;
379391
ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
@@ -439,6 +451,7 @@ explain (costs off) insert into insertconflicttest as i values (23, 'Avocado') o
439451

440452
drop index plain;
441453
-- Cleanup
454+
drop view insertconflictview;
442455
drop table insertconflicttest;
443456
--
444457
-- Verify that EXCLUDED does not allow system column references. These

‎src/test/regress/sql/insert_conflict.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
--
44
createtableinsertconflicttest(key int4, fruittext);
55

6+
-- These things should work through a view, as well
7+
createviewinsertconflictviewasselect*from insertconflicttest;
8+
69
--
710
-- Test unique index inference with operator class specifications and
811
-- named collations
@@ -20,6 +23,7 @@ explain (costs off) insert into insertconflicttest values(0, 'Crowberry') on con
2023
explain (costs off)insert into insertconflicttestvalues(0,'Crowberry')on conflict (key, fruit) do nothing;
2124
explain (costs off)insert into insertconflicttestvalues(0,'Crowberry')on conflict (fruit, key, fruit, key) do nothing;
2225
explain (costs off)insert into insertconflicttestvalues(0,'Crowberry')on conflict (lower(fruit), key,lower(fruit), key) do nothing;
26+
explain (costs off)insert into insertconflictviewvalues(0,'Crowberry')on conflict (lower(fruit), key,lower(fruit), key) do nothing;
2327
explain (costs off)insert into insertconflicttestvalues(0,'Crowberry')on conflict (key, fruit) doupdateset fruit=excluded.fruit
2428
where exists (select1from insertconflicttest iiwhereii.key=excluded.key);
2529
-- Neither collation nor operator class specifications are required --
@@ -215,6 +219,7 @@ create unique index partial_key_index on insertconflicttest(key) where fruit lik
215219
-- Succeeds
216220
insert into insertconflicttestvalues (23,'Blackberry')on conflict (key)where fruitlike'%berry' doupdateset fruit=excluded.fruit;
217221
insert into insertconflicttestas tvalues (23,'Blackberry')on conflict (key)where fruitlike'%berry'andt.fruit='inconsequential' do nothing;
222+
insert into insertconflictviewas tvalues (23,'Blackberry')on conflict (key)where fruitlike'%berry'andt.fruit='inconsequential' do nothing;
218223

219224
-- fails
220225
insert into insertconflicttestvalues (23,'Blackberry')on conflict (key) doupdateset fruit=excluded.fruit;
@@ -247,6 +252,7 @@ explain (costs off) insert into insertconflicttest as i values (23, 'Avocado') o
247252
dropindex plain;
248253

249254
-- Cleanup
255+
dropview insertconflictview;
250256
droptable insertconflicttest;
251257

252258

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp