]> granicus.if.org Git - postgresql/commitdiff
Repair two constraint-exclusion corner cases triggered by proving that an
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 26 May 2007 18:23:02 +0000 (18:23 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 26 May 2007 18:23:02 +0000 (18:23 +0000)
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.

src/backend/optimizer/path/allpaths.c
src/backend/optimizer/plan/planner.c
src/test/regress/expected/rules.out
src/test/regress/sql/rules.sql

index 07a99e9c6b7c6503542e1346cce33ef2377aefa9..0ad3dc5aae1b4c0f32107b20fe62ffc7a825c533 100644 (file)
@@ -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)
index 0f9776cdca20b2fcca18ef2276050d02439bd433..e2396d42ca6a279a67580c793b620d1078bf755e 100644 (file)
@@ -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
index 112891bbb2c1f753f41a3437ee09d28b0f557921..e1098fd68456d5da100b2e674fd19c26cccbdb4c 100644 (file)
@@ -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)
+
index 374e11d671c4f114ac126f240b9b4746fd33e33d..e898336d92a27df3bdb70cd8b3391022abd5ea8d 100644 (file)
@@ -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;