summaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
authorPavan Deolasee2017-06-15 07:41:07 +0000
committerPavan Deolasee2017-06-15 07:41:07 +0000
commit0ffa504a17f58f2bc045b0039f40e4917ee50d20 (patch)
treec629c449bcfcc45de1d03b2586e89932d546e8ba /src/backend/optimizer
parent36ccc8d64e61fe9d77bb7ac62267945f7c146baa (diff)
parente800656d9a9b40b2f55afabe76354ab6d93353b3 (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.c3
-rw-r--r--src/backend/optimizer/geqo/geqo_erx.c3
-rw-r--r--src/backend/optimizer/geqo/geqo_main.c4
-rw-r--r--src/backend/optimizer/geqo/geqo_mutation.c4
-rw-r--r--src/backend/optimizer/geqo/geqo_ox1.c3
-rw-r--r--src/backend/optimizer/geqo/geqo_ox2.c3
-rw-r--r--src/backend/optimizer/geqo/geqo_pmx.c3
-rw-r--r--src/backend/optimizer/geqo/geqo_px.c3
-rw-r--r--src/backend/optimizer/geqo/geqo_recombination.c5
-rw-r--r--src/backend/optimizer/path/costsize.c30
-rw-r--r--src/backend/optimizer/path/indxpath.c11
-rw-r--r--src/backend/optimizer/plan/createplan.c7
-rw-r--r--src/backend/optimizer/util/plancat.c6
-rw-r--r--src/backend/optimizer/util/predtest.c152
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;