On 21.03.2018 20:30, Konstantin Knizhnik wrote:


On 01.03.2018 23:15, Andres Freund wrote:
Hi,


This patch seems like quite a good improvement. One thing I've not
really looked at but am slightly concerned in passing: Are there cases
where we now would do a lot of predicate pruning work even though the
overhead of just evaluating the qual is trivial, e.g. because there's
only one row due to a pkey? The predtest code is many things but
lightning fast is not one of them.  Obviously that won't matter for
analytics queries, but I could see it hurt in OLTPish workloads...

Greetings,

Andres Freund

Hi,
I am sorry for delay with answer.

I understand your concern and did the following experiment.
I have initialized the database in the following way:

create table base (k integer primary key, v integer);
create table part1 (check (k between 1 and 10000)) inherits (base);
create table part2 (check (k between 10001 and 20000)) inherits (base);
create index pi1 on part1(v);
create index pi2 on part2(v);
insert into part1 values (generate series(1,10000), random()*100000);
insert into part2 values (generate_series(10001,20000), random()*100000);
vacuum analyze part1;
vacuum analyze part2;

Vanilla Postgres uses the following plan:

explain select * from base where k between 1 and 20000 and v = 100;
                              QUERY PLAN
-----------------------------------------------------------------------
 Append  (cost=0.00..16.63 rows=3 width=8)
   ->  Seq Scan on base  (cost=0.00..0.00 rows=1 width=8)
         Filter: ((k >= 1) AND (k <= 20000) AND (v = 100))
   ->  Index Scan using pi1 on part1  (cost=0.29..8.31 rows=1 width=8)
         Index Cond: (v = 100)
         Filter: ((k >= 1) AND (k <= 20000))
   ->  Index Scan using pi2 on part2  (cost=0.29..8.31 rows=1 width=8)
         Index Cond: (v = 100)
         Filter: ((k >= 1) AND (k <= 20000))
(9 rows)

Execution of this query 100000 times gives is done in 12 seconds.
With applied patch query plan is changed to:

                              QUERY PLAN
-----------------------------------------------------------------------
 Append  (cost=0.00..16.62 rows=3 width=8)
   ->  Seq Scan on base  (cost=0.00..0.00 rows=1 width=8)
         Filter: ((k >= 1) AND (k <= 20000) AND (v = 100))
   ->  Index Scan using pi1 on part1  (cost=0.29..8.30 rows=1 width=8)
         Index Cond: (v = 100)
   ->  Index Scan using pi2 on part2  (cost=0.29..8.30 rows=1 width=8)
         Index Cond: (v = 100)
(7 rows)

Elapsed time of 100000 query executions is 13 seconds.
So you was right that increased query optimization time exceeds advantage of extra checks elimination.
But it is true only if we are not using prepare statements.
With prepared statements results are the following:

Vanilla:       0m3.915s
This patch: 0m3.563s

So improvement is not so large, but it exists.
If somebody wants to repeat my experiments, I attached to this mail small shell script which I used to run query several times.
Non-prepared query is launched using the following command:

time ./repeat-query.sh "select * from base where k between 1 and 20000 and v = 100" 100000

and prepared query:

time ./repeat-query.sh "execute select100" 100000 "prepare select100 as select * from base where k between 1 and 20000 and v = 100"

And once again I want to notice that using prepared statements can increase performance almost 3 times! As far as using prepared statements is not always possible I want to recall autoprepare patch waiting at the commitfest:

https://www.postgresql.org/message-id/flat/8eed9c23-19ba-5404-7a9e-0584b836b3f3%40postgrespro.ru#8eed9c23-19ba-5404-7a9e-0584b836b...@postgrespro.ru

--
Konstantin Knizhnik
Postgres Professional:http://www.postgrespro.com
The Russian Postgres Company
Attached please find rebased version of the patch.
Also I do more testing, now using pgbench.
Scripts for initialization of the database and for custom script for pgbench are attached.
Results at my computer are the following:

pgbench options
        Vanilla
        Patch
-c 1
        9208
        8289
-c 1 -M prepared
        38503   41206
-c 10
        39224
        34040
-c 10 -M prepared
        165465
        172874






--
Konstantin Knizhnik
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index a2b1384..84b8543 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -631,12 +631,12 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NULL;        -- Nu
    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" IS NULL))
 (3 rows)
 
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NOT NULL;    -- NullTest
-                                             QUERY PLAN                                              
------------------------------------------------------------------------------------------------------
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NOT NULL and c3 is not null;    -- NullTest
+                                            QUERY PLAN                                            
+--------------------------------------------------------------------------------------------------
  Foreign Scan on public.ft1 t1
    Output: c1, c2, c3, c4, c5, c6, c7, c8
-   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" IS NOT NULL))
+   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c3 IS NOT NULL))
 (3 rows)
 
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE round(abs(c1), 0) = 1; -- FuncExpr
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 4d2e43c..cc03c86 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -298,7 +298,7 @@ RESET enable_nestloop;
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.c1 = 1;         -- Var, OpExpr(b), Const
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.c1 = 100 AND t1.c2 = 0; -- BoolExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NULL;        -- NullTest
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NOT NULL;    -- NullTest
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NOT NULL and c3 is not null;    -- NullTest
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE round(abs(c1), 0) = 1; -- FuncExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- OpExpr(l)
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 8735e29..81c3459 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -346,6 +346,7 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
 		switch (rel->rtekind)
 		{
 			case RTE_RELATION:
+				remove_restrictions_implied_by_constraints(root, rel, rte);
 				if (rte->relkind == RELKIND_FOREIGN_TABLE)
 				{
 					/* Foreign table */
@@ -1132,6 +1133,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 			set_dummy_rel_pathlist(childrel);
 			continue;
 		}
+		remove_restrictions_implied_by_constraints(root, childrel, childRTE);
 
 		/* CE failed, so finish copying/modifying join quals. */
 		childrel->joininfo = (List *)
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index bd3a0c4..96b9056 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -1485,6 +1485,51 @@ relation_excluded_by_constraints(PlannerInfo *root,
 	return false;
 }
 
+/*
+ * Remove from restrictions list items implied by table constraints
+ */
+void remove_restrictions_implied_by_constraints(PlannerInfo *root,
+												RelOptInfo *rel, RangeTblEntry *rte)
+{
+	List	   *constraint_pred;
+	List	   *safe_constraints = NIL;
+	List	   *safe_restrictions = NIL;
+	ListCell   *lc;
+
+	if (rte->rtekind != RTE_RELATION || rte->inh)
+		return;
+
+	/*
+	 * OK to fetch the constraint expressions.  Include "col IS NOT NULL"
+	 * expressions for attnotnull columns, in case we can refute those.
+	 */
+	constraint_pred = get_relation_constraints(root, rte->relid, rel, true);
+
+	/*
+	 * We do not currently enforce that CHECK constraints contain only
+	 * immutable functions, so it's necessary to check here. We daren't draw
+	 * conclusions from plan-time evaluation of non-immutable functions. Since
+	 * they're ANDed, we can just ignore any mutable constraints in the list,
+	 * and reason about the rest.
+	 */
+	foreach(lc, constraint_pred)
+	{
+		Node	   *pred = (Node*) lfirst(lc);
+
+		if (!contain_mutable_functions(pred))
+			safe_constraints = lappend(safe_constraints, pred);
+	}
+
+	foreach(lc, rel->baserestrictinfo)
+	{
+		RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
+		if (!predicate_implied_by(list_make1(rinfo->clause), safe_constraints, false)) {
+			safe_restrictions = lappend(safe_restrictions, rinfo);
+		}
+	}
+	rel->baserestrictinfo = safe_restrictions;
+}
+
 
 /*
  * build_physical_tlist
diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c
index 446207d..9c2f28f 100644
--- a/src/backend/optimizer/util/predtest.c
+++ b/src/backend/optimizer/util/predtest.c
@@ -17,6 +17,9 @@
 
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_range.h"
+#include "catalog/pg_operator.h"
+#include "access/htup_details.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
@@ -26,6 +29,8 @@
 #include "utils/inval.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
+#include "utils/typcache.h"
+#include "utils/rangetypes.h"
 
 
 /*
@@ -1472,6 +1477,67 @@ static const StrategyNumber BT_refute_table[6][6] = {
 	{none, none, BTEQ, none, none, none}	/* NE */
 };
 
+/*
+ * Contruct range type for the comparison operator:
+ * '<=' ->  '(,"$value"]'
+ * '>=' ->  '["$value",)'
+ * '<'  ->  '(,"$value")'
+ * '>'. ->  '("$value",)'
+ * otherwise: NULL
+ */
+static RangeType*
+operator_to_range(TypeCacheEntry *typcache, Oid oper, Const* literal)
+{
+	RangeBound  lower, upper;
+	List*       op_infos = get_op_btree_interpretation(oper);
+	ListCell   *lcp;
+
+	lower.lower = true;
+	upper.lower = false;
+	lower.infinite = true;
+	upper.infinite = true;
+
+	foreach(lcp, op_infos)
+	{
+		OpBtreeInterpretation *op_info = lfirst(lcp);
+
+		switch (op_info->strategy)
+		{
+		  case BTLessStrategyNumber:
+			lower.infinite = true;
+			lower.inclusive = false;
+			upper.infinite = false;
+			upper.inclusive = false;
+			upper.val = literal->constvalue;
+			break;
+		  case BTLessEqualStrategyNumber:
+			lower.infinite = true;
+			lower.inclusive = false;
+			upper.infinite = false;
+			upper.inclusive = true;
+			upper.val = literal->constvalue;
+			break;
+		  case BTGreaterStrategyNumber:
+			lower.infinite = false;
+			lower.inclusive = false;
+			lower.val = literal->constvalue;
+			upper.infinite = true;
+			upper.inclusive = false;
+			break;
+		  case BTGreaterEqualStrategyNumber:
+			lower.infinite = false;
+			lower.inclusive = true;
+			lower.val = literal->constvalue;
+			upper.infinite = true;
+			upper.inclusive = false;
+			break;
+		  default:
+			continue;
+		}
+		break;
+	}
+	return lower.infinite && upper.infinite ? NULL : make_range(typcache, &lower, &upper, false);
+}
 
 /*
  * operator_predicate_proof
@@ -1671,6 +1737,18 @@ operator_predicate_proof(Expr *predicate, Node *clause,
 		return false;
 	}
 
+	if (!refute_it && pred_const->consttype == clause_const->consttype)
+	{
+		TypeCacheEntry *typcache = lookup_type_cache(clause_const->consttype, TYPECACHE_RANGE_TYPE)->rng_type;
+		if (typcache != NULL)
+		{
+			RangeType* pred_range = operator_to_range(typcache, pred_op, pred_const);
+			RangeType* clause_range = operator_to_range(typcache, clause_op, clause_const);
+			if (pred_range && clause_range && range_eq_internal(typcache, pred_range, clause_range))
+				return true;
+		}
+	}
+
 	/*
 	 * We have two identical subexpressions, and two other subexpressions that
 	 * are not identical but are both Consts; and we have commuted the
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index 874d8cd..4b698c2 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -277,6 +277,7 @@ static uint64 tupledesc_id_counter = INVALID_TUPLEDESC_IDENTIFIER;
 
 static void load_typcache_tupdesc(TypeCacheEntry *typentry);
 static void load_rangetype_info(TypeCacheEntry *typentry);
+static void lookup_range_for_type(TypeCacheEntry *typentry);
 static void load_domaintype_info(TypeCacheEntry *typentry);
 static int	dcs_cmp(const void *a, const void *b);
 static void decr_dcc_refcount(DomainConstraintCache *dcc);
@@ -755,6 +756,11 @@ lookup_type_cache(Oid type_id, int flags)
 	{
 		load_rangetype_info(typentry);
 	}
+	if ((flags & TYPECACHE_RANGE_TYPE) &&
+		!(typentry->flags & TYPECACHE_RANGE_TYPE))
+	{
+		lookup_range_for_type(typentry);
+	}
 
 	/*
 	 * If requested, get information about a domain type
@@ -812,6 +818,39 @@ load_typcache_tupdesc(TypeCacheEntry *typentry)
 }
 
 /*
+ * Get range type for the correspondent scalar type.
+ * This function performs sequential scan in pg_range table.
+ */
+static void
+lookup_range_for_type(TypeCacheEntry *typentry)
+{
+	Relation	pgRangeRel;
+	Form_pg_range pgRange;
+	SysScanDesc scan;
+	HeapTuple	tuple;
+
+	pgRangeRel = heap_open(RangeRelationId, AccessShareLock);
+
+	scan = systable_beginscan(pgRangeRel, InvalidOid, false,
+							  NULL, 0, NULL);
+
+	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
+	{
+		pgRange = (Form_pg_range) GETSTRUCT(tuple);
+		if (pgRange->rngsubtype == typentry->type_id)
+		{
+			typentry->rng_type = lookup_type_cache(pgRange->rngtypid, TYPECACHE_RANGE_INFO);
+			break;
+		}
+	}
+	systable_endscan(scan);
+	heap_close(pgRangeRel, AccessShareLock);
+
+	typentry->flags |= TYPECACHE_RANGE_TYPE;
+}
+
+
+/*
  * load_rangetype_info --- helper routine to set up range type information
  */
 static void
diff --git a/src/include/optimizer/plancat.h b/src/include/optimizer/plancat.h
index 7d53cbb..12b3c55 100644
--- a/src/include/optimizer/plancat.h
+++ b/src/include/optimizer/plancat.h
@@ -38,6 +38,9 @@ extern int32 get_relation_data_width(Oid relid, int32 *attr_widths);
 extern bool relation_excluded_by_constraints(PlannerInfo *root,
 								 RelOptInfo *rel, RangeTblEntry *rte);
 
+extern void remove_restrictions_implied_by_constraints(PlannerInfo *root,
+													   RelOptInfo *rel, RangeTblEntry *rte);
+
 extern List *build_physical_tlist(PlannerInfo *root, RelOptInfo *rel);
 
 extern bool has_unique_index(RelOptInfo *rel, AttrNumber attno);
diff --git a/src/include/utils/typcache.h b/src/include/utils/typcache.h
index 217d064..4f63539 100644
--- a/src/include/utils/typcache.h
+++ b/src/include/utils/typcache.h
@@ -98,6 +98,12 @@ typedef struct TypeCacheEntry
 	FmgrInfo	rng_subdiff_finfo;	/* difference function, if any */
 
 	/*
+	 * Get range type for the element type when TYPECACHE_RANGE_TYPE is requested.
+	 * This infotmation is obtained by scan of pg_range table. First match is taken./
+	 */
+	struct TypeCacheEntry *rng_type;
+
+	/*
 	 * Domain's base type and typmod if it's a domain type.  Zeroes if not
 	 * domain, or if information hasn't been requested.
 	 */
@@ -140,6 +146,7 @@ typedef struct TypeCacheEntry
 #define TYPECACHE_DOMAIN_CONSTR_INFO		0x2000
 #define TYPECACHE_HASH_EXTENDED_PROC		0x4000
 #define TYPECACHE_HASH_EXTENDED_PROC_FINFO	0x8000
+#define TYPECACHE_RANGE_TYPE		0x10000
 
 /* This value will not equal any valid tupledesc identifier, nor 0 */
 #define INVALID_TUPLEDESC_IDENTIFIER ((uint64) 1)
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index f56151f..0b67564 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1716,30 +1716,26 @@ explain (costs off) select * from list_parted where a is not null;
 ---------------------------------
  Append
    ->  Seq Scan on part_ab_cd
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on part_ef_gh
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on part_null_xy
          Filter: (a IS NOT NULL)
-(7 rows)
+(5 rows)
 
 explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
                         QUERY PLAN                        
 ----------------------------------------------------------
  Append
    ->  Seq Scan on part_ab_cd
-         Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
    ->  Seq Scan on part_ef_gh
          Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(5 rows)
+(4 rows)
 
 explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
-                                      QUERY PLAN                                       
----------------------------------------------------------------------------------------
+          QUERY PLAN          
+------------------------------
  Append
    ->  Seq Scan on part_ab_cd
-         Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(3 rows)
+(2 rows)
 
 explain (costs off) select * from list_parted where a = 'ab';
                 QUERY PLAN                
@@ -1792,30 +1788,25 @@ explain (costs off) select * from range_list_parted where a = 5;
 (5 rows)
 
 explain (costs off) select * from range_list_parted where b = 'ab';
-             QUERY PLAN             
-------------------------------------
+            QUERY PLAN            
+----------------------------------
  Append
    ->  Seq Scan on part_1_10_ab
-         Filter: (b = 'ab'::bpchar)
    ->  Seq Scan on part_10_20_ab
-         Filter: (b = 'ab'::bpchar)
    ->  Seq Scan on part_21_30_ab
-         Filter: (b = 'ab'::bpchar)
    ->  Seq Scan on part_40_inf_ab
-         Filter: (b = 'ab'::bpchar)
-(9 rows)
+(5 rows)
 
 explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
-                           QUERY PLAN                            
------------------------------------------------------------------
+           QUERY PLAN            
+---------------------------------
  Append
    ->  Seq Scan on part_1_10_ab
-         Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
+         Filter: (a >= 3)
    ->  Seq Scan on part_10_20_ab
-         Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
    ->  Seq Scan on part_21_30_ab
-         Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(7 rows)
+         Filter: (a <= 23)
+(6 rows)
 
 /* Should select no rows because range partition key cannot be null */
 explain (costs off) select * from range_list_parted where a is null;
@@ -1831,44 +1822,34 @@ explain (costs off) select * from range_list_parted where b is null;
 ------------------------------------
  Append
    ->  Seq Scan on part_40_inf_null
-         Filter: (b IS NULL)
-(3 rows)
+(2 rows)
 
 explain (costs off) select * from range_list_parted where a is not null and a < 67;
-                   QUERY PLAN                   
-------------------------------------------------
+             QUERY PLAN             
+------------------------------------
  Append
    ->  Seq Scan on part_1_10_ab
-         Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_1_10_cd
-         Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_10_20_ab
-         Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_10_20_cd
-         Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_21_30_ab
-         Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_21_30_cd
-         Filter: ((a IS NOT NULL) AND (a < 67))
    ->  Seq Scan on part_40_inf_ab
-         Filter: ((a IS NOT NULL) AND (a < 67))
+         Filter: (a < 67)
    ->  Seq Scan on part_40_inf_cd
-         Filter: ((a IS NOT NULL) AND (a < 67))
+         Filter: (a < 67)
    ->  Seq Scan on part_40_inf_null
-         Filter: ((a IS NOT NULL) AND (a < 67))
-(19 rows)
+         Filter: (a < 67)
+(13 rows)
 
 explain (costs off) select * from range_list_parted where a >= 30;
              QUERY PLAN             
 ------------------------------------
  Append
    ->  Seq Scan on part_40_inf_ab
-         Filter: (a >= 30)
    ->  Seq Scan on part_40_inf_cd
-         Filter: (a >= 30)
    ->  Seq Scan on part_40_inf_null
-         Filter: (a >= 30)
-(7 rows)
+(4 rows)
 
 drop table list_parted;
 drop table range_list_parted;
@@ -1909,7 +1890,7 @@ explain (costs off) select * from mcrparted where a = 10 and abs(b) = 5;	-- scan
    ->  Seq Scan on mcrparted1
          Filter: ((a = 10) AND (abs(b) = 5))
    ->  Seq Scan on mcrparted2
-         Filter: ((a = 10) AND (abs(b) = 5))
+         Filter: (abs(b) = 5)
    ->  Seq Scan on mcrparted_def
          Filter: ((a = 10) AND (abs(b) = 5))
 (7 rows)
@@ -1939,25 +1920,20 @@ explain (costs off) select * from mcrparted where a > -1;	-- scans all partition
    ->  Seq Scan on mcrparted0
          Filter: (a > '-1'::integer)
    ->  Seq Scan on mcrparted1
-         Filter: (a > '-1'::integer)
    ->  Seq Scan on mcrparted2
-         Filter: (a > '-1'::integer)
    ->  Seq Scan on mcrparted3
-         Filter: (a > '-1'::integer)
    ->  Seq Scan on mcrparted4
-         Filter: (a > '-1'::integer)
    ->  Seq Scan on mcrparted5
-         Filter: (a > '-1'::integer)
    ->  Seq Scan on mcrparted_def
          Filter: (a > '-1'::integer)
-(15 rows)
+(10 rows)
 
 explain (costs off) select * from mcrparted where a = 20 and abs(b) = 10 and c > 10;	-- scans mcrparted4
-                        QUERY PLAN                         
------------------------------------------------------------
+                  QUERY PLAN                  
+----------------------------------------------
  Append
    ->  Seq Scan on mcrparted4
-         Filter: ((c > 10) AND (a = 20) AND (abs(b) = 10))
+         Filter: ((c > 10) AND (abs(b) = 10))
 (3 rows)
 
 explain (costs off) select * from mcrparted where a = 20 and c > 20; -- scans mcrparted3, mcrparte4, mcrparte5, mcrparted_def
@@ -1967,7 +1943,7 @@ explain (costs off) select * from mcrparted where a = 20 and c > 20; -- scans mc
    ->  Seq Scan on mcrparted3
          Filter: ((c > 20) AND (a = 20))
    ->  Seq Scan on mcrparted4
-         Filter: ((c > 20) AND (a = 20))
+         Filter: (c > 20)
    ->  Seq Scan on mcrparted5
          Filter: ((c > 20) AND (a = 20))
    ->  Seq Scan on mcrparted_def
@@ -1990,13 +1966,13 @@ explain (costs off) select min(a), max(a) from parted_minmax where b = '12345';
            ->  Merge Append
                  Sort Key: parted_minmax1.a
                  ->  Index Only Scan using parted_minmax1i on parted_minmax1
-                       Index Cond: ((a IS NOT NULL) AND (b = '12345'::text))
+                       Index Cond: (b = '12345'::text)
    InitPlan 2 (returns $1)
      ->  Limit
            ->  Merge Append
                  Sort Key: parted_minmax1_1.a DESC
                  ->  Index Only Scan Backward using parted_minmax1i on parted_minmax1 parted_minmax1_1
-                       Index Cond: ((a IS NOT NULL) AND (b = '12345'::text))
+                       Index Cond: (b = '12345'::text)
 (13 rows)
 
 select min(a), max(a) from parted_minmax where b = '12345';
diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
index 4fccd9a..cfd02d4 100644
--- a/src/test/regress/expected/partition_join.out
+++ b/src/test/regress/expected/partition_join.out
@@ -223,7 +223,7 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JO
          ->  Hash Left Join
                Hash Cond: (prt1_p1.a = b)
                ->  Seq Scan on prt1_p1
-                     Filter: ((a < 450) AND (b = 0))
+                     Filter: (b = 0)
                ->  Hash
                      ->  Result
                            One-Time Filter: false
@@ -261,7 +261,6 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JO
                Hash Cond: (prt1_p1.a = b)
                Filter: ((prt1_p1.b = 0) OR (a = 0))
                ->  Seq Scan on prt1_p1
-                     Filter: (a < 450)
                ->  Hash
                      ->  Result
                            One-Time Filter: false
@@ -277,11 +276,10 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JO
                Hash Cond: (prt2_p3.b = a)
                Filter: ((b = 0) OR (prt2_p3.a = 0))
                ->  Seq Scan on prt2_p3
-                     Filter: (b > 250)
                ->  Hash
                      ->  Result
                            One-Time Filter: false
-(27 rows)
+(25 rows)
 
 SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.b = 0 OR t2.a = 0 ORDER BY t1.a, t2.b;
   a  |  c   |  b  |  c   
@@ -1019,7 +1017,7 @@ SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT *
                ->  Sort
                      Sort Key: prt1_p1.a
                      ->  Seq Scan on prt1_p1
-                           Filter: ((a < 450) AND (b = 0))
+                           Filter: (b = 0)
                ->  Sort
                      Sort Key: b
                      ->  Result
diff --git a/src/test/regress/expected/partition_opt.out b/src/test/regress/expected/partition_opt.out
new file mode 100644
index 0000000..bbebd27
--- /dev/null
+++ b/src/test/regress/expected/partition_opt.out
@@ -0,0 +1,34 @@
+create table bt (k integer, v integer) partition by range (k);
+create table dt1 partition of bt for values from (1) to (10001);
+create table dt2 partition of bt for values from (10001) to (20001);
+create index dti1 on dt1(v);
+create index dti2 on dt2(v);
+insert into bt values (generate_series(1,20000), generate_series(1,20000));
+analyze bt;
+explain (costs off) select * from bt where k between 1 and 20000 and v = 100;
+             QUERY PLAN             
+------------------------------------
+ Append
+   ->  Index Scan using dti1 on dt1
+         Index Cond: (v = 100)
+   ->  Index Scan using dti2 on dt2
+         Index Cond: (v = 100)
+(5 rows)
+
+CREATE TABLE measurement (
+    city_id         int not null,
+    logdate         date not null,
+    peaktemp        int,
+    unitsales       int
+) PARTITION BY RANGE (logdate);
+CREATE TABLE measurement_y2006m03 PARTITION OF measurement
+    FOR VALUES FROM ('2006-03-01') TO ('2006-04-01');
+explain (costs off) select * from measurement where logdate between '2006-03-01' AND '2006-03-31';
+               QUERY PLAN               
+----------------------------------------
+ Append
+   ->  Seq Scan on measurement_y2006m03
+(2 rows)
+
+drop table bt;
+drop table measurement;
diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out
index 0951777..54a2125 100644
--- a/src/test/regress/expected/partition_prune.out
+++ b/src/test/regress/expected/partition_prune.out
@@ -25,22 +25,20 @@ explain (costs off) select * from lp where a > 'a' and a < 'd';
 -----------------------------------------------------------
  Append
    ->  Seq Scan on lp_bc
-         Filter: ((a > 'a'::bpchar) AND (a < 'd'::bpchar))
    ->  Seq Scan on lp_default
          Filter: ((a > 'a'::bpchar) AND (a < 'd'::bpchar))
-(5 rows)
+(4 rows)
 
 explain (costs off) select * from lp where a > 'a' and a <= 'd';
                          QUERY PLAN                         
 ------------------------------------------------------------
  Append
    ->  Seq Scan on lp_ad
-         Filter: ((a > 'a'::bpchar) AND (a <= 'd'::bpchar))
+         Filter: (a > 'a'::bpchar)
    ->  Seq Scan on lp_bc
-         Filter: ((a > 'a'::bpchar) AND (a <= 'd'::bpchar))
    ->  Seq Scan on lp_default
          Filter: ((a > 'a'::bpchar) AND (a <= 'd'::bpchar))
-(7 rows)
+(6 rows)
 
 explain (costs off) select * from lp where a = 'a';
             QUERY PLAN             
@@ -59,28 +57,22 @@ explain (costs off) select * from lp where 'a' = a;	/* commuted */
 (3 rows)
 
 explain (costs off) select * from lp where a is not null;
-           QUERY PLAN            
----------------------------------
+          QUERY PLAN          
+------------------------------
  Append
    ->  Seq Scan on lp_ad
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on lp_bc
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on lp_ef
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on lp_g
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on lp_default
-         Filter: (a IS NOT NULL)
-(11 rows)
+(6 rows)
 
 explain (costs off) select * from lp where a is null;
-         QUERY PLAN          
------------------------------
+        QUERY PLAN         
+---------------------------
  Append
    ->  Seq Scan on lp_null
-         Filter: (a IS NULL)
-(3 rows)
+(2 rows)
 
 explain (costs off) select * from lp where a = 'a' or a = 'c';
                         QUERY PLAN                        
@@ -93,56 +85,44 @@ explain (costs off) select * from lp where a = 'a' or a = 'c';
 (5 rows)
 
 explain (costs off) select * from lp where a is not null and (a = 'a' or a = 'c');
-                                   QUERY PLAN                                   
---------------------------------------------------------------------------------
+                        QUERY PLAN                        
+----------------------------------------------------------
  Append
    ->  Seq Scan on lp_ad
-         Filter: ((a IS NOT NULL) AND ((a = 'a'::bpchar) OR (a = 'c'::bpchar)))
+         Filter: ((a = 'a'::bpchar) OR (a = 'c'::bpchar))
    ->  Seq Scan on lp_bc
-         Filter: ((a IS NOT NULL) AND ((a = 'a'::bpchar) OR (a = 'c'::bpchar)))
+         Filter: ((a = 'a'::bpchar) OR (a = 'c'::bpchar))
 (5 rows)
 
 explain (costs off) select * from lp where a <> 'g';
-             QUERY PLAN             
-------------------------------------
+          QUERY PLAN          
+------------------------------
  Append
    ->  Seq Scan on lp_ad
-         Filter: (a <> 'g'::bpchar)
    ->  Seq Scan on lp_bc
-         Filter: (a <> 'g'::bpchar)
    ->  Seq Scan on lp_ef
-         Filter: (a <> 'g'::bpchar)
    ->  Seq Scan on lp_default
-         Filter: (a <> 'g'::bpchar)
-(9 rows)
+(5 rows)
 
 explain (costs off) select * from lp where a <> 'a' and a <> 'd';
-                         QUERY PLAN                          
--------------------------------------------------------------
+          QUERY PLAN          
+------------------------------
  Append
    ->  Seq Scan on lp_bc
-         Filter: ((a <> 'a'::bpchar) AND (a <> 'd'::bpchar))
    ->  Seq Scan on lp_ef
-         Filter: ((a <> 'a'::bpchar) AND (a <> 'd'::bpchar))
    ->  Seq Scan on lp_g
-         Filter: ((a <> 'a'::bpchar) AND (a <> 'd'::bpchar))
    ->  Seq Scan on lp_default
-         Filter: ((a <> 'a'::bpchar) AND (a <> 'd'::bpchar))
-(9 rows)
+(5 rows)
 
 explain (costs off) select * from lp where a not in ('a', 'd');
-                   QUERY PLAN                   
-------------------------------------------------
+          QUERY PLAN          
+------------------------------
  Append
    ->  Seq Scan on lp_bc
-         Filter: (a <> ALL ('{a,d}'::bpchar[]))
    ->  Seq Scan on lp_ef
-         Filter: (a <> ALL ('{a,d}'::bpchar[]))
    ->  Seq Scan on lp_g
-         Filter: (a <> ALL ('{a,d}'::bpchar[]))
    ->  Seq Scan on lp_default
-         Filter: (a <> ALL ('{a,d}'::bpchar[]))
-(9 rows)
+(5 rows)
 
 -- collation matches the partitioning collation, pruning works
 create table coll_pruning (a text collate "C") partition by list (a);
@@ -150,12 +130,11 @@ create table coll_pruning_a partition of coll_pruning for values in ('a');
 create table coll_pruning_b partition of coll_pruning for values in ('b');
 create table coll_pruning_def partition of coll_pruning default;
 explain (costs off) select * from coll_pruning where a collate "C" = 'a' collate "C";
-                 QUERY PLAN                  
----------------------------------------------
+            QUERY PLAN            
+----------------------------------
  Append
    ->  Seq Scan on coll_pruning_a
-         Filter: (a = 'a'::text COLLATE "C")
-(3 rows)
+(2 rows)
 
 -- collation doesn't match the partitioning collation, no pruning occurs
 explain (costs off) select * from coll_pruning where a collate "POSIX" = 'a' collate "POSIX";
@@ -192,32 +171,29 @@ create table rlp5 partition of rlp for values from (31) to (maxvalue) partition
 create table rlp5_default partition of rlp5 default;
 create table rlp5_1 partition of rlp5 for values from (31) to (40);
 explain (costs off) select * from rlp where a < 1;
-       QUERY PLAN        
--------------------------
+       QUERY PLAN       
+------------------------
  Append
    ->  Seq Scan on rlp1
-         Filter: (a < 1)
-(3 rows)
+(2 rows)
 
 explain (costs off) select * from rlp where 1 > a;	/* commuted */
-       QUERY PLAN        
--------------------------
+       QUERY PLAN       
+------------------------
  Append
    ->  Seq Scan on rlp1
-         Filter: (1 > a)
-(3 rows)
+(2 rows)
 
 explain (costs off) select * from rlp where a <= 1;
               QUERY PLAN               
 ---------------------------------------
  Append
    ->  Seq Scan on rlp1
-         Filter: (a <= 1)
    ->  Seq Scan on rlp2
          Filter: (a <= 1)
    ->  Seq Scan on rlp_default_default
          Filter: (a <= 1)
-(7 rows)
+(6 rows)
 
 explain (costs off) select * from rlp where a = 1;
        QUERY PLAN        
@@ -274,65 +250,47 @@ explain (costs off) select * from rlp where a <= 10;
 ---------------------------------------
  Append
    ->  Seq Scan on rlp1
-         Filter: (a <= 10)
    ->  Seq Scan on rlp2
-         Filter: (a <= 10)
    ->  Seq Scan on rlp_default_10
-         Filter: (a <= 10)
    ->  Seq Scan on rlp_default_default
          Filter: (a <= 10)
-(9 rows)
+(6 rows)
 
 explain (costs off) select * from rlp where a > 10;
               QUERY PLAN               
 ---------------------------------------
  Append
    ->  Seq Scan on rlp3abcd
-         Filter: (a > 10)
    ->  Seq Scan on rlp3efgh
-         Filter: (a > 10)
    ->  Seq Scan on rlp3nullxy
-         Filter: (a > 10)
    ->  Seq Scan on rlp3_default
-         Filter: (a > 10)
    ->  Seq Scan on rlp4_1
-         Filter: (a > 10)
    ->  Seq Scan on rlp4_2
-         Filter: (a > 10)
    ->  Seq Scan on rlp4_default
-         Filter: (a > 10)
    ->  Seq Scan on rlp5_1
-         Filter: (a > 10)
    ->  Seq Scan on rlp5_default
-         Filter: (a > 10)
    ->  Seq Scan on rlp_default_30
-         Filter: (a > 10)
    ->  Seq Scan on rlp_default_default
          Filter: (a > 10)
-(23 rows)
+(13 rows)
 
 explain (costs off) select * from rlp where a < 15;
               QUERY PLAN               
 ---------------------------------------
  Append
    ->  Seq Scan on rlp1
-         Filter: (a < 15)
    ->  Seq Scan on rlp2
-         Filter: (a < 15)
    ->  Seq Scan on rlp_default_10
-         Filter: (a < 15)
    ->  Seq Scan on rlp_default_default
          Filter: (a < 15)
-(9 rows)
+(6 rows)
 
 explain (costs off) select * from rlp where a <= 15;
               QUERY PLAN               
 ---------------------------------------
  Append
    ->  Seq Scan on rlp1
-         Filter: (a <= 15)
    ->  Seq Scan on rlp2
-         Filter: (a <= 15)
    ->  Seq Scan on rlp3abcd
          Filter: (a <= 15)
    ->  Seq Scan on rlp3efgh
@@ -342,10 +300,9 @@ explain (costs off) select * from rlp where a <= 15;
    ->  Seq Scan on rlp3_default
          Filter: (a <= 15)
    ->  Seq Scan on rlp_default_10
-         Filter: (a <= 15)
    ->  Seq Scan on rlp_default_default
          Filter: (a <= 15)
-(17 rows)
+(14 rows)
 
 explain (costs off) select * from rlp where a > 15 and b = 'ab';
                        QUERY PLAN                        
@@ -354,17 +311,17 @@ explain (costs off) select * from rlp where a > 15 and b = 'ab';
    ->  Seq Scan on rlp3abcd
          Filter: ((a > 15) AND ((b)::text = 'ab'::text))
    ->  Seq Scan on rlp4_1
-         Filter: ((a > 15) AND ((b)::text = 'ab'::text))
+         Filter: ((b)::text = 'ab'::text)
    ->  Seq Scan on rlp4_2
-         Filter: ((a > 15) AND ((b)::text = 'ab'::text))
+         Filter: ((b)::text = 'ab'::text)
    ->  Seq Scan on rlp4_default
-         Filter: ((a > 15) AND ((b)::text = 'ab'::text))
+         Filter: ((b)::text = 'ab'::text)
    ->  Seq Scan on rlp5_1
-         Filter: ((a > 15) AND ((b)::text = 'ab'::text))
+         Filter: ((b)::text = 'ab'::text)
    ->  Seq Scan on rlp5_default
-         Filter: ((a > 15) AND ((b)::text = 'ab'::text))
+         Filter: ((b)::text = 'ab'::text)
    ->  Seq Scan on rlp_default_30
-         Filter: ((a > 15) AND ((b)::text = 'ab'::text))
+         Filter: ((b)::text = 'ab'::text)
    ->  Seq Scan on rlp_default_default
          Filter: ((a > 15) AND ((b)::text = 'ab'::text))
 (17 rows)
@@ -422,13 +379,13 @@ explain (costs off) select * from rlp where a = 16 and b is not null;
 ------------------------------------------------
  Append
    ->  Seq Scan on rlp3abcd
-         Filter: ((b IS NOT NULL) AND (a = 16))
+         Filter: (a = 16)
    ->  Seq Scan on rlp3efgh
-         Filter: ((b IS NOT NULL) AND (a = 16))
+         Filter: (a = 16)
    ->  Seq Scan on rlp3nullxy
          Filter: ((b IS NOT NULL) AND (a = 16))
    ->  Seq Scan on rlp3_default
-         Filter: ((b IS NOT NULL) AND (a = 16))
+         Filter: (a = 16)
 (9 rows)
 
 explain (costs off) select * from rlp where a is null;
@@ -436,96 +393,67 @@ explain (costs off) select * from rlp where a is null;
 ------------------------------------
  Append
    ->  Seq Scan on rlp_default_null
-         Filter: (a IS NULL)
-(3 rows)
+(2 rows)
 
 explain (costs off) select * from rlp where a is not null;
               QUERY PLAN               
 ---------------------------------------
  Append
    ->  Seq Scan on rlp1
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on rlp2
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on rlp3abcd
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on rlp3efgh
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on rlp3nullxy
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on rlp3_default
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on rlp4_1
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on rlp4_2
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on rlp4_default
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on rlp5_1
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on rlp5_default
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on rlp_default_10
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on rlp_default_30
-         Filter: (a IS NOT NULL)
    ->  Seq Scan on rlp_default_default
-         Filter: (a IS NOT NULL)
-(29 rows)
+(15 rows)
 
 explain (costs off) select * from rlp where a > 30;
               QUERY PLAN               
 ---------------------------------------
  Append
    ->  Seq Scan on rlp5_1
-         Filter: (a > 30)
    ->  Seq Scan on rlp5_default
-         Filter: (a > 30)
    ->  Seq Scan on rlp_default_default
          Filter: (a > 30)
-(7 rows)
+(5 rows)
 
 explain (costs off) select * from rlp where a = 30;	/* only default is scanned */
             QUERY PLAN            
 ----------------------------------
  Append
    ->  Seq Scan on rlp_default_30
-         Filter: (a = 30)
-(3 rows)
+(2 rows)
 
 explain (costs off) select * from rlp where a <= 31;
               QUERY PLAN               
 ---------------------------------------
  Append
    ->  Seq Scan on rlp1
-         Filter: (a <= 31)
    ->  Seq Scan on rlp2
-         Filter: (a <= 31)
    ->  Seq Scan on rlp3abcd
-         Filter: (a <= 31)
    ->  Seq Scan on rlp3efgh
-         Filter: (a <= 31)
    ->  Seq Scan on rlp3nullxy
-         Filter: (a <= 31)
    ->  Seq Scan on rlp3_default
-         Filter: (a <= 31)
    ->  Seq Scan on rlp4_1
-         Filter: (a <= 31)
    ->  Seq Scan on rlp4_2
-         Filter: (a <= 31)
    ->  Seq Scan on rlp4_default
-         Filter: (a <= 31)
    ->  Seq Scan on rlp5_1
          Filter: (a <= 31)
    ->  Seq Scan on rlp5_default
          Filter: (a <= 31)
    ->  Seq Scan on rlp_default_10
-         Filter: (a <= 31)
    ->  Seq Scan on rlp_default_30
-         Filter: (a <= 31)
    ->  Seq Scan on rlp_default_default
          Filter: (a <= 31)
-(29 rows)
+(18 rows)
 
 explain (costs off) select * from rlp where a = 1 or a = 7;
               QUERY PLAN              
@@ -570,9 +498,9 @@ explain (costs off) select * from rlp where a > 20 and a < 27;
 -----------------------------------------
  Append
    ->  Seq Scan on rlp4_1
-         Filter: ((a > 20) AND (a < 27))
+         Filter: (a > 20)
    ->  Seq Scan on rlp4_2
-         Filter: ((a > 20) AND (a < 27))
+         Filter: (a < 27)
    ->  Seq Scan on rlp4_default
          Filter: ((a > 20) AND (a < 27))
 (7 rows)
@@ -592,51 +520,37 @@ explain (costs off) select * from rlp where a >= 29;
    ->  Seq Scan on rlp4_default
          Filter: (a >= 29)
    ->  Seq Scan on rlp5_1
-         Filter: (a >= 29)
    ->  Seq Scan on rlp5_default
-         Filter: (a >= 29)
    ->  Seq Scan on rlp_default_30
-         Filter: (a >= 29)
    ->  Seq Scan on rlp_default_default
          Filter: (a >= 29)
-(11 rows)
+(8 rows)
 
 -- redundant clauses are eliminated
 explain (costs off) select * from rlp where a > 1 and a = 10;	/* only default */
-               QUERY PLAN               
-----------------------------------------
+            QUERY PLAN            
+----------------------------------
  Append
    ->  Seq Scan on rlp_default_10
-         Filter: ((a > 1) AND (a = 10))
-(3 rows)
+(2 rows)
 
 explain (costs off) select * from rlp where a > 1 and a >=15;	/* rlp3 onwards, including default */
                QUERY PLAN                
 -----------------------------------------
  Append
    ->  Seq Scan on rlp3abcd
-         Filter: ((a > 1) AND (a >= 15))
    ->  Seq Scan on rlp3efgh
-         Filter: ((a > 1) AND (a >= 15))
    ->  Seq Scan on rlp3nullxy
-         Filter: ((a > 1) AND (a >= 15))
    ->  Seq Scan on rlp3_default
-         Filter: ((a > 1) AND (a >= 15))
    ->  Seq Scan on rlp4_1
-         Filter: ((a > 1) AND (a >= 15))
    ->  Seq Scan on rlp4_2
-         Filter: ((a > 1) AND (a >= 15))
    ->  Seq Scan on rlp4_default
-         Filter: ((a > 1) AND (a >= 15))
    ->  Seq Scan on rlp5_1
-         Filter: ((a > 1) AND (a >= 15))
    ->  Seq Scan on rlp5_default
-         Filter: ((a > 1) AND (a >= 15))
    ->  Seq Scan on rlp_default_30
-         Filter: ((a > 1) AND (a >= 15))
    ->  Seq Scan on rlp_default_default
          Filter: ((a > 1) AND (a >= 15))
-(23 rows)
+(13 rows)
 
 explain (costs off) select * from rlp where a = 1 and a = 3;	/* empty */
         QUERY PLAN        
@@ -725,28 +639,23 @@ explain (costs off) select * from mc3p where a = 10 and abs(b) between 5 and 35;
    ->  Seq Scan on mc3p1
          Filter: ((a = 10) AND (abs(b) >= 5) AND (abs(b) <= 35))
    ->  Seq Scan on mc3p2
-         Filter: ((a = 10) AND (abs(b) >= 5) AND (abs(b) <= 35))
    ->  Seq Scan on mc3p3
-         Filter: ((a = 10) AND (abs(b) >= 5) AND (abs(b) <= 35))
    ->  Seq Scan on mc3p4
-         Filter: ((a = 10) AND (abs(b) >= 5) AND (abs(b) <= 35))
+         Filter: (abs(b) <= 35)
    ->  Seq Scan on mc3p_default
          Filter: ((a = 10) AND (abs(b) >= 5) AND (abs(b) <= 35))
-(11 rows)
+(9 rows)
 
 explain (costs off) select * from mc3p where a > 10;
            QUERY PLAN           
 --------------------------------
  Append
    ->  Seq Scan on mc3p5
-         Filter: (a > 10)
    ->  Seq Scan on mc3p6
-         Filter: (a > 10)
    ->  Seq Scan on mc3p7
-         Filter: (a > 10)
    ->  Seq Scan on mc3p_default
          Filter: (a > 10)
-(9 rows)
+(6 rows)
 
 explain (costs off) select * from mc3p where a >= 10;
            QUERY PLAN           
@@ -755,43 +664,36 @@ explain (costs off) select * from mc3p where a >= 10;
    ->  Seq Scan on mc3p1
          Filter: (a >= 10)
    ->  Seq Scan on mc3p2
-         Filter: (a >= 10)
    ->  Seq Scan on mc3p3
-         Filter: (a >= 10)
    ->  Seq Scan on mc3p4
-         Filter: (a >= 10)
    ->  Seq Scan on mc3p5
-         Filter: (a >= 10)
    ->  Seq Scan on mc3p6
-         Filter: (a >= 10)
    ->  Seq Scan on mc3p7
-         Filter: (a >= 10)
    ->  Seq Scan on mc3p_default
          Filter: (a >= 10)
-(17 rows)
+(11 rows)
 
 explain (costs off) select * from mc3p where a < 10;
            QUERY PLAN           
 --------------------------------
  Append
    ->  Seq Scan on mc3p0
-         Filter: (a < 10)
    ->  Seq Scan on mc3p1
          Filter: (a < 10)
    ->  Seq Scan on mc3p_default
          Filter: (a < 10)
-(7 rows)
+(6 rows)
 
 explain (costs off) select * from mc3p where a <= 10 and abs(b) < 10;
                   QUERY PLAN                   
 -----------------------------------------------
  Append
    ->  Seq Scan on mc3p0
-         Filter: ((a <= 10) AND (abs(b) < 10))
+         Filter: (abs(b) < 10)
    ->  Seq Scan on mc3p1
-         Filter: ((a <= 10) AND (abs(b) < 10))
+         Filter: (abs(b) < 10)
    ->  Seq Scan on mc3p2
-         Filter: ((a <= 10) AND (abs(b) < 10))
+         Filter: (abs(b) < 10)
    ->  Seq Scan on mc3p_default
          Filter: ((a <= 10) AND (abs(b) < 10))
 (9 rows)
@@ -805,11 +707,11 @@ explain (costs off) select * from mc3p where a = 11 and abs(b) = 0;
 (3 rows)
 
 explain (costs off) select * from mc3p where a = 20 and abs(b) = 10 and c = 100;
-                         QUERY PLAN                         
-------------------------------------------------------------
+                  QUERY PLAN                   
+-----------------------------------------------
  Append
    ->  Seq Scan on mc3p6
-         Filter: ((a = 20) AND (c = 100) AND (abs(b) = 10))
+         Filter: ((c = 100) AND (abs(b) = 10))
 (3 rows)
 
 explain (costs off) select * from mc3p where a > 20;
@@ -829,12 +731,10 @@ explain (costs off) select * from mc3p where a >= 20;
    ->  Seq Scan on mc3p5
          Filter: (a >= 20)
    ->  Seq Scan on mc3p6
-         Filter: (a >= 20)
    ->  Seq Scan on mc3p7
-         Filter: (a >= 20)
    ->  Seq Scan on mc3p_default
          Filter: (a >= 20)
-(9 rows)
+(7 rows)
 
 explain (costs off) select * from mc3p where (a = 1 and abs(b) = 1 and c = 1) or (a = 10 and abs(b) = 5 and c = 10) or (a > 11 and a < 20);
                                                            QUERY PLAN                                                            
@@ -871,7 +771,6 @@ explain (costs off) select * from mc3p where (a = 1 and abs(b) = 1 and c = 1) or
 -------------------------------------------------------------------------------------------------------------------------------------------------------
  Append
    ->  Seq Scan on mc3p0
-         Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a < 20)) OR (a < 1) OR (a = 1))
    ->  Seq Scan on mc3p1
          Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a < 20)) OR (a < 1) OR (a = 1))
    ->  Seq Scan on mc3p2
@@ -880,7 +779,7 @@ explain (costs off) select * from mc3p where (a = 1 and abs(b) = 1 and c = 1) or
          Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a < 20)) OR (a < 1) OR (a = 1))
    ->  Seq Scan on mc3p_default
          Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a < 20)) OR (a < 1) OR (a = 1))
-(11 rows)
+(10 rows)
 
 explain (costs off) select * from mc3p where a = 1 or abs(b) = 1 or c = 1;
                       QUERY PLAN                      
@@ -915,12 +814,11 @@ explain (costs off) select * from mc3p where (a = 1 and abs(b) = 1) or (a = 10 a
    ->  Seq Scan on mc3p2
          Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 10)))
    ->  Seq Scan on mc3p3
-         Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 10)))
    ->  Seq Scan on mc3p4
          Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 10)))
    ->  Seq Scan on mc3p_default
          Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 10)))
-(13 rows)
+(12 rows)
 
 explain (costs off) select * from mc3p where (a = 1 and abs(b) = 1) or (a = 10 and abs(b) = 9);
                                  QUERY PLAN                                  
@@ -950,22 +848,18 @@ explain (costs off) select * from mc2p where a < 2;
 --------------------------------
  Append
    ->  Seq Scan on mc2p0
-         Filter: (a < 2)
    ->  Seq Scan on mc2p1
-         Filter: (a < 2)
    ->  Seq Scan on mc2p2
-         Filter: (a < 2)
    ->  Seq Scan on mc2p_default
          Filter: (a < 2)
-(9 rows)
+(6 rows)
 
 explain (costs off) select * from mc2p where a = 2 and b < 1;
-              QUERY PLAN               
----------------------------------------
+       QUERY PLAN        
+-------------------------
  Append
    ->  Seq Scan on mc2p3
-         Filter: ((b < 1) AND (a = 2))
-(3 rows)
+(2 rows)
 
 explain (costs off) select * from mc2p where a > 1;
            QUERY PLAN           
@@ -974,14 +868,11 @@ explain (costs off) select * from mc2p where a > 1;
    ->  Seq Scan on mc2p2
          Filter: (a > 1)
    ->  Seq Scan on mc2p3
-         Filter: (a > 1)
    ->  Seq Scan on mc2p4
-         Filter: (a > 1)
    ->  Seq Scan on mc2p5
-         Filter: (a > 1)
    ->  Seq Scan on mc2p_default
          Filter: (a > 1)
-(11 rows)
+(8 rows)
 
 explain (costs off) select * from mc2p where a = 1 and b > 1;
               QUERY PLAN               
@@ -1011,20 +902,18 @@ explain (costs off) select * from boolpart where a = false;
 ------------------------------------
  Append
    ->  Seq Scan on boolpart_f
-         Filter: (NOT a)
    ->  Seq Scan on boolpart_default
          Filter: (NOT a)
-(5 rows)
+(4 rows)
 
 explain (costs off) select * from boolpart where not a = false;
              QUERY PLAN             
 ------------------------------------
  Append
    ->  Seq Scan on boolpart_t
-         Filter: a
    ->  Seq Scan on boolpart_default
          Filter: a
-(5 rows)
+(4 rows)
 
 explain (costs off) select * from boolpart where a is true or a is not true;
                     QUERY PLAN                    
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index f1ae40d..b9565d5 100644
--- a/src/test/regress/expected/rowsecurity.out
+++ b/src/test/regress/expected/rowsecurity.out
@@ -1057,14 +1057,14 @@ NOTICE:  f_leak => awesome science fiction
 (4 rows)
 
 EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
-                             QUERY PLAN                             
---------------------------------------------------------------------
+                     QUERY PLAN                      
+-----------------------------------------------------
  Append
    InitPlan 1 (returns $0)
      ->  Index Scan using uaccount_pkey on uaccount
            Index Cond: (pguser = CURRENT_USER)
    ->  Seq Scan on part_document_fiction
-         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
+         Filter: ((dlevel <= $0) AND f_leak(dtitle))
 (6 rows)
 
 -- pp1 ERROR
@@ -1136,14 +1136,14 @@ NOTICE:  f_leak => awesome science fiction
 (4 rows)
 
 EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
-                             QUERY PLAN                             
---------------------------------------------------------------------
+                     QUERY PLAN                      
+-----------------------------------------------------
  Append
    InitPlan 1 (returns $0)
      ->  Index Scan using uaccount_pkey on uaccount
            Index Cond: (pguser = CURRENT_USER)
    ->  Seq Scan on part_document_fiction
-         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
+         Filter: ((dlevel <= $0) AND f_leak(dtitle))
 (6 rows)
 
 -- viewpoint from regress_rls_carol
diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out
index d09326c..8253534 100644
--- a/src/test/regress/expected/update.out
+++ b/src/test/regress/expected/update.out
@@ -275,12 +275,10 @@ EXPLAIN (costs off) UPDATE range_parted set c = c - 50 WHERE c > 97;
    ->  Seq Scan on part_c_1_100
          Filter: (c > '97'::numeric)
    ->  Seq Scan on part_d_1_15
-         Filter: (c > '97'::numeric)
    ->  Seq Scan on part_d_15_20
-         Filter: (c > '97'::numeric)
    ->  Seq Scan on part_b_20_b_30
          Filter: (c > '97'::numeric)
-(22 rows)
+(20 rows)
 
 -- fail, row movement happens only within the partition subtree.
 UPDATE part_c_100_200 set c = c - 20, d = c WHERE c = 105;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index ad9434f..c99df34 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -116,7 +116,7 @@ test: plancache limit plpgsql copy2 temp domain rangefuncs prepare without_oid c
 # ----------
 # Another group of parallel tests
 # ----------
-test: identity partition_join partition_prune reloptions hash_part indexing
+test: identity partition_join partition_prune reloptions hash_part indexing partition_opt
 
 # event triggers cannot run concurrently with any test that runs DDL
 test: event_trigger
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 27cd498..15ced95 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -182,6 +182,7 @@ test: xml
 test: identity
 test: partition_join
 test: partition_prune
+test: partition_opt
 test: reloptions
 test: hash_part
 test: indexing
diff --git a/src/test/regress/sql/partition_opt.sql b/src/test/regress/sql/partition_opt.sql
new file mode 100644
index 0000000..d29472e
--- /dev/null
+++ b/src/test/regress/sql/partition_opt.sql
@@ -0,0 +1,24 @@
+create table bt (k integer, v integer) partition by range (k);
+create table dt1 partition of bt for values from (1) to (10001);
+create table dt2 partition of bt for values from (10001) to (20001);
+create index dti1 on dt1(v);
+create index dti2 on dt2(v);
+insert into bt values (generate_series(1,20000), generate_series(1,20000));
+analyze bt;
+explain (costs off) select * from bt where k between 1 and 20000 and v = 100;
+
+CREATE TABLE measurement (
+    city_id         int not null,
+    logdate         date not null,
+    peaktemp        int,
+    unitsales       int
+) PARTITION BY RANGE (logdate);
+
+
+CREATE TABLE measurement_y2006m03 PARTITION OF measurement
+    FOR VALUES FROM ('2006-03-01') TO ('2006-04-01');
+
+explain (costs off) select * from measurement where logdate between '2006-03-01' AND '2006-03-31';
+
+drop table bt;
+drop table measurement;
\set x random(1, 100000)
select * from base where k between 1 and 20000 and v = :x

Attachment: init.sql
Description: application/sql

Reply via email to