diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index ef4f0421e93bdc7ba7eaf78be71be1be2c062fac..8b96f77a7316f2b327e7209bb9c7aab4d0748b2e 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.269 2003/11/29 19:51:49 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.270 2003/12/30 23:53:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1169,11 +1169,12 @@ _copyRestrictInfo(RestrictInfo *from) COPY_NODE_FIELD(clause); COPY_SCALAR_FIELD(ispusheddown); + COPY_SCALAR_FIELD(canjoin); + COPY_BITMAPSET_FIELD(left_relids); + COPY_BITMAPSET_FIELD(right_relids); COPY_NODE_FIELD(subclauseindices); /* XXX probably bad */ COPY_SCALAR_FIELD(eval_cost); COPY_SCALAR_FIELD(this_selec); - COPY_BITMAPSET_FIELD(left_relids); - COPY_BITMAPSET_FIELD(right_relids); COPY_SCALAR_FIELD(mergejoinoperator); COPY_SCALAR_FIELD(left_sortop); COPY_SCALAR_FIELD(right_sortop); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index f4fd1d774326d6784ab12dad0bea23e48448e5ad..5c7e53844022743eea617cff8e2d6cec65a1a7f5 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.210 2003/11/29 19:51:49 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.211 2003/12/30 23:53:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -563,16 +563,9 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b) COMPARE_SCALAR_FIELD(ispusheddown); /* - * We ignore subclauseindices, eval_cost, this_selec, - * left/right_relids, left/right_pathkey, and left/right_bucketsize, - * since they may not be set yet, and should be derivable from the - * clause anyway. Probably it's not really necessary to compare any - * of these remaining fields ... + * We ignore all the remaining fields, since they may not be set yet, + * and should be derivable from the clause anyway. */ - COMPARE_SCALAR_FIELD(mergejoinoperator); - COMPARE_SCALAR_FIELD(left_sortop); - COMPARE_SCALAR_FIELD(right_sortop); - COMPARE_SCALAR_FIELD(hashjoinoperator); return true; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 0946cbc9eb7e5ddb2311f76be18d73c0a71fd598..6b8a8a4a8748439e90a85ca41f05fed07138a4c6 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.222 2003/11/29 19:51:49 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.223 2003/12/30 23:53:14 tgl Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -1074,9 +1074,10 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node) /* NB: this isn't a complete set of fields */ WRITE_NODE_FIELD(clause); WRITE_BOOL_FIELD(ispusheddown); - WRITE_NODE_FIELD(subclauseindices); + WRITE_BOOL_FIELD(canjoin); WRITE_BITMAPSET_FIELD(left_relids); WRITE_BITMAPSET_FIELD(right_relids); + WRITE_NODE_FIELD(subclauseindices); WRITE_OID_FIELD(mergejoinoperator); WRITE_OID_FIELD(left_sortop); WRITE_OID_FIELD(right_sortop); diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index b9ccc770a431c923b1fe4e510bb7de9ebc1bc215..c2fe837db65a71df189acb8fbce8050fb65d61a1 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.150 2003/12/18 00:22:12 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.151 2003/12/30 23:53:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -64,9 +64,11 @@ static List *group_clauses_by_indexkey_for_join(Query *root, Relids outer_relids, JoinType jointype, bool isouterjoin); static bool match_clause_to_indexcol(RelOptInfo *rel, IndexOptInfo *index, - int indexcol, Oid opclass, Expr *clause); + int indexcol, Oid opclass, + Expr *clause, RestrictInfo *rinfo); static bool match_join_clause_to_indexcol(RelOptInfo *rel, IndexOptInfo *index, - int indexcol, Oid opclass, Expr *clause); + int indexcol, Oid opclass, + RestrictInfo *rinfo); static Oid indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left); static bool pred_test(List *predicate_list, List *restrictinfo_list, @@ -374,14 +376,14 @@ match_or_subclause_to_indexkey(RelOptInfo *rel, foreach(item, ((BoolExpr *) clause)->args) { if (match_clause_to_indexcol(rel, index, 0, opclass, - lfirst(item))) + lfirst(item), NULL)) return true; } return false; } else return match_clause_to_indexcol(rel, index, 0, opclass, - clause); + clause, NULL); } /*---------- @@ -445,7 +447,7 @@ extract_or_indexqual_conditions(RelOptInfo *rel, if (match_clause_to_indexcol(rel, index, indexcol, curClass, - subsubclause)) + subsubclause, NULL)) FastConc(&clausegroup, expand_indexqual_condition(subsubclause, curClass)); @@ -453,7 +455,7 @@ extract_or_indexqual_conditions(RelOptInfo *rel, } else if (match_clause_to_indexcol(rel, index, indexcol, curClass, - orsubclause)) + orsubclause, NULL)) FastConc(&clausegroup, expand_indexqual_condition(orsubclause, curClass)); @@ -470,7 +472,7 @@ extract_or_indexqual_conditions(RelOptInfo *rel, if (match_clause_to_indexcol(rel, index, indexcol, curClass, - rinfo->clause)) + rinfo->clause, rinfo)) FastConc(&clausegroup, expand_indexqual_condition(rinfo->clause, curClass)); @@ -550,7 +552,8 @@ group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index) index, indexcol, curClass, - rinfo->clause)) + rinfo->clause, + rinfo)) FastAppend(&clausegroup, rinfo); } @@ -625,7 +628,8 @@ group_clauses_by_indexkey_for_join(Query *root, index, indexcol, curClass, - rinfo->clause)) + rinfo->clause, + rinfo)) FastAppend(&clausegroup, rinfo); } @@ -654,7 +658,7 @@ group_clauses_by_indexkey_for_join(Query *root, index, indexcol, curClass, - rinfo->clause)) + rinfo)) { FastAppend(&clausegroup, rinfo); if (!jfoundhere) @@ -726,6 +730,7 @@ group_clauses_by_indexkey_for_join(Query *root, * 'indexcol' is a column number of 'index' (counting from 0). * 'opclass' is the corresponding operator class. * 'clause' is the clause to be tested. + * 'rinfo' is the clause's RestrictInfo, if available (NULL if not). * * Returns true if the clause can be used with this index key. * @@ -737,7 +742,8 @@ match_clause_to_indexcol(RelOptInfo *rel, IndexOptInfo *index, int indexcol, Oid opclass, - Expr *clause) + Expr *clause, + RestrictInfo *rinfo) { Node *leftop, *rightop; @@ -754,9 +760,13 @@ match_clause_to_indexcol(RelOptInfo *rel, * Check for clauses of the form: (indexkey operator constant) or * (constant operator indexkey). Anything that is a "pseudo constant" * expression will do. + * + * If we have the RestrictInfo available, we can make a more efficient + * test for pseudo-constness. */ if (match_index_to_operand(leftop, indexcol, rel, index) && - is_pseudo_constant_clause(rightop)) + (rinfo ? is_pseudo_constant_clause_relids(rightop, rinfo->right_relids) + : is_pseudo_constant_clause(rightop))) { if (is_indexable_operator(clause, opclass, true)) return true; @@ -771,7 +781,8 @@ match_clause_to_indexcol(RelOptInfo *rel, } if (match_index_to_operand(rightop, indexcol, rel, index) && - is_pseudo_constant_clause(leftop)) + (rinfo ? is_pseudo_constant_clause_relids(leftop, rinfo->left_relids) + : is_pseudo_constant_clause(leftop))) { if (is_indexable_operator(clause, opclass, false)) return true; @@ -813,7 +824,7 @@ match_clause_to_indexcol(RelOptInfo *rel, * 'index' is an index on 'rel'. * 'indexcol' is a column number of 'index' (counting from 0). * 'opclass' is the corresponding operator class. - * 'clause' is the clause to be tested. + * 'rinfo' is the clause to be tested (as a RestrictInfo node). * * Returns true if the clause can be used with this index key. * @@ -825,8 +836,9 @@ match_join_clause_to_indexcol(RelOptInfo *rel, IndexOptInfo *index, int indexcol, Oid opclass, - Expr *clause) + RestrictInfo *rinfo) { + Expr *clause = rinfo->clause; Node *leftop, *rightop; @@ -846,27 +858,25 @@ match_join_clause_to_indexcol(RelOptInfo *rel, */ if (match_index_to_operand(leftop, indexcol, rel, index)) { - Relids othervarnos = pull_varnos(rightop); + Relids othervarnos = rinfo->right_relids; bool isIndexable; isIndexable = !bms_overlap(rel->relids, othervarnos) && !contain_volatile_functions(rightop) && is_indexable_operator(clause, opclass, true); - bms_free(othervarnos); return isIndexable; } if (match_index_to_operand(rightop, indexcol, rel, index)) { - Relids othervarnos = pull_varnos(leftop); + Relids othervarnos = rinfo->left_relids; bool isIndexable; isIndexable = !bms_overlap(rel->relids, othervarnos) && !contain_volatile_functions(leftop) && is_indexable_operator(clause, opclass, false); - bms_free(othervarnos); return isIndexable; } @@ -1351,7 +1361,6 @@ indexable_outerrelids(RelOptInfo *rel, IndexOptInfo *index) foreach(j, joininfo->jinfo_restrictinfo) { RestrictInfo *rinfo = (RestrictInfo *) lfirst(j); - Expr *clause = rinfo->clause; int indexcol = 0; Oid *classes = index->classlist; @@ -1363,7 +1372,7 @@ indexable_outerrelids(RelOptInfo *rel, IndexOptInfo *index) index, indexcol, curClass, - clause)) + rinfo)) { match_found = true; break; diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index 5b95ec7c4dd9df39b72d544d771ade6320fdac22..91cd0ab22a5f45dbdabd8025a22ce4459d7004e9 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.83 2003/11/29 19:51:50 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.84 2003/12/30 23:53:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -690,7 +690,7 @@ hash_inner_and_outer(Query *root, { RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i); - if (restrictinfo->left_relids == NULL || + if (!restrictinfo->canjoin || restrictinfo->hashjoinoperator == InvalidOid) continue; /* not hashjoinable */ @@ -809,12 +809,12 @@ select_mergejoin_clauses(RelOptInfo *joinrel, switch (jointype) { case JOIN_RIGHT: - if (restrictinfo->left_relids == NULL || + if (!restrictinfo->canjoin || restrictinfo->mergejoinoperator == InvalidOid) return NIL; /* not mergejoinable */ break; case JOIN_FULL: - if (restrictinfo->left_relids == NULL || + if (!restrictinfo->canjoin || restrictinfo->mergejoinoperator == InvalidOid) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -826,7 +826,7 @@ select_mergejoin_clauses(RelOptInfo *joinrel, } } - if (restrictinfo->left_relids == NULL || + if (!restrictinfo->canjoin || restrictinfo->mergejoinoperator == InvalidOid) continue; /* not mergejoinable */ diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 5612430a390fe6d0b1b79d0d4d9e0a3cae02e5b6..3da001e997a0167eb6a2f873b32d3c9dd11baecc 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.93 2003/11/29 19:51:50 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.94 2003/12/30 23:53:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -380,12 +380,13 @@ distribute_qual_to_rels(Query *root, Node *clause, bool can_be_equijoin; restrictinfo->clause = (Expr *) clause; + restrictinfo->canjoin = false; /* set below, if join clause */ + restrictinfo->left_relids = NULL; + restrictinfo->right_relids = NULL; restrictinfo->subclauseindices = NIL; restrictinfo->eval_cost.startup = -1; /* not computed until * needed */ restrictinfo->this_selec = -1; /* not computed until needed */ - restrictinfo->left_relids = NULL; /* set below, if join clause */ - restrictinfo->right_relids = NULL; restrictinfo->mergejoinoperator = InvalidOid; restrictinfo->left_sortop = InvalidOid; restrictinfo->right_sortop = InvalidOid; @@ -510,6 +511,15 @@ distribute_qual_to_rels(Query *root, Node *clause, restrictinfo->ispusheddown = ispusheddown || !bms_equal(relids, qualscope); + /* + * If it's a binary opclause, set up left/right relids info. + */ + if (is_opclause(clause) && length(((OpExpr *) clause)->args) == 2) + { + restrictinfo->left_relids = pull_varnos(get_leftop((Expr *) clause)); + restrictinfo->right_relids = pull_varnos(get_rightop((Expr *) clause)); + } + switch (bms_membership(relids)) { case BMS_SINGLETON: @@ -562,18 +572,11 @@ distribute_qual_to_rels(Query *root, Node *clause, */ if (is_opclause(clause) && length(((OpExpr *) clause)->args) == 2) { - Relids left_relids; - Relids right_relids; - - left_relids = pull_varnos(get_leftop((Expr *) clause)); - right_relids = pull_varnos(get_rightop((Expr *) clause)); - if (!bms_is_empty(left_relids) && - !bms_is_empty(right_relids) && - !bms_overlap(left_relids, right_relids)) - { - restrictinfo->left_relids = left_relids; - restrictinfo->right_relids = right_relids; - } + if (!bms_is_empty(restrictinfo->left_relids) && + !bms_is_empty(restrictinfo->right_relids) && + !bms_overlap(restrictinfo->left_relids, + restrictinfo->right_relids)) + restrictinfo->canjoin = true; } /* @@ -814,13 +817,14 @@ qual_is_redundant(Query *root, List *equalexprs; bool someadded; - newleft = get_leftop(restrictinfo->clause); - newright = get_rightop(restrictinfo->clause); - /* Never redundant unless vars appear on both sides */ - if (!contain_var_clause(newleft) || !contain_var_clause(newright)) + if (bms_is_empty(restrictinfo->left_relids) || + bms_is_empty(restrictinfo->right_relids)) return false; + newleft = get_leftop(restrictinfo->clause); + newright = get_rightop(restrictinfo->clause); + /* * Set cached pathkeys. NB: it is okay to do this now because this * routine is only invoked while we are generating implied equalities. diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index d6f0bb3ad2eff317545f20465432b4180a2d8410..35efa6bc63074fa14758c90b2c402cf24d288853 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.157 2003/12/28 21:57:37 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.158 2003/12/30 23:53:15 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -811,6 +811,20 @@ is_pseudo_constant_clause(Node *clause) return false; } +/* + * is_pseudo_constant_clause_relids + * Same as above, except caller already has available the var membership + * of the clause; this lets us avoid the contain_var_clause() scan. + */ +bool +is_pseudo_constant_clause_relids(Node *clause, Relids relids) +{ + if (bms_is_empty(relids) && + !contain_volatile_functions(clause)) + return true; + return false; +} + /* * pull_constant_clauses * Scan through a list of qualifications and separate "constant" quals diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c index 2ae122e92a904e8b0df4669ba2eb0b7aa1566154..f77966a22623d54952064f9dcc6f52b3c4efb7ef 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.20 2003/11/29 19:51:51 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.21 2003/12/30 23:53:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -227,15 +227,9 @@ join_clause_is_redundant(Query *root, if (redundant) { - /* - * It looks redundant, now check for "var = const" case. If - * left_relids/right_relids are set, then there are definitely - * vars on both sides; else we must check the hard way. - */ - if (rinfo->left_relids) - return true; /* var = var, so redundant */ - if (contain_var_clause(get_leftop(rinfo->clause)) && - contain_var_clause(get_rightop(rinfo->clause))) + /* It looks redundant, but check for "var = const" case */ + if (!bms_is_empty(rinfo->left_relids) && + !bms_is_empty(rinfo->right_relids)) return true; /* var = var, so redundant */ /* else var = const, not redundant */ } diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 6b205b20da5a2de1dcd05701e8a8be1f0a4eda9d..0d129f38ea1375d2793c756f0873a8c0bada3c53 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.87 2003/12/28 21:57:37 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.88 2003/12/30 23:53:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -596,6 +596,19 @@ typedef struct RestrictInfo bool ispusheddown; /* TRUE if clause was pushed down in level */ + /* + * This flag is set true if the clause looks potentially useful as a + * merge or hash join clause, that is if it is a binary opclause with + * nonoverlapping sets of relids referenced in the left and right sides. + * (Whether the operator is actually merge or hash joinable isn't + * checked, however.) + */ + bool canjoin; + + /* These fields are set for any binary opclause: */ + Relids left_relids; /* relids in left side of clause */ + Relids right_relids; /* relids in right side of clause */ + /* only used if clause is an OR clause: */ List *subclauseindices; /* indexes matching subclauses */ /* subclauseindices is a List of Lists of IndexOptInfos */ @@ -604,15 +617,6 @@ typedef struct RestrictInfo QualCost eval_cost; /* eval cost of clause; -1 if not yet set */ Selectivity this_selec; /* selectivity; -1 if not yet set */ - /* - * If the clause looks useful for joining --- that is, it is a binary - * opclause with nonoverlapping sets of relids referenced in the left - * and right sides --- then these two fields are set to sets of the - * referenced relids. Otherwise they are both NULL. - */ - Relids left_relids; /* relids in left side of join clause */ - Relids right_relids; /* relids in right side of join clause */ - /* valid if clause is mergejoinable, else InvalidOid: */ Oid mergejoinoperator; /* copy of clause operator */ Oid left_sortop; /* leftside sortop needed for mergejoin */ diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h index 7fb60b548e48af3a25e946c1c86381e78dad14c8..3e089256a51fb5d2c910b7c1c3e63e937b53514a 100644 --- a/src/include/optimizer/clauses.h +++ b/src/include/optimizer/clauses.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/clauses.h,v 1.69 2003/11/29 22:41:07 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.70 2003/12/30 23:53:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -54,6 +54,7 @@ extern bool contain_volatile_functions(Node *clause); extern bool contain_nonstrict_functions(Node *clause); extern bool is_pseudo_constant_clause(Node *clause); +extern bool is_pseudo_constant_clause_relids(Node *clause, Relids relids); extern List *pull_constant_clauses(List *quals, List **constantQual); extern bool has_distinct_on_clause(Query *query);