diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/catalog/heap.c | 13 | ||||
-rw-r--r-- | src/backend/catalog/index.c | 7 | ||||
-rw-r--r-- | src/backend/commands/indexcmds.c | 29 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 6 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 33 | ||||
-rw-r--r-- | src/backend/optimizer/prep/prepqual.c | 186 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 6 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 25 | ||||
-rw-r--r-- | src/backend/utils/adt/selfuncs.c | 9 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 29 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 4 | ||||
-rw-r--r-- | src/include/nodes/relation.h | 5 | ||||
-rw-r--r-- | src/include/optimizer/prep.h | 6 |
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 |