diff options
author | Pavan Deolasee | 2017-06-15 07:41:07 +0000 |
---|---|---|
committer | Pavan Deolasee | 2017-06-15 07:41:07 +0000 |
commit | 0ffa504a17f58f2bc045b0039f40e4917ee50d20 (patch) | |
tree | c629c449bcfcc45de1d03b2586e89932d546e8ba /src/backend/optimizer | |
parent | 36ccc8d64e61fe9d77bb7ac62267945f7c146baa (diff) | |
parent | e800656d9a9b40b2f55afabe76354ab6d93353b3 (diff) |
Merge 'remotes/PGSQL/master' into xl10devel
Merge upstream master branch upto e800656d9a9b40b2f55afabe76354ab6d93353b3.
Code compiles and regression works ok (with lots and lots of failures though).
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r-- | src/backend/optimizer/geqo/geqo_cx.c | 3 | ||||
-rw-r--r-- | src/backend/optimizer/geqo/geqo_erx.c | 3 | ||||
-rw-r--r-- | src/backend/optimizer/geqo/geqo_main.c | 4 | ||||
-rw-r--r-- | src/backend/optimizer/geqo/geqo_mutation.c | 4 | ||||
-rw-r--r-- | src/backend/optimizer/geqo/geqo_ox1.c | 3 | ||||
-rw-r--r-- | src/backend/optimizer/geqo/geqo_ox2.c | 3 | ||||
-rw-r--r-- | src/backend/optimizer/geqo/geqo_pmx.c | 3 | ||||
-rw-r--r-- | src/backend/optimizer/geqo/geqo_px.c | 3 | ||||
-rw-r--r-- | src/backend/optimizer/geqo/geqo_recombination.c | 5 | ||||
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 30 | ||||
-rw-r--r-- | src/backend/optimizer/path/indxpath.c | 11 | ||||
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 7 | ||||
-rw-r--r-- | src/backend/optimizer/util/plancat.c | 6 | ||||
-rw-r--r-- | src/backend/optimizer/util/predtest.c | 152 |
14 files changed, 159 insertions, 78 deletions
diff --git a/src/backend/optimizer/geqo/geqo_cx.c b/src/backend/optimizer/geqo/geqo_cx.c index 9f6d5e478a..c72081e81a 100644 --- a/src/backend/optimizer/geqo/geqo_cx.c +++ b/src/backend/optimizer/geqo/geqo_cx.c @@ -38,6 +38,7 @@ #include "optimizer/geqo_recombination.h" #include "optimizer/geqo_random.h" +#if defined(CX) /* cx * @@ -119,3 +120,5 @@ cx(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, return num_diffs; } + +#endif /* defined(CX) */ diff --git a/src/backend/optimizer/geqo/geqo_erx.c b/src/backend/optimizer/geqo/geqo_erx.c index 133fe32348..173be44409 100644 --- a/src/backend/optimizer/geqo/geqo_erx.c +++ b/src/backend/optimizer/geqo/geqo_erx.c @@ -35,6 +35,7 @@ #include "optimizer/geqo_recombination.h" #include "optimizer/geqo_random.h" +#if defined(ERX) static int gimme_edge(PlannerInfo *root, Gene gene1, Gene gene2, Edge *edge_table); static void remove_gene(PlannerInfo *root, Gene gene, Edge edge, Edge *edge_table); @@ -466,3 +467,5 @@ edge_failure(PlannerInfo *root, Gene *gene, int index, Edge *edge_table, int num elog(ERROR, "no edge found"); return 0; /* to keep the compiler quiet */ } + +#endif /* defined(ERX) */ diff --git a/src/backend/optimizer/geqo/geqo_main.c b/src/backend/optimizer/geqo/geqo_main.c index 52bd428187..86213ac5a0 100644 --- a/src/backend/optimizer/geqo/geqo_main.c +++ b/src/backend/optimizer/geqo/geqo_main.c @@ -46,14 +46,14 @@ double Geqo_seed; static int gimme_pool_size(int nr_rel); static int gimme_number_generations(int pool_size); -/* define edge recombination crossover [ERX] per default */ +/* complain if no recombination mechanism is #define'd */ #if !defined(ERX) && \ !defined(PMX) && \ !defined(CX) && \ !defined(PX) && \ !defined(OX1) && \ !defined(OX2) -#define ERX +#error "must choose one GEQO recombination mechanism in geqo.h" #endif diff --git a/src/backend/optimizer/geqo/geqo_mutation.c b/src/backend/optimizer/geqo/geqo_mutation.c index 1a06d49775..c6af00a2a7 100644 --- a/src/backend/optimizer/geqo/geqo_mutation.c +++ b/src/backend/optimizer/geqo/geqo_mutation.c @@ -35,6 +35,8 @@ #include "optimizer/geqo_mutation.h" #include "optimizer/geqo_random.h" +#if defined(CX) /* currently used only in CX mode */ + void geqo_mutation(PlannerInfo *root, Gene *tour, int num_gene) { @@ -60,3 +62,5 @@ geqo_mutation(PlannerInfo *root, Gene *tour, int num_gene) num_swaps -= 1; } } + +#endif /* defined(CX) */ diff --git a/src/backend/optimizer/geqo/geqo_ox1.c b/src/backend/optimizer/geqo/geqo_ox1.c index fbf15282ad..891cfa2403 100644 --- a/src/backend/optimizer/geqo/geqo_ox1.c +++ b/src/backend/optimizer/geqo/geqo_ox1.c @@ -37,6 +37,7 @@ #include "optimizer/geqo_random.h" #include "optimizer/geqo_recombination.h" +#if defined(OX1) /* ox1 * @@ -90,3 +91,5 @@ ox1(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, } } + +#endif /* defined(OX1) */ diff --git a/src/backend/optimizer/geqo/geqo_ox2.c b/src/backend/optimizer/geqo/geqo_ox2.c index 01c55bea41..b43455d3eb 100644 --- a/src/backend/optimizer/geqo/geqo_ox2.c +++ b/src/backend/optimizer/geqo/geqo_ox2.c @@ -37,6 +37,7 @@ #include "optimizer/geqo_random.h" #include "optimizer/geqo_recombination.h" +#if defined(OX2) /* ox2 * @@ -107,3 +108,5 @@ ox2(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, } } + +#endif /* defined(OX2) */ diff --git a/src/backend/optimizer/geqo/geqo_pmx.c b/src/backend/optimizer/geqo/geqo_pmx.c index deb0f7b353..e9485cc8b5 100644 --- a/src/backend/optimizer/geqo/geqo_pmx.c +++ b/src/backend/optimizer/geqo/geqo_pmx.c @@ -37,6 +37,7 @@ #include "optimizer/geqo_random.h" #include "optimizer/geqo_recombination.h" +#if defined(PMX) /* pmx * @@ -219,3 +220,5 @@ pmx(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene) pfree(indx); pfree(check_list); } + +#endif /* defined(PMX) */ diff --git a/src/backend/optimizer/geqo/geqo_px.c b/src/backend/optimizer/geqo/geqo_px.c index 99289bc11f..f7f615462c 100644 --- a/src/backend/optimizer/geqo/geqo_px.c +++ b/src/backend/optimizer/geqo/geqo_px.c @@ -37,6 +37,7 @@ #include "optimizer/geqo_random.h" #include "optimizer/geqo_recombination.h" +#if defined(PX) /* px * @@ -105,3 +106,5 @@ px(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, } } + +#endif /* defined(PX) */ diff --git a/src/backend/optimizer/geqo/geqo_recombination.c b/src/backend/optimizer/geqo/geqo_recombination.c index ef433e54e5..a61547c16d 100644 --- a/src/backend/optimizer/geqo/geqo_recombination.c +++ b/src/backend/optimizer/geqo/geqo_recombination.c @@ -58,6 +58,9 @@ init_tour(PlannerInfo *root, Gene *tour, int num_gene) } } +/* city table is used in these recombination methods: */ +#if defined(CX) || defined(PX) || defined(OX1) || defined(OX2) + /* alloc_city_table * * allocate memory for city table @@ -85,3 +88,5 @@ free_city_table(PlannerInfo *root, City *city_table) { pfree(city_table); } + +#endif /* CX || PX || OX1 || OX2 */ diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 6e4808d51b..dfb1c973c5 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -2220,6 +2220,7 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path, Cost inner_run_cost = workspace->inner_run_cost; Cost inner_rescan_run_cost = workspace->inner_rescan_run_cost; double outer_matched_rows; + double outer_unmatched_rows; Selectivity inner_scan_frac; /* @@ -2232,6 +2233,7 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path, * least 1, no such clamp is needed now.) */ outer_matched_rows = rint(outer_path_rows * extra->semifactors.outer_match_frac); + outer_unmatched_rows = outer_path_rows - outer_matched_rows; inner_scan_frac = 2.0 / (extra->semifactors.match_count + 1.0); /* @@ -2275,7 +2277,7 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path, * of a nonempty scan. We consider that these are all rescans, * since we used inner_run_cost once already. */ - run_cost += (outer_path_rows - outer_matched_rows) * + run_cost += outer_unmatched_rows * inner_rescan_run_cost / inner_path_rows; /* @@ -2293,20 +2295,28 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path, * difficult to estimate whether that will happen (and it could * not happen if there are any unmatched outer rows!), so be * conservative and always charge the whole first-scan cost once. + * We consider this charge to correspond to the first unmatched + * outer row, unless there isn't one in our estimate, in which + * case blame it on the first matched row. */ + + /* First, count all unmatched join tuples as being processed */ + ntuples += outer_unmatched_rows * inner_path_rows; + + /* Now add the forced full scan, and decrement appropriate count */ run_cost += inner_run_cost; + if (outer_unmatched_rows >= 1) + outer_unmatched_rows -= 1; + else + outer_matched_rows -= 1; /* Add inner run cost for additional outer tuples having matches */ - if (outer_matched_rows > 1) - run_cost += (outer_matched_rows - 1) * inner_rescan_run_cost * inner_scan_frac; - - /* Add inner run cost for unmatched outer tuples */ - run_cost += (outer_path_rows - outer_matched_rows) * - inner_rescan_run_cost; + if (outer_matched_rows > 0) + run_cost += outer_matched_rows * inner_rescan_run_cost * inner_scan_frac; - /* And count the unmatched join tuples as being processed */ - ntuples += (outer_path_rows - outer_matched_rows) * - inner_path_rows; + /* Add inner run cost for additional unmatched outer tuples */ + if (outer_unmatched_rows > 0) + run_cost += outer_unmatched_rows * inner_rescan_run_cost; } } else diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 607a8f97bf..07ab33902b 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -1210,10 +1210,10 @@ build_paths_for_OR(PlannerInfo *root, RelOptInfo *rel, all_clauses = list_concat(list_copy(clauses), other_clauses); - if (!predicate_implied_by(index->indpred, all_clauses)) + if (!predicate_implied_by(index->indpred, all_clauses, false)) continue; /* can't use it at all */ - if (!predicate_implied_by(index->indpred, other_clauses)) + if (!predicate_implied_by(index->indpred, other_clauses, false)) useful_predicate = true; } } @@ -1519,7 +1519,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths) { Node *np = (Node *) lfirst(l); - if (predicate_implied_by(list_make1(np), qualsofar)) + if (predicate_implied_by(list_make1(np), qualsofar, false)) { redundant = true; break; /* out of inner foreach loop */ @@ -2871,7 +2871,8 @@ check_index_predicates(PlannerInfo *root, RelOptInfo *rel) continue; /* ignore non-partial indexes here */ if (!index->predOK) /* don't repeat work if already proven OK */ - index->predOK = predicate_implied_by(index->indpred, clauselist); + index->predOK = predicate_implied_by(index->indpred, clauselist, + false); /* If rel is an update target, leave indrestrictinfo as set above */ if (is_target_rel) @@ -2886,7 +2887,7 @@ check_index_predicates(PlannerInfo *root, RelOptInfo *rel) /* predicate_implied_by() assumes first arg is immutable */ if (contain_mutable_functions((Node *) rinfo->clause) || !predicate_implied_by(list_make1(rinfo->clause), - index->indpred)) + index->indpred, false)) index->indrestrictinfo = lappend(index->indrestrictinfo, rinfo); } } diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index af89e9d288..5c833e933d 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -2860,7 +2860,7 @@ create_indexscan_plan(PlannerInfo *root, if (is_redundant_derived_clause(rinfo, indexquals)) continue; /* derived from same EquivalenceClass */ if (!contain_mutable_functions((Node *) rinfo->clause) && - predicate_implied_by(list_make1(rinfo->clause), indexquals)) + predicate_implied_by(list_make1(rinfo->clause), indexquals, false)) continue; /* provably implied by indexquals */ qpqual = lappend(qpqual, rinfo); } @@ -3021,7 +3021,7 @@ create_bitmap_scan_plan(PlannerInfo *root, if (rinfo->parent_ec && list_member_ptr(indexECs, rinfo->parent_ec)) continue; /* derived from same EquivalenceClass */ if (!contain_mutable_functions(clause) && - predicate_implied_by(list_make1(clause), indexquals)) + predicate_implied_by(list_make1(clause), indexquals, false)) continue; /* provably implied by indexquals */ qpqual = lappend(qpqual, rinfo); } @@ -3252,7 +3252,8 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, * the conditions that got pushed into the bitmapqual. Avoid * generating redundant conditions. */ - if (!predicate_implied_by(list_make1(pred), ipath->indexclauses)) + if (!predicate_implied_by(list_make1(pred), ipath->indexclauses, + false)) { *qual = lappend(*qual, pred); *indexqual = lappend(*indexqual, pred); diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index aa8f6cf020..dec1589ec5 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -789,7 +789,7 @@ infer_arbiter_indexes(PlannerInfo *root) */ predExprs = RelationGetIndexPredicate(idxRel); - if (!predicate_implied_by(predExprs, (List *) onconflict->arbiterWhere)) + if (!predicate_implied_by(predExprs, (List *) onconflict->arbiterWhere, false)) goto next; results = lappend_oid(results, idxForm->indexrelid); @@ -1424,7 +1424,7 @@ relation_excluded_by_constraints(PlannerInfo *root, safe_restrictions = lappend(safe_restrictions, rinfo->clause); } - if (predicate_refuted_by(safe_restrictions, safe_restrictions)) + if (predicate_refuted_by(safe_restrictions, safe_restrictions, false)) return true; /* Only plain relations have constraints */ @@ -1463,7 +1463,7 @@ relation_excluded_by_constraints(PlannerInfo *root, * have volatile and nonvolatile subclauses, and it's OK to make * deductions with the nonvolatile parts. */ - if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo)) + if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo, false)) return true; return false; 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; |