aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/heap.c13
-rw-r--r--src/backend/catalog/index.c7
-rw-r--r--src/backend/commands/indexcmds.c29
-rw-r--r--src/backend/executor/execMain.c6
-rw-r--r--src/backend/optimizer/plan/planner.c33
-rw-r--r--src/backend/optimizer/prep/prepqual.c186
-rw-r--r--src/backend/optimizer/util/clauses.c6
-rw-r--r--src/backend/utils/adt/ruleutils.c25
-rw-r--r--src/backend/utils/adt/selfuncs.c9
-rw-r--r--src/backend/utils/cache/relcache.c29
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/nodes/relation.h5
-rw-r--r--src/include/optimizer/prep.h6
13 files changed, 149 insertions, 209 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 1a9743fb5f3..14c3745e5e9 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.256 2003/11/29 19:51:42 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.257 2003/12/28 21:57:36 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -1344,10 +1344,9 @@ StoreRelCheck(Relation rel, char *ccname, char *ccbin)
int16 *attNos;
/*
- * Convert condition to a normal boolean expression tree.
+ * Convert condition to an expression tree.
*/
expr = stringToNode(ccbin);
- expr = (Node *) make_ands_explicit((List *) expr);
/*
* deparse it
@@ -1652,14 +1651,6 @@ AddRelationRawConstraints(Relation rel,
errmsg("cannot use aggregate function in check constraint")));
/*
- * Constraints are evaluated with execQual, which expects an
- * implicit-AND list, so convert expression to implicit-AND form.
- * (We could go so far as to convert to CNF, but that's probably
- * overkill...)
- */
- expr = (Node *) make_ands_implicit((Expr *) expr);
-
- /*
* OK, store it.
*/
StoreRelCheck(rel, ccname, nodeToString(expr));
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index a05d74849e5..59effe8e321 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.223 2003/11/29 19:51:43 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.224 2003/12/28 21:57:36 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -397,13 +397,14 @@ UpdateIndexRelation(Oid indexoid,
exprsDatum = (Datum) 0;
/*
- * Convert the index predicate (if any) to a text datum
+ * Convert the index predicate (if any) to a text datum. Note we
+ * convert implicit-AND format to normal explicit-AND for storage.
*/
if (indexInfo->ii_Predicate != NIL)
{
char *predString;
- predString = nodeToString(indexInfo->ii_Predicate);
+ predString = nodeToString(make_ands_explicit(indexInfo->ii_Predicate));
predDatum = DirectFunctionCall1(textin,
CStringGetDatum(predString));
pfree(predString);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 863d74f59a3..507bcf50d5f 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.116 2003/11/29 19:51:47 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.117 2003/12/28 21:57:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,7 +42,7 @@
/* non-export function prototypes */
-static void CheckPredicate(List *predList);
+static void CheckPredicate(Expr *predicate);
static void ComputeIndexAttrs(IndexInfo *indexInfo, Oid *classOidP,
List *attList,
Oid relId,
@@ -80,7 +80,6 @@ DefineIndex(RangeVar *heapRelation,
Form_pg_am accessMethodForm;
IndexInfo *indexInfo;
int numberOfAttributes;
- List *cnfPred = NIL;
/*
* count attributes in index
@@ -172,16 +171,10 @@ DefineIndex(RangeVar *heapRelation,
}
/*
- * Convert the partial-index predicate from parsetree form to an
- * implicit-AND qual expression, for easier evaluation at runtime.
- * While we are at it, we reduce it to a canonical (CNF or DNF) form
- * to simplify the task of proving implications.
+ * Validate predicate, if given
*/
if (predicate)
- {
- cnfPred = canonicalize_qual((Expr *) copyObject(predicate), true);
- CheckPredicate(cnfPred);
- }
+ CheckPredicate(predicate);
/*
* Check that all of the attributes in a primary key are marked as not
@@ -237,13 +230,13 @@ DefineIndex(RangeVar *heapRelation,
/*
* Prepare arguments for index_create, primarily an IndexInfo
- * structure
+ * structure. Note that ii_Predicate must be in implicit-AND format.
*/
indexInfo = makeNode(IndexInfo);
indexInfo->ii_NumIndexAttrs = numberOfAttributes;
indexInfo->ii_Expressions = NIL; /* for now */
indexInfo->ii_ExpressionsState = NIL;
- indexInfo->ii_Predicate = cnfPred;
+ indexInfo->ii_Predicate = make_ands_implicit(predicate);
indexInfo->ii_PredicateState = NIL;
indexInfo->ii_Unique = unique;
@@ -268,7 +261,7 @@ DefineIndex(RangeVar *heapRelation,
/*
* CheckPredicate
- * Checks that the given list of partial-index predicates is valid.
+ * Checks that the given partial-index predicate is valid.
*
* This used to also constrain the form of the predicate to forms that
* indxpath.c could do something with. However, that seems overly
@@ -278,18 +271,18 @@ DefineIndex(RangeVar *heapRelation,
* (except ones requiring a plan), and let indxpath.c fend for itself.
*/
static void
-CheckPredicate(List *predList)
+CheckPredicate(Expr *predicate)
{
/*
* We don't currently support generation of an actual query plan for a
* predicate, only simple scalar expressions; hence these
* restrictions.
*/
- if (contain_subplans((Node *) predList))
+ if (contain_subplans((Node *) predicate))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use subquery in index predicate")));
- if (contain_agg_clause((Node *) predList))
+ if (contain_agg_clause((Node *) predicate))
ereport(ERROR,
(errcode(ERRCODE_GROUPING_ERROR),
errmsg("cannot use aggregate in index predicate")));
@@ -298,7 +291,7 @@ CheckPredicate(List *predList)
* A predicate using mutable functions is probably wrong, for the same
* reasons that we don't allow an index expression to use one.
*/
- if (contain_mutable_functions((Node *) predList))
+ if (contain_mutable_functions((Node *) predicate))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("functions in index predicate must be marked IMMUTABLE")));
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index e53bb1f7040..f84b4dd690e 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.223 2003/12/01 22:07:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.224 2003/12/28 21:57:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -40,6 +40,7 @@
#include "executor/execdebug.h"
#include "executor/execdefs.h"
#include "miscadmin.h"
+#include "optimizer/clauses.h"
#include "optimizer/var.h"
#include "parser/parsetree.h"
#include "utils/acl.h"
@@ -1658,7 +1659,8 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
(List **) palloc(ncheck * sizeof(List *));
for (i = 0; i < ncheck; i++)
{
- qual = (List *) stringToNode(check[i].ccbin);
+ /* ExecQual wants implicit-AND form */
+ qual = make_ands_implicit(stringToNode(check[i].ccbin));
resultRelInfo->ri_ConstraintExprs[i] = (List *)
ExecPrepareExpr((Expr *) qual, estate);
}
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index bdc146a028e..bf8a28d1254 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.162 2003/11/29 19:51:50 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.163 2003/12/28 21:57:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -377,23 +377,13 @@ preprocess_expression(Query *parse, Node *expr, int kind)
expr = flatten_join_alias_vars(parse, expr);
/*
- * Simplify constant expressions.
- *
- * Note that at this point quals have not yet been converted to
- * implicit-AND form, so we can apply eval_const_expressions directly.
- */
- expr = eval_const_expressions(expr);
-
- /*
- * If it's a qual or havingQual, canonicalize it, and convert it to
- * implicit-AND format.
- *
- * XXX Is there any value in re-applying eval_const_expressions after
- * canonicalize_qual?
+ * If it's a qual or havingQual, canonicalize it. It seems most useful
+ * to do this before applying eval_const_expressions, since the latter
+ * can optimize flattened AND/ORs better than unflattened ones.
*/
if (kind == EXPRKIND_QUAL)
{
- expr = (Node *) canonicalize_qual((Expr *) expr, true);
+ expr = (Node *) canonicalize_qual((Expr *) expr);
#ifdef OPTIMIZER_DEBUG
printf("After canonicalize_qual()\n");
@@ -401,6 +391,19 @@ preprocess_expression(Query *parse, Node *expr, int kind)
#endif
}
+ /*
+ * Simplify constant expressions.
+ */
+ expr = eval_const_expressions(expr);
+
+ /*
+ * If it's a qual or havingQual, convert it to implicit-AND format.
+ * (We don't want to do this before eval_const_expressions, since the
+ * latter would be unable to simplify a top-level AND correctly.)
+ */
+ if (kind == EXPRKIND_QUAL)
+ expr = (Node *) make_ands_implicit((Expr *) expr);
+
/* Expand SubLinks to SubPlans */
if (parse->hasSubLinks)
expr = SS_process_sublinks(expr, (kind == EXPRKIND_QUAL));
diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c
index 1bff3509e26..186de4c40ac 100644
--- a/src/backend/optimizer/prep/prepqual.c
+++ b/src/backend/optimizer/prep/prepqual.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.39 2003/11/29 19:51:51 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.40 2003/12/28 21:57:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,7 +20,7 @@
#include "optimizer/prep.h"
#include "utils/lsyscache.h"
-static Expr *flatten_andors(Expr *qual);
+static Node *flatten_andors_mutator(Node *node, void *context);
static void flatten_andors_and_walker(FastList *out_list, List *andlist);
static void flatten_andors_or_walker(FastList *out_list, List *orlist);
static List *pull_ands(List *andlist);
@@ -61,8 +61,7 @@ static void count_bool_nodes(Expr *qual, double *nodes,
*
* canonicalize_qual() does "smart" conversion to either CNF or DNF, per
* the above considerations, while cnfify() and dnfify() simply perform
- * the demanded transformation. The latter two may become dead code
- * eventually.
+ * the demanded transformation. The latter two are presently dead code.
*****************************************************************************/
@@ -72,11 +71,6 @@ static void count_bool_nodes(Expr *qual, double *nodes,
*
* Returns the modified qualification.
*
- * If 'removeAndFlag' is true then it removes explicit AND at the top level,
- * producing a list of implicitly-ANDed conditions. Otherwise, a regular
- * boolean expression is returned. Since most callers pass 'true', we
- * prefer to declare the result as List *, not Expr *.
- *
* XXX This code could be much smarter, at the cost of also being slower,
* if we tried to compute selectivities and/or see whether there are
* actually indexes to support an indexscan implementation of a DNF qual.
@@ -85,8 +79,8 @@ static void count_bool_nodes(Expr *qual, double *nodes,
* implement. For now, though, we just try to avoid doing anything
* quite as stupid as unconditionally converting to CNF was...
*/
-List *
-canonicalize_qual(Expr *qual, bool removeAndFlag)
+Expr *
+canonicalize_qual(Expr *qual)
{
Expr *newqual;
double nodes,
@@ -95,23 +89,23 @@ canonicalize_qual(Expr *qual, bool removeAndFlag)
bool cnfok,
dnfok;
+ /* Quick exit for empty qual */
if (qual == NULL)
- return NIL;
+ return NULL;
/*
* Flatten AND and OR groups throughout the tree. This improvement is
* always worthwhile, so do it unconditionally.
*/
- qual = flatten_andors(qual);
+ newqual = (Expr *) flatten_andors((Node *) qual);
/*
* Push down NOTs. We do this only in the top-level boolean
* expression, without examining arguments of operators/functions.
- * Even so, it might not be a win if we are unable to find negators
- * for all the operators involved; perhaps we should compare before-
- * and-after tree sizes?
+ * The main reason for doing this is to expose as much top-level AND/OR
+ * structure as we can, so there's no point in descending further.
*/
- newqual = find_nots(qual);
+ newqual = find_nots(newqual);
/*
* Choose whether to convert to CNF, or DNF, or leave well enough
@@ -175,13 +169,10 @@ canonicalize_qual(Expr *qual, bool removeAndFlag)
newqual = qual_cleanup(find_ands(newqual));
}
- /* Convert to implicit-AND list if requested */
- if (removeAndFlag)
- newqual = (Expr *) make_ands_implicit(newqual);
-
- return (List *) newqual;
+ return newqual;
}
+#ifdef NOT_USED
/*
* cnfify
* Convert a qualification to conjunctive normal form by applying
@@ -223,6 +214,7 @@ cnfify(Expr *qual, bool removeAndFlag)
return (List *) newqual;
}
+#endif
#ifdef NOT_USED
/*
@@ -281,50 +273,46 @@ dnfify(Expr *qual)
/*--------------------
* flatten_andors
- * Given a qualification, simplify nested AND/OR clauses into flat
- * AND/OR clauses with more arguments.
+ * Given an expression tree, simplify nested AND/OR clauses into flat
+ * AND/OR clauses with more arguments. The entire tree is processed.
*
- * Returns the rebuilt expr (note original list structure is not touched).
+ * Returns the rebuilt expr (note original structure is not touched).
*--------------------
*/
-static Expr *
-flatten_andors(Expr *qual)
+Node *
+flatten_andors(Node *node)
{
- if (qual == NULL)
- return NULL;
+ return flatten_andors_mutator(node, NULL);
+}
- if (and_clause((Node *) qual))
+static Node *
+flatten_andors_mutator(Node *node, void *context)
+{
+ if (node == NULL)
+ return NULL;
+ if (IsA(node, BoolExpr))
{
- FastList out_list;
+ BoolExpr *bexpr = (BoolExpr *) node;
- FastListInit(&out_list);
- flatten_andors_and_walker(&out_list, ((BoolExpr *) qual)->args);
- return make_andclause(FastListValue(&out_list));
- }
- else if (or_clause((Node *) qual))
- {
- FastList out_list;
+ if (bexpr->boolop == AND_EXPR)
+ {
+ FastList out_list;
- FastListInit(&out_list);
- flatten_andors_or_walker(&out_list, ((BoolExpr *) qual)->args);
- return make_orclause(FastListValue(&out_list));
- }
- else if (not_clause((Node *) qual))
- return make_notclause(flatten_andors(get_notclausearg(qual)));
- else if (is_opclause(qual))
- {
- OpExpr *opexpr = (OpExpr *) qual;
- Expr *left = (Expr *) get_leftop(qual);
- Expr *right = (Expr *) get_rightop(qual);
-
- return make_opclause(opexpr->opno,
- opexpr->opresulttype,
- opexpr->opretset,
- flatten_andors(left),
- flatten_andors(right));
+ FastListInit(&out_list);
+ flatten_andors_and_walker(&out_list, bexpr->args);
+ return (Node *) make_andclause(FastListValue(&out_list));
+ }
+ if (bexpr->boolop == OR_EXPR)
+ {
+ FastList out_list;
+
+ FastListInit(&out_list);
+ flatten_andors_or_walker(&out_list, bexpr->args);
+ return (Node *) make_orclause(FastListValue(&out_list));
+ }
+ /* else it's a NOT clause, fall through */
}
- else
- return qual;
+ return expression_tree_mutator(node, flatten_andors_mutator, context);
}
static void
@@ -334,9 +322,9 @@ flatten_andors_and_walker(FastList *out_list, List *andlist)
foreach(arg, andlist)
{
- Expr *subexpr = (Expr *) lfirst(arg);
+ Node *subexpr = (Node *) lfirst(arg);
- if (and_clause((Node *) subexpr))
+ if (and_clause(subexpr))
flatten_andors_and_walker(out_list, ((BoolExpr *) subexpr)->args);
else
FastAppend(out_list, flatten_andors(subexpr));
@@ -350,9 +338,9 @@ flatten_andors_or_walker(FastList *out_list, List *orlist)
foreach(arg, orlist)
{
- Expr *subexpr = (Expr *) lfirst(arg);
+ Node *subexpr = (Node *) lfirst(arg);
- if (or_clause((Node *) subexpr))
+ if (or_clause(subexpr))
flatten_andors_or_walker(out_list, ((BoolExpr *) subexpr)->args);
else
FastAppend(out_list, flatten_andors(subexpr));
@@ -383,9 +371,9 @@ pull_ands_walker(FastList *out_list, List *andlist)
foreach(arg, andlist)
{
- Expr *subexpr = (Expr *) lfirst(arg);
+ Node *subexpr = (Node *) lfirst(arg);
- if (and_clause((Node *) subexpr))
+ if (and_clause(subexpr))
pull_ands_walker(out_list, ((BoolExpr *) subexpr)->args);
else
FastAppend(out_list, subexpr);
@@ -416,9 +404,9 @@ pull_ors_walker(FastList *out_list, List *orlist)
foreach(arg, orlist)
{
- Expr *subexpr = (Expr *) lfirst(arg);
+ Node *subexpr = (Node *) lfirst(arg);
- if (or_clause((Node *) subexpr))
+ if (or_clause(subexpr))
pull_ors_walker(out_list, ((BoolExpr *) subexpr)->args);
else
FastAppend(out_list, subexpr);
@@ -427,9 +415,10 @@ pull_ors_walker(FastList *out_list, List *orlist)
/*
* find_nots
- * Traverse the qualification, looking for 'NOT's to take care of.
- * For 'NOT' clauses, apply push_not() to try to push down the 'NOT'.
- * For all other clause types, simply recurse.
+ * Traverse the qualification, looking for NOTs to take care of.
+ * For NOT clauses, apply push_nots() to try to push down the NOT.
+ * For AND and OR clause types, simply recurse. Otherwise stop
+ * recursing (we do not worry about structure below the top AND/OR tree).
*
* Returns the modified qualification. AND/OR flatness is preserved.
*/
@@ -439,21 +428,6 @@ find_nots(Expr *qual)
if (qual == NULL)
return NULL;
-#ifdef NOT_USED
- /* recursing into operator expressions is probably not worth it. */
- if (is_opclause(qual))
- {
- OpExpr *opexpr = (OpExpr *) qual;
- Expr *left = (Expr *) get_leftop(qual);
- Expr *right = (Expr *) get_rightop(qual);
-
- return make_opclause(opexpr->opno,
- opexpr->opresulttype,
- opexpr->opretset,
- find_nots(left),
- find_nots(right));
- }
-#endif
if (and_clause((Node *) qual))
{
FastList t_list;
@@ -482,7 +456,7 @@ find_nots(Expr *qual)
/*
* push_nots
- * Push down a 'NOT' as far as possible.
+ * Push down a NOT as far as possible.
*
* Input is an expression to be negated (e.g., the argument of a NOT clause).
* Returns a new qual equivalent to the negation of the given qual.
@@ -496,7 +470,7 @@ push_nots(Expr *qual)
/*
* Negate an operator clause if possible: ("NOT" (< A B)) => (> A B)
- * Otherwise, retain the clause as it is (the 'not' can't be pushed
+ * Otherwise, retain the clause as it is (the NOT can't be pushed
* down any farther).
*/
if (is_opclause(qual))
@@ -543,16 +517,15 @@ push_nots(Expr *qual)
else if (not_clause((Node *) qual))
{
/*
- * Another 'not' cancels this 'not', so eliminate the 'not' and
- * stop negating this branch. But search the subexpression for
- * more 'not's to simplify.
+ * Another NOT cancels this NOT, so eliminate the NOT and
+ * stop negating this branch.
*/
- return find_nots(get_notclausearg(qual));
+ return get_notclausearg(qual);
}
else
{
/*
- * We don't know how to negate anything else, place a 'not' at
+ * We don't know how to negate anything else, place a NOT at
* this level.
*/
return make_notclause(qual);
@@ -561,12 +534,13 @@ push_nots(Expr *qual)
/*
* find_ors
- * Given a qualification tree with the 'not's pushed down, convert it
+ * Given a qualification tree with the NOTs pushed down, convert it
* to a tree in CNF by repeatedly applying the rule:
* ("OR" A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C))
*
* Note that 'or' clauses will always be turned into 'and' clauses
- * if they contain any 'and' subclauses.
+ * if they contain any 'and' subclauses. Also, we do not descend
+ * below the top-level AND/OR structure.
*
* Returns the modified qualification. AND/OR flatness is preserved.
*/
@@ -576,7 +550,6 @@ find_ors(Expr *qual)
if (qual == NULL)
return NULL;
- /* We used to recurse into opclauses here, but I see no reason to... */
if (and_clause((Node *) qual))
{
List *andlist = NIL;
@@ -595,8 +568,6 @@ find_ors(Expr *qual)
orlist = lappend(orlist, find_ors(lfirst(temp)));
return or_normalize(pull_ors(orlist));
}
- else if (not_clause((Node *) qual))
- return make_notclause(find_ors(get_notclausearg(qual)));
else
return qual;
}
@@ -688,12 +659,13 @@ or_normalize(List *orlist)
/*
* find_ands
- * Given a qualification tree with the 'not's pushed down, convert it
+ * Given a qualification tree with the NOTs pushed down, convert it
* to a tree in DNF by repeatedly applying the rule:
* ("AND" A ("OR" B C)) => ("OR" ("AND" A B) ("AND" A C))
*
* Note that 'and' clauses will always be turned into 'or' clauses
- * if they contain any 'or' subclauses.
+ * if they contain any 'or' subclauses. Also, we do not descend
+ * below the top-level AND/OR structure.
*
* Returns the modified qualification. AND/OR flatness is preserved.
*/
@@ -703,7 +675,6 @@ find_ands(Expr *qual)
if (qual == NULL)
return NULL;
- /* We used to recurse into opclauses here, but I see no reason to... */
if (or_clause((Node *) qual))
{
List *orlist = NIL;
@@ -722,8 +693,6 @@ find_ands(Expr *qual)
andlist = lappend(andlist, find_ands(lfirst(temp)));
return and_normalize(pull_ands(andlist));
}
- else if (not_clause((Node *) qual))
- return make_notclause(find_ands(get_notclausearg(qual)));
else
return qual;
}
@@ -860,8 +829,6 @@ qual_cleanup(Expr *qual)
else
return lfirst(orlist);
}
- else if (not_clause((Node *) qual))
- return make_notclause(qual_cleanup(get_notclausearg(qual)));
else
return qual;
}
@@ -889,14 +856,14 @@ remove_duplicates(List *list)
/*
* count_bool_nodes
* Support for heuristics in canonicalize_qual(): count the
- * number of nodes that are inputs to the top level AND/OR/NOT
+ * number of nodes that are inputs to the top level AND/OR
* part of a qual tree, and estimate how many nodes will appear
* in the CNF'ified or DNF'ified equivalent of the expression.
*
- * This is just an approximate calculation; it doesn't deal with NOTs
- * very well, and of course it cannot detect possible simplifications
- * from eliminating duplicate subclauses. The idea is just to cheaply
- * determine whether CNF will be markedly worse than DNF or vice versa.
+ * This is just an approximate calculation; it cannot detect possible
+ * simplifications from eliminating duplicate subclauses. The idea is just to
+ * cheaply determine whether CNF will be markedly worse than DNF or vice
+ * versa.
*
* The counts/estimates are represented as doubles to avoid risk of overflow.
*/
@@ -953,11 +920,6 @@ count_bool_nodes(Expr *qual,
if (*cnfnodes < *dnfnodes)
*cnfnodes = *dnfnodes;
}
- else if (not_clause((Node *) qual))
- {
- count_bool_nodes(get_notclausearg(qual),
- nodes, cnfnodes, dnfnodes);
- }
else if (contain_subplans((Node *) qual))
{
/*
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 697799a494e..d6f0bb3ad2e 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.156 2003/12/09 01:56:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.157 2003/12/28 21:57:37 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -261,8 +261,8 @@ make_and_qual(Node *qual1, Node *qual2)
}
/*
- * Sometimes (such as in the result of canonicalize_qual or the input of
- * ExecQual), we use lists of expression nodes with implicit AND semantics.
+ * Sometimes (such as in the input of ExecQual), we use lists of expression
+ * nodes with implicit AND semantics.
*
* These functions convert between an AND-semantics expression list and the
* ordinary representation of a boolean expression.
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index ca3c3720519..f8937c7ea64 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.160 2003/11/29 19:51:59 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.161 2003/12/28 21:57:37 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -810,13 +810,6 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
node = (Node *) stringToNode(predString);
pfree(predString);
- /*
- * If top level is a List, assume it is an implicit-AND
- * structure, and convert to explicit AND. This is needed for
- * partial index predicates.
- */
- if (node && IsA(node, List))
- node = (Node *) make_ands_explicit((List *) node);
/* Deparse */
str = deparse_expression_pretty(node, context, false, false,
prettyFlags, 0);
@@ -1060,14 +1053,6 @@ pg_get_constraintdef_worker(Oid constraintId, int prettyFlags)
conbin = DatumGetCString(DirectFunctionCall1(textout, val));
expr = stringToNode(conbin);
- /*
- * If top level is a List, assume it is an implicit-AND
- * structure, and convert to explicit AND. This is needed
- * for partial index predicates.
- */
- if (expr && IsA(expr, List))
- expr = (Node *) make_ands_explicit((List *) expr);
-
/* Set up deparsing context for Var nodes in constraint */
if (conForm->conrelid != InvalidOid)
{
@@ -1212,14 +1197,6 @@ pg_get_expr_worker(text *expr, Oid relid, char *relname, int prettyFlags)
/* Convert expression to node tree */
node = (Node *) stringToNode(exprstr);
- /*
- * If top level is a List, assume it is an implicit-AND structure, and
- * convert to explicit AND. This is needed for partial index
- * predicates.
- */
- if (node && IsA(node, List))
- node = (Node *) make_ands_explicit((List *) node);
-
/* Deparse */
context = deparse_context_for(relname, relid);
str = deparse_expression_pretty(node, context, false, false,
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 9b2e86224a5..0a37df1d9a7 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.150 2003/12/07 04:14:10 joe Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.151 2003/12/28 21:57:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3902,12 +3902,12 @@ genericcostestimate(Query *root, RelOptInfo *rel,
* If the index is partial, AND the index predicate with the
* explicitly given indexquals to produce a more accurate idea of the
* index restriction. This may produce redundant clauses, which we
- * hope that cnfify and clauselist_selectivity will deal with
+ * hope that canonicalize_qual and clauselist_selectivity will deal with
* intelligently.
*
* Note that index->indpred and indexQuals are both in implicit-AND form
* to start with, which we have to make explicit to hand to
- * canonicalize_qual, and then we get back implicit-AND form again.
+ * canonicalize_qual, and then we convert back to implicit-AND form.
*/
if (index->indpred != NIL)
{
@@ -3915,7 +3915,8 @@ genericcostestimate(Query *root, RelOptInfo *rel,
andedQuals = make_ands_explicit(nconc(listCopy(index->indpred),
indexQuals));
- selectivityQuals = canonicalize_qual(andedQuals, true);
+ andedQuals = canonicalize_qual(andedQuals);
+ selectivityQuals = make_ands_implicit(andedQuals);
}
/* Estimate the fraction of main-table tuples that will be visited */
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 679a73644e4..797d96ca8ec 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.193 2003/11/29 19:52:00 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.194 2003/12/28 21:57:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,7 @@
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
+#include "optimizer/prep.h"
#include "storage/smgr.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
@@ -2770,11 +2771,13 @@ RelationGetIndexExpressions(Relation relation)
pfree(exprsString);
/*
- * Run the expressions through eval_const_expressions. This is not
- * just an optimization, but is necessary, because the planner will be
- * comparing them to const-folded qual clauses, and may fail to detect
- * valid matches without this.
+ * Run the expressions through flatten_andors and eval_const_expressions.
+ * This is not just an optimization, but is necessary, because the planner
+ * will be comparing them to similarly-processed qual clauses, and may
+ * fail to detect valid matches without this.
*/
+ result = (List *) flatten_andors((Node *) result);
+
result = (List *) eval_const_expressions((Node *) result);
/* May as well fix opfuncids too */
@@ -2791,7 +2794,8 @@ RelationGetIndexExpressions(Relation relation)
/*
* RelationGetIndexPredicate -- get the index predicate for an index
*
- * We cache the result of transforming pg_index.indpred into a node tree.
+ * We cache the result of transforming pg_index.indpred into an implicit-AND
+ * node tree (suitable for ExecQual).
* If the rel is not an index or has no predicate, we return NIL.
* Otherwise, the returned tree is copied into the caller's memory context.
* (We don't want to return a pointer to the relcache copy, since it could
@@ -2835,13 +2839,18 @@ RelationGetIndexPredicate(Relation relation)
pfree(predString);
/*
- * Run the expression through eval_const_expressions. This is not
- * just an optimization, but is necessary, because the planner will be
- * comparing it to const-folded qual clauses, and may fail to detect
- * valid matches without this.
+ * Run the expression through canonicalize_qual and eval_const_expressions.
+ * This is not just an optimization, but is necessary, because the planner
+ * will be comparing it to similarly-processed qual clauses, and may fail
+ * to detect valid matches without this.
*/
+ result = (List *) canonicalize_qual((Expr *) result);
+
result = (List *) eval_const_expressions((Node *) result);
+ /* Also convert to implicit-AND format */
+ result = make_ands_implicit((Expr *) result);
+
/* May as well fix opfuncids too */
fix_opfuncids((Node *) result);
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 0af05e01d6e..b5f0da8d0dc 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.213 2003/12/03 18:53:52 joe Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.214 2003/12/28 21:57:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200312031
+#define CATALOG_VERSION_NO 200312281
#endif
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 62e77afcd2e..6b205b20da5 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.86 2003/11/29 22:41:06 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.87 2003/12/28 21:57:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -245,7 +245,8 @@ typedef struct RelOptInfo
* zero entry, rather than looking at ncolumns.
*
* The indexprs and indpred expressions have been run through
- * eval_const_expressions() for ease of matching to WHERE clauses.
+ * prepqual.c and eval_const_expressions() for ease of matching to
+ * WHERE clauses. indpred is in implicit-AND form.
*/
typedef struct IndexOptInfo
diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h
index 060b25b314c..6255c362307 100644
--- a/src/include/optimizer/prep.h
+++ b/src/include/optimizer/prep.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/optimizer/prep.h,v 1.42 2003/11/29 22:41:07 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/prep.h,v 1.43 2003/12/28 21:57:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -36,8 +36,8 @@ extern Relids get_relids_for_join(Query *parse, int joinrelid);
/*
* prototypes for prepqual.c
*/
-extern List *canonicalize_qual(Expr *qual, bool removeAndFlag);
-extern List *cnfify(Expr *qual, bool removeAndFlag);
+extern Expr *canonicalize_qual(Expr *qual);
+extern Node *flatten_andors(Node *node);
/*
* prototypes for preptlist.c