Skip to content

Commit cadb783

Browse files
committed
Repair two constraint-exclusion corner cases triggered by proving that an
inheritance child of an UPDATE/DELETE target relation can be excluded by constraints. I had rearranged some code in set_append_rel_pathlist() to avoid "useless" work when a child is excluded, but overdid it and left the child with no cheapest_path entry, causing possible failure later if the appendrel was involved in a join. Also, it seems that the dummy plan generated by inheritance_planner() when all branches are excluded has to be a bit less dummy now than was required in 8.2. Per report from Jan Wieck. Add his test case to the regression tests.
1 parent 604ffd2 commit cadb783

File tree

4 files changed

+134
-16
lines changed

4 files changed

+134
-16
lines changed

src/backend/optimizer/path/allpaths.c

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.163 2007/04/21 21:01:44 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.164 2007/05/26 18:23:01 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -45,6 +45,7 @@ static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
4545
RangeTblEntry *rte);
4646
static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
4747
Index rti, RangeTblEntry *rte);
48+
static void set_dummy_rel_pathlist(RelOptInfo *rel);
4849
static void set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
4950
Index rti, RangeTblEntry *rte);
5051
static void set_function_pathlist(PlannerInfo *root, RelOptInfo *rel,
@@ -198,23 +199,14 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
198199
{
199200
/*
200201
* If we can prove we don't need to scan the rel via constraint exclusion,
201-
* set up a single dummy path for it. (Rather than inventing a special
202-
* "dummy" path type, we represent this as an AppendPath with no members.)
203-
* We only need to check for regular baserels; if it's an otherrel, CE
204-
* was already checked in set_append_rel_pathlist().
202+
* set up a single dummy path for it. We only need to check for regular
203+
* baserels; if it's an otherrel, CE was already checked in
204+
* set_append_rel_pathlist().
205205
*/
206206
if (rel->reloptkind == RELOPT_BASEREL &&
207207
relation_excluded_by_constraints(rel, rte))
208208
{
209-
/* Set dummy size estimates --- we leave attr_widths[] as zeroes */
210-
rel->rows = 0;
211-
rel->width = 0;
212-
213-
add_path(rel, (Path *) create_append_path(rel, NIL));
214-
215-
/* Select cheapest path (pretty easy in this case...) */
216-
set_cheapest(rel);
217-
209+
set_dummy_rel_pathlist(rel);
218210
return;
219211
}
220212

@@ -330,7 +322,12 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
330322

331323
if (relation_excluded_by_constraints(childrel, childRTE))
332324
{
333-
/* this child need not be scanned, so just disregard it */
325+
/*
326+
* This child need not be scanned, so we can omit it from the
327+
* appendrel. Mark it with a dummy cheapest-path though, in
328+
* case best_appendrel_indexscan() looks at it later.
329+
*/
330+
set_dummy_rel_pathlist(childrel);
334331
continue;
335332
}
336333

@@ -425,6 +422,26 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
425422
set_cheapest(rel);
426423
}
427424

425+
/*
426+
* set_dummy_rel_pathlist
427+
* Build a dummy path for a relation that's been excluded by constraints
428+
*
429+
* Rather than inventing a special "dummy" path type, we represent this as an
430+
* AppendPath with no members.
431+
*/
432+
static void
433+
set_dummy_rel_pathlist(RelOptInfo *rel)
434+
{
435+
/* Set dummy size estimates --- we leave attr_widths[] as zeroes */
436+
rel->rows = 0;
437+
rel->width = 0;
438+
439+
add_path(rel, (Path *) create_append_path(rel, NIL));
440+
441+
/* Select cheapest path (pretty easy in this case...) */
442+
set_cheapest(rel);
443+
}
444+
428445
/* quick-and-dirty test to see if any joining is needed */
429446
static bool
430447
has_multiple_baserels(PlannerInfo *root)

src/backend/optimizer/plan/planner.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.220 2007/05/25 17:54:25 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.221 2007/05/26 18:23:01 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -669,11 +669,16 @@ inheritance_planner(PlannerInfo *root)
669669
* If we managed to exclude every child rel, return a dummy plan
670670
*/
671671
if (subplans == NIL)
672+
{
673+
root->resultRelations = list_make1_int(parentRTindex);
674+
/* although dummy, it must have a valid tlist for executor */
675+
tlist = preprocess_targetlist(root, parse->targetList);
672676
return (Plan *) make_result(root,
673677
tlist,
674678
(Node *) list_make1(makeBoolConst(false,
675679
false)),
676680
NULL);
681+
}
677682

678683
/*
679684
* Planning might have modified the rangetable, due to changes of the

src/test/regress/expected/rules.out

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,3 +1493,61 @@ select * from id_ordered;
14931493

14941494
set client_min_messages to warning; -- suppress cascade notices
14951495
drop table id cascade;
1496+
reset client_min_messages;
1497+
--
1498+
-- check corner case where an entirely-dummy subplan is created by
1499+
-- constraint exclusion
1500+
--
1501+
create temp table t1 (a integer primary key);
1502+
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t1_pkey" for table "t1"
1503+
create temp table t1_1 (check (a >= 0 and a < 10)) inherits (t1);
1504+
create temp table t1_2 (check (a >= 10 and a < 20)) inherits (t1);
1505+
create rule t1_ins_1 as on insert to t1
1506+
where new.a >= 0 and new.a < 10
1507+
do instead
1508+
insert into t1_1 values (new.a);
1509+
create rule t1_ins_2 as on insert to t1
1510+
where new.a >= 10 and new.a < 20
1511+
do instead
1512+
insert into t1_2 values (new.a);
1513+
create rule t1_upd_1 as on update to t1
1514+
where old.a >= 0 and old.a < 10
1515+
do instead
1516+
update t1_1 set a = new.a where a = old.a;
1517+
create rule t1_upd_2 as on update to t1
1518+
where old.a >= 10 and old.a < 20
1519+
do instead
1520+
update t1_2 set a = new.a where a = old.a;
1521+
set constraint_exclusion = on;
1522+
insert into t1 select * from generate_series(5,19,1) g;
1523+
update t1 set a = 4 where a = 5;
1524+
select * from only t1;
1525+
a
1526+
---
1527+
(0 rows)
1528+
1529+
select * from only t1_1;
1530+
a
1531+
---
1532+
6
1533+
7
1534+
8
1535+
9
1536+
4
1537+
(5 rows)
1538+
1539+
select * from only t1_2;
1540+
a
1541+
----
1542+
10
1543+
11
1544+
12
1545+
13
1546+
14
1547+
15
1548+
16
1549+
17
1550+
18
1551+
19
1552+
(10 rows)
1553+

src/test/regress/sql/rules.sql

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,3 +881,41 @@ select * from id_ordered;
881881

882882
set client_min_messages to warning; -- suppress cascade notices
883883
drop table id cascade;
884+
reset client_min_messages;
885+
886+
--
887+
-- check corner case where an entirely-dummy subplan is created by
888+
-- constraint exclusion
889+
--
890+
891+
create temp table t1 (a integer primary key);
892+
893+
create temp table t1_1 (check (a >= 0 and a < 10)) inherits (t1);
894+
create temp table t1_2 (check (a >= 10 and a < 20)) inherits (t1);
895+
896+
create rule t1_ins_1 as on insert to t1
897+
where new.a >= 0 and new.a < 10
898+
do instead
899+
insert into t1_1 values (new.a);
900+
create rule t1_ins_2 as on insert to t1
901+
where new.a >= 10 and new.a < 20
902+
do instead
903+
insert into t1_2 values (new.a);
904+
905+
create rule t1_upd_1 as on update to t1
906+
where old.a >= 0 and old.a < 10
907+
do instead
908+
update t1_1 set a = new.a where a = old.a;
909+
create rule t1_upd_2 as on update to t1
910+
where old.a >= 10 and old.a < 20
911+
do instead
912+
update t1_2 set a = new.a where a = old.a;
913+
914+
set constraint_exclusion = on;
915+
916+
insert into t1 select * from generate_series(5,19,1) g;
917+
update t1 set a = 4 where a = 5;
918+
919+
select * from only t1;
920+
select * from only t1_1;
921+
select * from only t1_2;

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