summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/optimizer/util/plancat.c46
-rw-r--r--src/test/regress/expected/predicate.out27
-rw-r--r--src/test/regress/sql/predicate.sql20
3 files changed, 75 insertions, 18 deletions
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 6ce4efea118..4536bdd6cb4 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -77,7 +77,8 @@ static List *get_relation_constraints(PlannerInfo *root,
bool include_partition);
static List *build_index_tlist(PlannerInfo *root, IndexOptInfo *index,
Relation heapRelation);
-static List *get_relation_statistics(RelOptInfo *rel, Relation relation);
+static List *get_relation_statistics(PlannerInfo *root, RelOptInfo *rel,
+ Relation relation);
static void set_relation_partition_info(PlannerInfo *root, RelOptInfo *rel,
Relation relation);
static PartitionScheme find_partition_scheme(PlannerInfo *root,
@@ -508,7 +509,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
rel->indexlist = indexinfos;
- rel->statlist = get_relation_statistics(rel, relation);
+ rel->statlist = get_relation_statistics(root, rel, relation);
/* Grab foreign-table info using the relcache, while we have it */
if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
@@ -1407,6 +1408,14 @@ get_relation_constraints(PlannerInfo *root,
cexpr = stringToNode(constr->check[i].ccbin);
/*
+ * Fix Vars to have the desired varno. This must be done before
+ * const-simplification because eval_const_expressions reduces
+ * NullTest for Vars based on varno.
+ */
+ if (varno != 1)
+ ChangeVarNodes(cexpr, 1, varno, 0);
+
+ /*
* Run each expression through const-simplification and
* canonicalization. This is not just an optimization, but is
* necessary, because we will be comparing it to
@@ -1420,10 +1429,6 @@ get_relation_constraints(PlannerInfo *root,
cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true);
- /* Fix Vars to have the desired varno */
- if (varno != 1)
- ChangeVarNodes(cexpr, 1, varno, 0);
-
/*
* Finally, convert to implicit-AND format (that is, a List) and
* append the resulting item(s) to our output list.
@@ -1572,7 +1577,8 @@ get_relation_statistics_worker(List **stainfos, RelOptInfo *rel,
* just the identifying metadata. Only stats actually built are considered.
*/
static List *
-get_relation_statistics(RelOptInfo *rel, Relation relation)
+get_relation_statistics(PlannerInfo *root, RelOptInfo *rel,
+ Relation relation)
{
Index varno = rel->relid;
List *statoidlist;
@@ -1604,8 +1610,8 @@ get_relation_statistics(RelOptInfo *rel, Relation relation)
keys = bms_add_member(keys, staForm->stxkeys.values[i]);
/*
- * Preprocess expressions (if any). We read the expressions, run them
- * through eval_const_expressions, and fix the varnos.
+ * Preprocess expressions (if any). We read the expressions, fix the
+ * varnos, and run them through eval_const_expressions.
*
* XXX We don't know yet if there are any data for this stats object,
* with either stxdinherit value. But it's reasonable to assume there
@@ -1629,6 +1635,18 @@ get_relation_statistics(RelOptInfo *rel, Relation relation)
pfree(exprsString);
/*
+ * Modify the copies we obtain from the relcache to have the
+ * correct varno for the parent relation, so that they match
+ * up correctly against qual clauses.
+ *
+ * This must be done before const-simplification because
+ * eval_const_expressions reduces NullTest for Vars based on
+ * varno.
+ */
+ if (varno != 1)
+ ChangeVarNodes((Node *) exprs, 1, varno, 0);
+
+ /*
* Run the expressions through eval_const_expressions. This is
* not just an optimization, but is necessary, because the
* planner will be comparing them to similarly-processed qual
@@ -1636,18 +1654,10 @@ get_relation_statistics(RelOptInfo *rel, Relation relation)
* We must not use canonicalize_qual, however, since these
* aren't qual expressions.
*/
- exprs = (List *) eval_const_expressions(NULL, (Node *) exprs);
+ exprs = (List *) eval_const_expressions(root, (Node *) exprs);
/* May as well fix opfuncids too */
fix_opfuncids((Node *) exprs);
-
- /*
- * Modify the copies we obtain from the relcache to have the
- * correct varno for the parent relation, so that they match
- * up correctly against qual clauses.
- */
- if (varno != 1)
- ChangeVarNodes((Node *) exprs, 1, varno, 0);
}
}
diff --git a/src/test/regress/expected/predicate.out b/src/test/regress/expected/predicate.out
index 59bfe33bb1c..1aff0b59ff8 100644
--- a/src/test/regress/expected/predicate.out
+++ b/src/test/regress/expected/predicate.out
@@ -409,3 +409,30 @@ SELECT * FROM pred_tab t1
DROP TABLE pred_tab;
DROP TABLE pred_tab_notnull;
+-- Validate that NullTest quals in constraint expressions are reduced correctly
+CREATE TABLE pred_tab1 (a int NOT NULL, b int,
+ CONSTRAINT check_tab1 CHECK (a IS NULL OR b > 2));
+CREATE TABLE pred_tab2 (a int, b int,
+ CONSTRAINT check_a CHECK (a IS NOT NULL));
+SET constraint_exclusion TO ON;
+-- Ensure that we get a dummy plan
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab1, pred_tab2 WHERE pred_tab2.a IS NULL;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+-- Ensure that we get a dummy plan
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab2, pred_tab1 WHERE pred_tab1.a IS NULL OR pred_tab1.b < 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+RESET constraint_exclusion;
+DROP TABLE pred_tab1;
+DROP TABLE pred_tab2;
diff --git a/src/test/regress/sql/predicate.sql b/src/test/regress/sql/predicate.sql
index d92277353a0..32302d60b6d 100644
--- a/src/test/regress/sql/predicate.sql
+++ b/src/test/regress/sql/predicate.sql
@@ -201,3 +201,23 @@ SELECT * FROM pred_tab t1
DROP TABLE pred_tab;
DROP TABLE pred_tab_notnull;
+
+-- Validate that NullTest quals in constraint expressions are reduced correctly
+CREATE TABLE pred_tab1 (a int NOT NULL, b int,
+ CONSTRAINT check_tab1 CHECK (a IS NULL OR b > 2));
+CREATE TABLE pred_tab2 (a int, b int,
+ CONSTRAINT check_a CHECK (a IS NOT NULL));
+
+SET constraint_exclusion TO ON;
+
+-- Ensure that we get a dummy plan
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab1, pred_tab2 WHERE pred_tab2.a IS NULL;
+
+-- Ensure that we get a dummy plan
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab2, pred_tab1 WHERE pred_tab1.a IS NULL OR pred_tab1.b < 2;
+
+RESET constraint_exclusion;
+DROP TABLE pred_tab1;
+DROP TABLE pred_tab2;