* 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.
+ *
+ * After fixing the varnos, we need to run the index expressions
+ * and predicate through const-simplification again, using a valid
+ * "root". This ensures that NullTest quals for Vars can be
+ * properly reduced.
*/
info->indexprs = RelationGetIndexExpressions(indexRelation);
info->indpred = RelationGetIndexPredicate(indexRelation);
- if (info->indexprs && varno != 1)
- ChangeVarNodes((Node *) info->indexprs, 1, varno, 0);
- if (info->indpred && varno != 1)
- ChangeVarNodes((Node *) info->indpred, 1, varno, 0);
+ if (info->indexprs)
+ {
+ if (varno != 1)
+ ChangeVarNodes((Node *) info->indexprs, 1, varno, 0);
+
+ info->indexprs = (List *)
+ eval_const_expressions(root, (Node *) info->indexprs);
+ }
+ if (info->indpred)
+ {
+ if (varno != 1)
+ ChangeVarNodes((Node *) info->indpred, 1, varno, 0);
+
+ info->indpred = (List *)
+ eval_const_expressions(root,
+ (Node *) make_ands_explicit(info->indpred));
+ info->indpred = make_ands_implicit((Expr *) info->indpred);
+ }
/* Build targetlist using the completed indexprs data */
info->indextlist = build_index_tlist(root, info, relation);
/* Expression attributes (if any) must match */
idxExprs = RelationGetIndexExpressions(idxRel);
- if (idxExprs && varno != 1)
- ChangeVarNodes((Node *) idxExprs, 1, varno, 0);
+ if (idxExprs)
+ {
+ if (varno != 1)
+ ChangeVarNodes((Node *) idxExprs, 1, varno, 0);
+
+ idxExprs = (List *) eval_const_expressions(root, (Node *) idxExprs);
+ }
/*
* If arbiterElems are present, check them. (Note that if a
continue;
predExprs = RelationGetIndexPredicate(idxRel);
- if (predExprs && varno != 1)
- ChangeVarNodes((Node *) predExprs, 1, varno, 0);
+ if (predExprs)
+ {
+ if (varno != 1)
+ ChangeVarNodes((Node *) predExprs, 1, varno, 0);
+
+ predExprs = (List *)
+ eval_const_expressions(root,
+ (Node *) make_ands_explicit(predExprs));
+ predExprs = make_ands_implicit((Expr *) predExprs);
+ }
/*
* Partial indexes affect each form of ON CONFLICT differently: if a
RESET constraint_exclusion;
DROP TABLE pred_tab1;
DROP TABLE pred_tab2;
+-- Validate that NullTest quals in index expressions and predicate are reduced correctly
+CREATE TABLE pred_tab (a int, b int NOT NULL, c int NOT NULL);
+INSERT INTO pred_tab SELECT i, i, i FROM generate_series(1, 1000) i;
+CREATE INDEX pred_tab_exprs_idx ON pred_tab ((a < 5 AND b IS NOT NULL AND c IS NOT NULL));
+CREATE INDEX pred_tab_pred_idx ON pred_tab (a) WHERE b IS NOT NULL AND c IS NOT NULL;
+ANALYZE pred_tab;
+-- Ensure that index pred_tab_exprs_idx is used
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab WHERE (a < 5 AND b IS NOT NULL AND c IS NOT NULL) IS TRUE;
+ QUERY PLAN
+-------------------------------------------------
+ Index Scan using pred_tab_exprs_idx on pred_tab
+ Index Cond: ((a < 5) = true)
+(2 rows)
+
+SELECT * FROM pred_tab WHERE (a < 5 AND b IS NOT NULL AND c IS NOT NULL) IS TRUE;
+ a | b | c
+---+---+---
+ 1 | 1 | 1
+ 2 | 2 | 2
+ 3 | 3 | 3
+ 4 | 4 | 4
+(4 rows)
+
+-- Ensure that index pred_tab_pred_idx is used
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab WHERE a < 3 AND b IS NOT NULL AND c IS NOT NULL;
+ QUERY PLAN
+------------------------------------------------
+ Index Scan using pred_tab_pred_idx on pred_tab
+ Index Cond: (a < 3)
+(2 rows)
+
+SELECT * FROM pred_tab WHERE a < 3 AND b IS NOT NULL AND c IS NOT NULL;
+ a | b | c
+---+---+---
+ 1 | 1 | 1
+ 2 | 2 | 2
+(2 rows)
+
+DROP TABLE pred_tab;
RESET constraint_exclusion;
DROP TABLE pred_tab1;
DROP TABLE pred_tab2;
+
+-- Validate that NullTest quals in index expressions and predicate are reduced correctly
+CREATE TABLE pred_tab (a int, b int NOT NULL, c int NOT NULL);
+INSERT INTO pred_tab SELECT i, i, i FROM generate_series(1, 1000) i;
+CREATE INDEX pred_tab_exprs_idx ON pred_tab ((a < 5 AND b IS NOT NULL AND c IS NOT NULL));
+CREATE INDEX pred_tab_pred_idx ON pred_tab (a) WHERE b IS NOT NULL AND c IS NOT NULL;
+ANALYZE pred_tab;
+
+-- Ensure that index pred_tab_exprs_idx is used
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab WHERE (a < 5 AND b IS NOT NULL AND c IS NOT NULL) IS TRUE;
+SELECT * FROM pred_tab WHERE (a < 5 AND b IS NOT NULL AND c IS NOT NULL) IS TRUE;
+
+-- Ensure that index pred_tab_pred_idx is used
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab WHERE a < 3 AND b IS NOT NULL AND c IS NOT NULL;
+SELECT * FROM pred_tab WHERE a < 3 AND b IS NOT NULL AND c IS NOT NULL;
+
+DROP TABLE pred_tab;