diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 07a99e9c6b..0ad3dc5aae 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.163 2007/04/21 21:01:44 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.164 2007/05/26 18:23:01 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -45,6 +45,7 @@ static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte); static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte); +static void set_dummy_rel_pathlist(RelOptInfo *rel); static void set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte); static void set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, @@ -198,23 +199,14 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) { /* * If we can prove we don't need to scan the rel via constraint exclusion, - * set up a single dummy path for it. (Rather than inventing a special - * "dummy" path type, we represent this as an AppendPath with no members.) - * We only need to check for regular baserels; if it's an otherrel, CE - * was already checked in set_append_rel_pathlist(). + * set up a single dummy path for it. We only need to check for regular + * baserels; if it's an otherrel, CE was already checked in + * set_append_rel_pathlist(). */ if (rel->reloptkind == RELOPT_BASEREL && relation_excluded_by_constraints(rel, rte)) { - /* Set dummy size estimates --- we leave attr_widths[] as zeroes */ - rel->rows = 0; - rel->width = 0; - - add_path(rel, (Path *) create_append_path(rel, NIL)); - - /* Select cheapest path (pretty easy in this case...) */ - set_cheapest(rel); - + set_dummy_rel_pathlist(rel); return; } @@ -330,7 +322,12 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, if (relation_excluded_by_constraints(childrel, childRTE)) { - /* this child need not be scanned, so just disregard it */ + /* + * This child need not be scanned, so we can omit it from the + * appendrel. Mark it with a dummy cheapest-path though, in + * case best_appendrel_indexscan() looks at it later. + */ + set_dummy_rel_pathlist(childrel); continue; } @@ -425,6 +422,26 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, set_cheapest(rel); } +/* + * set_dummy_rel_pathlist + * Build a dummy path for a relation that's been excluded by constraints + * + * Rather than inventing a special "dummy" path type, we represent this as an + * AppendPath with no members. + */ +static void +set_dummy_rel_pathlist(RelOptInfo *rel) +{ + /* Set dummy size estimates --- we leave attr_widths[] as zeroes */ + rel->rows = 0; + rel->width = 0; + + add_path(rel, (Path *) create_append_path(rel, NIL)); + + /* Select cheapest path (pretty easy in this case...) */ + set_cheapest(rel); +} + /* quick-and-dirty test to see if any joining is needed */ static bool has_multiple_baserels(PlannerInfo *root) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 0f9776cdca..e2396d42ca 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.220 2007/05/25 17:54:25 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.221 2007/05/26 18:23:01 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -669,11 +669,16 @@ inheritance_planner(PlannerInfo *root) * If we managed to exclude every child rel, return a dummy plan */ if (subplans == NIL) + { + root->resultRelations = list_make1_int(parentRTindex); + /* although dummy, it must have a valid tlist for executor */ + tlist = preprocess_targetlist(root, parse->targetList); return (Plan *) make_result(root, tlist, (Node *) list_make1(makeBoolConst(false, false)), NULL); + } /* * Planning might have modified the rangetable, due to changes of the diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 112891bbb2..e1098fd684 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1493,3 +1493,61 @@ select * from id_ordered; set client_min_messages to warning; -- suppress cascade notices drop table id cascade; +reset client_min_messages; +-- +-- check corner case where an entirely-dummy subplan is created by +-- constraint exclusion +-- +create temp table t1 (a integer primary key); +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t1_pkey" for table "t1" +create temp table t1_1 (check (a >= 0 and a < 10)) inherits (t1); +create temp table t1_2 (check (a >= 10 and a < 20)) inherits (t1); +create rule t1_ins_1 as on insert to t1 + where new.a >= 0 and new.a < 10 + do instead + insert into t1_1 values (new.a); +create rule t1_ins_2 as on insert to t1 + where new.a >= 10 and new.a < 20 + do instead + insert into t1_2 values (new.a); +create rule t1_upd_1 as on update to t1 + where old.a >= 0 and old.a < 10 + do instead + update t1_1 set a = new.a where a = old.a; +create rule t1_upd_2 as on update to t1 + where old.a >= 10 and old.a < 20 + do instead + update t1_2 set a = new.a where a = old.a; +set constraint_exclusion = on; +insert into t1 select * from generate_series(5,19,1) g; +update t1 set a = 4 where a = 5; +select * from only t1; + a +--- +(0 rows) + +select * from only t1_1; + a +--- + 6 + 7 + 8 + 9 + 4 +(5 rows) + +select * from only t1_2; + a +---- + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 +(10 rows) + diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql index 374e11d671..e898336d92 100644 --- a/src/test/regress/sql/rules.sql +++ b/src/test/regress/sql/rules.sql @@ -881,3 +881,41 @@ select * from id_ordered; set client_min_messages to warning; -- suppress cascade notices drop table id cascade; +reset client_min_messages; + +-- +-- check corner case where an entirely-dummy subplan is created by +-- constraint exclusion +-- + +create temp table t1 (a integer primary key); + +create temp table t1_1 (check (a >= 0 and a < 10)) inherits (t1); +create temp table t1_2 (check (a >= 10 and a < 20)) inherits (t1); + +create rule t1_ins_1 as on insert to t1 + where new.a >= 0 and new.a < 10 + do instead + insert into t1_1 values (new.a); +create rule t1_ins_2 as on insert to t1 + where new.a >= 10 and new.a < 20 + do instead + insert into t1_2 values (new.a); + +create rule t1_upd_1 as on update to t1 + where old.a >= 0 and old.a < 10 + do instead + update t1_1 set a = new.a where a = old.a; +create rule t1_upd_2 as on update to t1 + where old.a >= 10 and old.a < 20 + do instead + update t1_2 set a = new.a where a = old.a; + +set constraint_exclusion = on; + +insert into t1 select * from generate_series(5,19,1) g; +update t1 set a = 4 where a = 5; + +select * from only t1; +select * from only t1_1; +select * from only t1_2;