diff options
Diffstat (limited to 'src/backend/optimizer/util/predtest.c')
-rw-r--r-- | src/backend/optimizer/util/predtest.c | 152 |
1 files changed, 97 insertions, 55 deletions
diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index c4a04cfa95..06fce8458c 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -77,8 +77,10 @@ typedef struct PredIterInfoData } while (0) -static bool predicate_implied_by_recurse(Node *clause, Node *predicate); -static bool predicate_refuted_by_recurse(Node *clause, Node *predicate); +static bool predicate_implied_by_recurse(Node *clause, Node *predicate, + bool clause_is_check); +static bool predicate_refuted_by_recurse(Node *clause, Node *predicate, + bool clause_is_check); static PredClass predicate_classify(Node *clause, PredIterInfo info); static void list_startup_fn(Node *clause, PredIterInfo info); static Node *list_next_fn(PredIterInfo info); @@ -90,8 +92,10 @@ static void arrayconst_cleanup_fn(PredIterInfo info); static void arrayexpr_startup_fn(Node *clause, PredIterInfo info); static Node *arrayexpr_next_fn(PredIterInfo info); static void arrayexpr_cleanup_fn(PredIterInfo info); -static bool predicate_implied_by_simple_clause(Expr *predicate, Node *clause); -static bool predicate_refuted_by_simple_clause(Expr *predicate, Node *clause); +static bool predicate_implied_by_simple_clause(Expr *predicate, Node *clause, + bool clause_is_check); +static bool predicate_refuted_by_simple_clause(Expr *predicate, Node *clause, + bool clause_is_check); static Node *extract_not_arg(Node *clause); static Node *extract_strong_not_arg(Node *clause); static bool list_member_strip(List *list, Expr *datum); @@ -107,8 +111,11 @@ static void InvalidateOprProofCacheCallBack(Datum arg, int cacheid, uint32 hashv /* * predicate_implied_by - * Recursively checks whether the clauses in restrictinfo_list imply - * that the given predicate is true. + * Recursively checks whether the clauses in clause_list imply that the + * given predicate is true. If clause_is_check is true, assume that the + * clauses in clause_list are CHECK constraints (where null is + * effectively true) rather than WHERE clauses (where null is effectively + * false). * * The top-level List structure of each list corresponds to an AND list. * We assume that eval_const_expressions() has been applied and so there @@ -125,14 +132,15 @@ static void InvalidateOprProofCacheCallBack(Datum arg, int cacheid, uint32 hashv * the plan and the time we execute the plan. */ bool -predicate_implied_by(List *predicate_list, List *restrictinfo_list) +predicate_implied_by(List *predicate_list, List *clause_list, + bool clause_is_check) { Node *p, *r; if (predicate_list == NIL) return true; /* no predicate: implication is vacuous */ - if (restrictinfo_list == NIL) + if (clause_list == NIL) return false; /* no restriction: implication must fail */ /* @@ -145,19 +153,22 @@ predicate_implied_by(List *predicate_list, List *restrictinfo_list) p = (Node *) linitial(predicate_list); else p = (Node *) predicate_list; - if (list_length(restrictinfo_list) == 1) - r = (Node *) linitial(restrictinfo_list); + if (list_length(clause_list) == 1) + r = (Node *) linitial(clause_list); else - r = (Node *) restrictinfo_list; + r = (Node *) clause_list; /* And away we go ... */ - return predicate_implied_by_recurse(r, p); + return predicate_implied_by_recurse(r, p, clause_is_check); } /* * predicate_refuted_by - * Recursively checks whether the clauses in restrictinfo_list refute - * the given predicate (that is, prove it false). + * Recursively checks whether the clauses in clause_list refute the given + * predicate (that is, prove it false). If clause_is_check is true, assume + * that the clauses in clause_list are CHECK constraints (where null is + * effectively true) rather than WHERE clauses (where null is effectively + * false). * * This is NOT the same as !(predicate_implied_by), though it is similar * in the technique and structure of the code. @@ -183,14 +194,15 @@ predicate_implied_by(List *predicate_list, List *restrictinfo_list) * time we make the plan and the time we execute the plan. */ bool -predicate_refuted_by(List *predicate_list, List *restrictinfo_list) +predicate_refuted_by(List *predicate_list, List *clause_list, + bool clause_is_check) { Node *p, *r; if (predicate_list == NIL) return false; /* no predicate: no refutation is possible */ - if (restrictinfo_list == NIL) + if (clause_list == NIL) return false; /* no restriction: refutation must fail */ /* @@ -203,13 +215,13 @@ predicate_refuted_by(List *predicate_list, List *restrictinfo_list) p = (Node *) linitial(predicate_list); else p = (Node *) predicate_list; - if (list_length(restrictinfo_list) == 1) - r = (Node *) linitial(restrictinfo_list); + if (list_length(clause_list) == 1) + r = (Node *) linitial(clause_list); else - r = (Node *) restrictinfo_list; + r = (Node *) clause_list; /* And away we go ... */ - return predicate_refuted_by_recurse(r, p); + return predicate_refuted_by_recurse(r, p, clause_is_check); } /*---------- @@ -248,7 +260,8 @@ predicate_refuted_by(List *predicate_list, List *restrictinfo_list) *---------- */ static bool -predicate_implied_by_recurse(Node *clause, Node *predicate) +predicate_implied_by_recurse(Node *clause, Node *predicate, + bool clause_is_check) { PredIterInfoData clause_info; PredIterInfoData pred_info; @@ -275,7 +288,8 @@ predicate_implied_by_recurse(Node *clause, Node *predicate) result = true; iterate_begin(pitem, predicate, pred_info) { - if (!predicate_implied_by_recurse(clause, pitem)) + if (!predicate_implied_by_recurse(clause, pitem, + clause_is_check)) { result = false; break; @@ -294,7 +308,8 @@ predicate_implied_by_recurse(Node *clause, Node *predicate) result = false; iterate_begin(pitem, predicate, pred_info) { - if (predicate_implied_by_recurse(clause, pitem)) + if (predicate_implied_by_recurse(clause, pitem, + clause_is_check)) { result = true; break; @@ -311,7 +326,8 @@ predicate_implied_by_recurse(Node *clause, Node *predicate) */ iterate_begin(citem, clause, clause_info) { - if (predicate_implied_by_recurse(citem, predicate)) + if (predicate_implied_by_recurse(citem, predicate, + clause_is_check)) { result = true; break; @@ -328,7 +344,8 @@ predicate_implied_by_recurse(Node *clause, Node *predicate) result = false; iterate_begin(citem, clause, clause_info) { - if (predicate_implied_by_recurse(citem, predicate)) + if (predicate_implied_by_recurse(citem, predicate, + clause_is_check)) { result = true; break; @@ -355,7 +372,8 @@ predicate_implied_by_recurse(Node *clause, Node *predicate) iterate_begin(pitem, predicate, pred_info) { - if (predicate_implied_by_recurse(citem, pitem)) + if (predicate_implied_by_recurse(citem, pitem, + clause_is_check)) { presult = true; break; @@ -382,7 +400,8 @@ predicate_implied_by_recurse(Node *clause, Node *predicate) result = true; iterate_begin(citem, clause, clause_info) { - if (!predicate_implied_by_recurse(citem, predicate)) + if (!predicate_implied_by_recurse(citem, predicate, + clause_is_check)) { result = false; break; @@ -404,7 +423,8 @@ predicate_implied_by_recurse(Node *clause, Node *predicate) result = true; iterate_begin(pitem, predicate, pred_info) { - if (!predicate_implied_by_recurse(clause, pitem)) + if (!predicate_implied_by_recurse(clause, pitem, + clause_is_check)) { result = false; break; @@ -421,7 +441,8 @@ predicate_implied_by_recurse(Node *clause, Node *predicate) result = false; iterate_begin(pitem, predicate, pred_info) { - if (predicate_implied_by_recurse(clause, pitem)) + if (predicate_implied_by_recurse(clause, pitem, + clause_is_check)) { result = true; break; @@ -437,7 +458,8 @@ predicate_implied_by_recurse(Node *clause, Node *predicate) */ return predicate_implied_by_simple_clause((Expr *) predicate, - clause); + clause, + clause_is_check); } break; } @@ -478,7 +500,8 @@ predicate_implied_by_recurse(Node *clause, Node *predicate) *---------- */ static bool -predicate_refuted_by_recurse(Node *clause, Node *predicate) +predicate_refuted_by_recurse(Node *clause, Node *predicate, + bool clause_is_check) { PredIterInfoData clause_info; PredIterInfoData pred_info; @@ -508,7 +531,8 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate) result = false; iterate_begin(pitem, predicate, pred_info) { - if (predicate_refuted_by_recurse(clause, pitem)) + if (predicate_refuted_by_recurse(clause, pitem, + clause_is_check)) { result = true; break; @@ -525,7 +549,8 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate) */ iterate_begin(citem, clause, clause_info) { - if (predicate_refuted_by_recurse(citem, predicate)) + if (predicate_refuted_by_recurse(citem, predicate, + clause_is_check)) { result = true; break; @@ -542,7 +567,8 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate) result = true; iterate_begin(pitem, predicate, pred_info) { - if (!predicate_refuted_by_recurse(clause, pitem)) + if (!predicate_refuted_by_recurse(clause, pitem, + clause_is_check)) { result = false; break; @@ -558,7 +584,8 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate) */ not_arg = extract_not_arg(predicate); if (not_arg && - predicate_implied_by_recurse(clause, not_arg)) + predicate_implied_by_recurse(clause, not_arg, + clause_is_check)) return true; /* @@ -567,7 +594,8 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate) result = false; iterate_begin(citem, clause, clause_info) { - if (predicate_refuted_by_recurse(citem, predicate)) + if (predicate_refuted_by_recurse(citem, predicate, + clause_is_check)) { result = true; break; @@ -589,7 +617,8 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate) result = true; iterate_begin(pitem, predicate, pred_info) { - if (!predicate_refuted_by_recurse(clause, pitem)) + if (!predicate_refuted_by_recurse(clause, pitem, + clause_is_check)) { result = false; break; @@ -611,7 +640,8 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate) iterate_begin(pitem, predicate, pred_info) { - if (predicate_refuted_by_recurse(citem, pitem)) + if (predicate_refuted_by_recurse(citem, pitem, + clause_is_check)) { presult = true; break; @@ -634,7 +664,8 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate) */ not_arg = extract_not_arg(predicate); if (not_arg && - predicate_implied_by_recurse(clause, not_arg)) + predicate_implied_by_recurse(clause, not_arg, + clause_is_check)) return true; /* @@ -643,7 +674,8 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate) result = true; iterate_begin(citem, clause, clause_info) { - if (!predicate_refuted_by_recurse(citem, predicate)) + if (!predicate_refuted_by_recurse(citem, predicate, + clause_is_check)) { result = false; break; @@ -679,7 +711,8 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate) result = false; iterate_begin(pitem, predicate, pred_info) { - if (predicate_refuted_by_recurse(clause, pitem)) + if (predicate_refuted_by_recurse(clause, pitem, + clause_is_check)) { result = true; break; @@ -696,7 +729,8 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate) result = true; iterate_begin(pitem, predicate, pred_info) { - if (!predicate_refuted_by_recurse(clause, pitem)) + if (!predicate_refuted_by_recurse(clause, pitem, + clause_is_check)) { result = false; break; @@ -712,7 +746,8 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate) */ not_arg = extract_not_arg(predicate); if (not_arg && - predicate_implied_by_recurse(clause, not_arg)) + predicate_implied_by_recurse(clause, not_arg, + clause_is_check)) return true; /* @@ -720,7 +755,8 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate) */ return predicate_refuted_by_simple_clause((Expr *) predicate, - clause); + clause, + clause_is_check); } break; } @@ -1022,14 +1058,15 @@ arrayexpr_cleanup_fn(PredIterInfo info) * functions in the expression are immutable, ie dependent only on their input * arguments --- but this was checked for the predicate by the caller.) * - * When the predicate is of the form "foo IS NOT NULL", we can conclude that - * the predicate is implied if the clause is a strict operator or function - * that has "foo" as an input. In this case the clause must yield NULL when - * "foo" is NULL, which we can take as equivalent to FALSE because we know - * we are within an AND/OR subtree of a WHERE clause. (Again, "foo" is - * already known immutable, so the clause will certainly always fail.) - * Also, if the clause is just "foo" (meaning it's a boolean variable), - * the predicate is implied since the clause can't be true if "foo" is NULL. + * When clause_is_check is false, we know we are within an AND/OR + * subtree of a WHERE clause. So, if the predicate is of the form "foo IS + * NOT NULL", we can conclude that the predicate is implied if the clause is + * a strict operator or function that has "foo" as an input. In this case + * the clause must yield NULL when "foo" is NULL, which we can take as + * equivalent to FALSE given the context. (Again, "foo" is already known + * immutable, so the clause will certainly always fail.) Also, if the clause + * is just "foo" (meaning it's a boolean variable), the predicate is implied + * since the clause can't be true if "foo" is NULL. * * Finally, if both clauses are binary operator expressions, we may be able * to prove something using the system's knowledge about operators; those @@ -1037,7 +1074,8 @@ arrayexpr_cleanup_fn(PredIterInfo info) *---------- */ static bool -predicate_implied_by_simple_clause(Expr *predicate, Node *clause) +predicate_implied_by_simple_clause(Expr *predicate, Node *clause, + bool clause_is_check) { /* Allow interrupting long proof attempts */ CHECK_FOR_INTERRUPTS(); @@ -1053,7 +1091,7 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause) Expr *nonnullarg = ((NullTest *) predicate)->arg; /* row IS NOT NULL does not act in the simple way we have in mind */ - if (!((NullTest *) predicate)->argisrow) + if (!((NullTest *) predicate)->argisrow && !clause_is_check) { if (is_opclause(clause) && list_member_strip(((OpExpr *) clause)->args, nonnullarg) && @@ -1098,7 +1136,8 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause) *---------- */ static bool -predicate_refuted_by_simple_clause(Expr *predicate, Node *clause) +predicate_refuted_by_simple_clause(Expr *predicate, Node *clause, + bool clause_is_check) { /* Allow interrupting long proof attempts */ CHECK_FOR_INTERRUPTS(); @@ -1114,6 +1153,9 @@ predicate_refuted_by_simple_clause(Expr *predicate, Node *clause) { Expr *isnullarg = ((NullTest *) predicate)->arg; + if (clause_is_check) + return false; + /* row IS NULL does not act in the simple way we have in mind */ if (((NullTest *) predicate)->argisrow) return false; |