diff options
-rw-r--r-- | src/backend/optimizer/util/plancat.c | 46 | ||||
-rw-r--r-- | src/test/regress/expected/predicate.out | 27 | ||||
-rw-r--r-- | src/test/regress/sql/predicate.sql | 20 |
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; |