diff options
Diffstat (limited to 'src/backend/optimizer/path')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 69 | ||||
-rw-r--r-- | src/backend/optimizer/path/clausesel.c | 123 | ||||
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 4 | ||||
-rw-r--r-- | src/backend/optimizer/path/indxpath.c | 14 | ||||
-rw-r--r-- | src/backend/optimizer/path/joinrels.c | 8 | ||||
-rw-r--r-- | src/backend/optimizer/path/orindxpath.c | 40 |
6 files changed, 110 insertions, 148 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 243ff7c5a72..afb3259e736 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.73 2001/05/08 17:25:28 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.74 2001/05/20 20:28:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,8 +35,8 @@ static void set_base_rel_pathlists(Query *root); static void set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte); static void set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, - RangeTblEntry *rte, - List *inheritlist); + Index rti, RangeTblEntry *rte, + List *inheritlist); static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed, List *initial_rels); @@ -69,7 +69,7 @@ make_one_rel(Query *root) rel = make_fromexpr_rel(root, root->jointree); /* - * The result should join all the query's rels. + * The result should join all the query's base rels. */ Assert(length(rel->relids) == length(root->base_rel_list)); @@ -190,10 +190,11 @@ set_base_rel_pathlists(Query *root) /* Select cheapest path (pretty easy in this case...) */ set_cheapest(rel); } - else if ((inheritlist = expand_inherted_rtentry(root, rti)) != NIL) + else if ((inheritlist = expand_inherted_rtentry(root, rti, true)) + != NIL) { /* Relation is root of an inheritance tree, process specially */ - set_inherited_rel_pathlist(root, rel, rte, inheritlist); + set_inherited_rel_pathlist(root, rel, rti, rte, inheritlist); } else { @@ -210,8 +211,6 @@ set_base_rel_pathlists(Query *root) static void set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte) { - List *indices = find_secondary_indexes(rte->relid); - /* Mark rel with estimated output rows, width, etc */ set_baserel_size_estimates(root, rel); @@ -230,13 +229,9 @@ set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte) create_tidscan_paths(root, rel); /* Consider index paths for both simple and OR index clauses */ - create_index_paths(root, rel, indices); + create_index_paths(root, rel); - /* - * Note: create_or_index_paths depends on create_index_paths to have - * marked OR restriction clauses with relevant indices; this is why it - * doesn't need to be given the list of indices. - */ + /* create_index_paths must be done before create_or_index_paths */ create_or_index_paths(root, rel, rel->baserestrictinfo); /* Now find the cheapest of the paths for this rel */ @@ -248,14 +243,26 @@ set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte) * Build access paths for a inheritance tree rooted at rel * * inheritlist is a list of RT indexes of all tables in the inheritance tree, - * including the parent itself. Note we will not come here unless there's - * at least one child in addition to the parent. + * including a duplicate of the parent itself. Note we will not come here + * unless there's at least one child in addition to the parent. + * + * NOTE: the passed-in rel and RTE will henceforth represent the appended + * result of the whole inheritance tree. The members of inheritlist represent + * the individual tables --- in particular, the inheritlist member that is a + * duplicate of the parent RTE represents the parent table alone. + * We will generate plans to scan the individual tables that refer to + * the inheritlist RTEs, whereas Vars elsewhere in the plan tree that + * refer to the original RTE are taken to refer to the append output. + * In particular, this means we have separate RelOptInfos for the parent + * table and for the append output, which is a good thing because they're + * not the same size. */ static void -set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte, +set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, + Index rti, RangeTblEntry *rte, List *inheritlist) { - int parentRTindex = lfirsti(rel->relids); + int parentRTindex = rti; Oid parentOID = rte->relid; List *subpaths = NIL; List *il; @@ -268,7 +275,15 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte, elog(ERROR, "SELECT FOR UPDATE is not supported for inherit queries"); /* - * Recompute size estimates for whole inheritance tree + * The executor will check the parent table's access permissions when it + * examines the parent's inheritlist entry. There's no need to check + * twice, so turn off access check bits in the original RTE. + */ + rte->checkForRead = false; + rte->checkForWrite = false; + + /* + * Initialize to compute size estimates for whole inheritance tree */ rel->rows = 0; rel->width = 0; @@ -289,21 +304,17 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte, /* * Make a RelOptInfo for the child so we can do planning. Do NOT - * attach the RelOptInfo to the query's base_rel_list, however. - * - * NOTE: when childRTindex == parentRTindex, we create a second - * RelOptInfo for the same relation. This RelOptInfo will - * represent the parent table alone, whereas the original - * RelOptInfo represents the union of the inheritance tree - * members. + * attach the RelOptInfo to the query's base_rel_list, however, + * since the child is not part of the main join tree. Instead, + * the child RelOptInfo is added to other_rel_list. */ - childrel = make_base_rel(root, childRTindex); + childrel = build_other_rel(root, childRTindex); /* * Copy the parent's targetlist and restriction quals to the - * child, with attribute-number adjustment if needed. We don't + * child, with attribute-number adjustment as needed. We don't * bother to copy the join quals, since we can't do any joining - * here. + * of the individual tables. */ childrel->targetlist = (List *) adjust_inherited_attrs((Node *) rel->targetlist, diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index 2699b56cb37..78407fb833a 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -8,13 +8,15 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.43 2001/03/23 04:49:53 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.44 2001/05/20 20:28:18 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "catalog/pg_operator.h" +#include "catalog/pg_type.h" +#include "nodes/makefuncs.h" #include "optimizer/clauses.h" #include "optimizer/cost.h" #include "optimizer/plancat.h" @@ -24,6 +26,12 @@ #include "utils/lsyscache.h" +/* note that pg_type.h hardwires size of bool as 1 ... duplicate it */ +#define MAKEBOOLCONST(val,isnull) \ + ((Node *) makeConst(BOOLOID, 1, (Datum) (val), \ + (isnull), true, false, false)) + + /* * Data structure for accumulating info about possible range-query * clause pairs in clauselist_selectivity. @@ -39,7 +47,7 @@ typedef struct RangeQueryClause } RangeQueryClause; static void addRangeClause(RangeQueryClause **rqlist, Node *clause, - int flag, bool isLTsel, Selectivity s2); + bool varonleft, bool isLTsel, Selectivity s2); static Selectivity clause_selectivity(Query *root, Node *clause, int varRelid); @@ -131,35 +139,24 @@ clauselist_selectivity(Query *root, * match what clause_selectivity() would do in the cases it * handles. */ - if (varRelid != 0 || NumRelids(clause) == 1) + if (is_opclause(clause) && + (varRelid != 0 || NumRelids(clause) == 1)) { - int relidx; - AttrNumber attno; - Datum constval; - int flag; - - get_relattval(clause, varRelid, - &relidx, &attno, &constval, &flag); - if (relidx != 0) + Expr *expr = (Expr *) clause; + + if (length(expr->args) == 2) { - /* if get_relattval succeeded, it must be an opclause */ - Var *other; + bool varonleft = true; - other = (flag & SEL_RIGHT) ? get_rightop((Expr *) clause) : - get_leftop((Expr *) clause); - if (is_pseudo_constant_clause((Node *) other)) + if (is_pseudo_constant_clause(lsecond(expr->args)) || + (varonleft = false, + is_pseudo_constant_clause(lfirst(expr->args)))) { - Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno; + Oid opno = ((Oper *) expr->oper)->opno; RegProcedure oprrest = get_oprrest(opno); - if (!oprrest) - s2 = (Selectivity) 0.5; - else - s2 = restriction_selectivity(oprrest, opno, - getrelid(relidx, - root->rtable), - attno, - constval, flag); + s2 = restriction_selectivity(root, opno, + expr->args, varRelid); /* * If we reach here, we have computed the same result @@ -171,10 +168,12 @@ clauselist_selectivity(Query *root, switch (oprrest) { case F_SCALARLTSEL: - addRangeClause(&rqlist, clause, flag, true, s2); + addRangeClause(&rqlist, clause, + varonleft, true, s2); break; case F_SCALARGTSEL: - addRangeClause(&rqlist, clause, flag, false, s2); + addRangeClause(&rqlist, clause, + varonleft, false, s2); break; default: /* Just merge the selectivity in generically */ @@ -220,7 +219,7 @@ clauselist_selectivity(Query *root, * No data available --- use a default estimate that * is small, but not real small. */ - s2 = 0.01; + s2 = 0.005; } else { @@ -259,14 +258,13 @@ clauselist_selectivity(Query *root, */ static void addRangeClause(RangeQueryClause **rqlist, Node *clause, - int flag, bool isLTsel, Selectivity s2) + bool varonleft, bool isLTsel, Selectivity s2) { RangeQueryClause *rqelem; Node *var; bool is_lobound; - /* get_relattval sets flag&SEL_RIGHT if the var is on the LEFT. */ - if (flag & SEL_RIGHT) + if (varonleft) { var = (Node *) get_leftop((Expr *) clause); is_lobound = !isLTsel; /* x < something is high bound */ @@ -405,12 +403,12 @@ clause_selectivity(Query *root, * is equivalent to the clause reln.attribute = 't', so we * compute the selectivity as if that is what we have. */ - s1 = restriction_selectivity(F_EQSEL, + s1 = restriction_selectivity(root, BooleanEqualOperator, - rte->relid, - var->varattno, - BoolGetDatum(true), - SEL_CONSTANT | SEL_RIGHT); + makeList2(var, + MAKEBOOLCONST(true, + false)), + varRelid); } } } @@ -486,57 +484,14 @@ clause_selectivity(Query *root, if (is_join_clause) { /* Estimate selectivity for a join clause. */ - RegProcedure oprjoin = get_oprjoin(opno); - - /* - * if the oprjoin procedure is missing for whatever reason, - * use a selectivity of 0.5 - */ - if (!oprjoin) - s1 = (Selectivity) 0.5; - else - { - int relid1, - relid2; - AttrNumber attno1, - attno2; - Oid reloid1, - reloid2; - - get_rels_atts(clause, &relid1, &attno1, &relid2, &attno2); - reloid1 = relid1 ? getrelid(relid1, root->rtable) : InvalidOid; - reloid2 = relid2 ? getrelid(relid2, root->rtable) : InvalidOid; - s1 = join_selectivity(oprjoin, opno, - reloid1, attno1, - reloid2, attno2); - } + s1 = join_selectivity(root, opno, + ((Expr *) clause)->args); } else { /* Estimate selectivity for a restriction clause. */ - RegProcedure oprrest = get_oprrest(opno); - - /* - * if the oprrest procedure is missing for whatever reason, - * use a selectivity of 0.5 - */ - if (!oprrest) - s1 = (Selectivity) 0.5; - else - { - int relidx; - AttrNumber attno; - Datum constval; - int flag; - Oid reloid; - - get_relattval(clause, varRelid, - &relidx, &attno, &constval, &flag); - reloid = relidx ? getrelid(relidx, root->rtable) : InvalidOid; - s1 = restriction_selectivity(oprrest, opno, - reloid, attno, - constval, flag); - } + s1 = restriction_selectivity(root, opno, + ((Expr *) clause)->args, varRelid); } } else if (is_funcclause(clause)) @@ -555,7 +510,7 @@ clause_selectivity(Query *root, /* * Just for the moment! FIX ME! - vadim 02/04/98 */ - s1 = 1.0; + s1 = (Selectivity) 0.5; } else if (IsA(clause, RelabelType)) { diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index dddca240e95..b4379e4b39b 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -42,7 +42,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.73 2001/05/09 23:13:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.74 2001/05/20 20:28:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -773,7 +773,7 @@ estimate_hash_bucketsize(Query *root, Var *var) if (relid == InvalidOid) return 0.1; - rel = get_base_rel(root, var->varno); + rel = find_base_rel(root, var->varno); if (rel->tuples <= 0.0 || rel->rows <= 0.0) return 0.1; /* ensure we can divide below */ diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index ca19465c897..a5f5bb151da 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.104 2001/03/23 04:49:53 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.105 2001/05/20 20:28:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -127,18 +127,15 @@ static Const *string_to_const(const char *str, Oid datatype); * consideration in nested-loop joins. * * 'rel' is the relation for which we want to generate index paths - * 'indices' is a list of available indexes for 'rel' */ void -create_index_paths(Query *root, - RelOptInfo *rel, - List *indices) +create_index_paths(Query *root, RelOptInfo *rel) { List *restrictinfo_list = rel->baserestrictinfo; List *joininfo_list = rel->joininfo; List *ilist; - foreach(ilist, indices) + foreach(ilist, rel->indexlist) { IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist); List *restrictclauses; @@ -1435,10 +1432,10 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index, /* * Note that we are making a pathnode for a single-scan indexscan; - * therefore, both indexid and indexqual should be single-element + * therefore, both indexinfo and indexqual should be single-element * lists. */ - pathnode->indexid = makeListi1(index->indexoid); + pathnode->indexinfo = makeList1(index); pathnode->indexqual = makeList1(indexquals); /* We don't actually care what order the index scans in ... */ @@ -2030,7 +2027,6 @@ find_operator(const char *opname, Oid datatype) static Datum string_to_datum(const char *str, Oid datatype) { - /* * We cheat a little by assuming that textin() will do for bpchar and * varchar constants too... diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 929a977112d..3bde257a37e 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.52 2001/03/22 03:59:35 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.53 2001/05/20 20:28:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -332,7 +332,7 @@ make_rels_by_clauseless_joins(Query *root, /* * make_jointree_rel - * Find or build a RelOptInfojoin rel representing a specific + * Find or build a RelOptInfo join rel representing a specific * jointree item. For JoinExprs, we only consider the construction * path that corresponds exactly to what the user wrote. */ @@ -343,7 +343,7 @@ make_jointree_rel(Query *root, Node *jtnode) { int varno = ((RangeTblRef *) jtnode)->rtindex; - return get_base_rel(root, varno); + return build_base_rel(root, varno); } else if (IsA(jtnode, FromExpr)) { @@ -402,7 +402,7 @@ make_join_rel(Query *root, RelOptInfo *rel1, RelOptInfo *rel2, * Find or build the join RelOptInfo, and compute the restrictlist * that goes with this particular joining. */ - joinrel = get_join_rel(root, rel1, rel2, jointype, &restrictlist); + joinrel = build_join_rel(root, rel1, rel2, jointype, &restrictlist); /* * Consider paths using each rel as both outer and inner. diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c index d4e467c3e04..25cbc3e4fa2 100644 --- a/src/backend/optimizer/path/orindxpath.c +++ b/src/backend/optimizer/path/orindxpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.42 2001/01/24 19:42:58 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.43 2001/05/20 20:28:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -26,8 +26,8 @@ static void best_or_subclause_indices(Query *root, RelOptInfo *rel, IndexPath *pathnode); static void best_or_subclause_index(Query *root, RelOptInfo *rel, Expr *subclause, List *indices, + IndexOptInfo **retIndexInfo, List **retIndexQual, - Oid *retIndexid, Cost *retStartupCost, Cost *retTotalCost); @@ -122,14 +122,14 @@ create_or_index_paths(Query *root, * of an 'or' clause and the cost of scanning a relation using these * indices. The cost is the sum of the individual index costs, since * the executor will perform a scan for each subclause of the 'or'. + * Returns a list of IndexOptInfo nodes, one per scan. * - * This routine also creates the indexqual and indexid lists that will - * be needed by the executor. The indexqual list has one entry for each - * scan of the base rel, which is a sublist of indexqual conditions to - * apply in that scan. The implicit semantics are AND across each sublist - * of quals, and OR across the toplevel list (note that the executor - * takes care not to return any single tuple more than once). The indexid - * list gives the OID of the index to be used in each scan. + * This routine also creates the indexqual list that will be needed by + * the executor. The indexqual list has one entry for each scan of the base + * rel, which is a sublist of indexqual conditions to apply in that scan. + * The implicit semantics are AND across each sublist of quals, and OR across + * the toplevel list (note that the executor takes care not to return any + * single tuple more than once). * * 'rel' is the node of the relation on which the indexes are defined * 'subclauses' are the subclauses of the 'or' clause @@ -138,9 +138,9 @@ create_or_index_paths(Query *root, * 'pathnode' is the IndexPath node being built. * * Results are returned by setting these fields of the passed pathnode: + * 'indexinfo' gets a list of the index IndexOptInfo nodes, one per scan * 'indexqual' gets the constructed indexquals for the path (a list * of sublists of clauses, one sublist per scan of the base rel) - * 'indexid' gets a list of the index OIDs for each scan of the rel * 'startup_cost' and 'total_cost' get the complete path costs. * * 'startup_cost' is the startup cost for the first index scan only; @@ -161,28 +161,28 @@ best_or_subclause_indices(Query *root, { List *slist; + pathnode->indexinfo = NIL; pathnode->indexqual = NIL; - pathnode->indexid = NIL; pathnode->path.startup_cost = 0; pathnode->path.total_cost = 0; foreach(slist, subclauses) { Expr *subclause = lfirst(slist); + IndexOptInfo *best_indexinfo; List *best_indexqual; - Oid best_indexid; Cost best_startup_cost; Cost best_total_cost; best_or_subclause_index(root, rel, subclause, lfirst(indices), - &best_indexqual, &best_indexid, + &best_indexinfo, &best_indexqual, &best_startup_cost, &best_total_cost); - Assert(best_indexid != InvalidOid); + Assert(best_indexinfo != NULL); + pathnode->indexinfo = lappend(pathnode->indexinfo, best_indexinfo); pathnode->indexqual = lappend(pathnode->indexqual, best_indexqual); - pathnode->indexid = lappendi(pathnode->indexid, best_indexid); - if (slist == subclauses)/* first scan? */ + if (slist == subclauses) /* first scan? */ pathnode->path.startup_cost = best_startup_cost; pathnode->path.total_cost += best_total_cost; @@ -199,8 +199,8 @@ best_or_subclause_indices(Query *root, * 'rel' is the node of the relation on which the index is defined * 'subclause' is the OR subclause being considered * 'indices' is a list of IndexOptInfo nodes that match the subclause + * '*retIndexInfo' gets the IndexOptInfo of the best index * '*retIndexQual' gets a list of the indexqual conditions for the best index - * '*retIndexid' gets the OID of the best index * '*retStartupCost' gets the startup cost of a scan with that index * '*retTotalCost' gets the total cost of a scan with that index */ @@ -209,8 +209,8 @@ best_or_subclause_index(Query *root, RelOptInfo *rel, Expr *subclause, List *indices, + IndexOptInfo **retIndexInfo, /* return value */ List **retIndexQual, /* return value */ - Oid *retIndexid, /* return value */ Cost *retStartupCost, /* return value */ Cost *retTotalCost) /* return value */ { @@ -218,8 +218,8 @@ best_or_subclause_index(Query *root, List *ilist; /* if we don't match anything, return zeros */ + *retIndexInfo = NULL; *retIndexQual = NIL; - *retIndexid = InvalidOid; *retStartupCost = 0; *retTotalCost = 0; @@ -238,8 +238,8 @@ best_or_subclause_index(Query *root, if (first_time || subclause_path.total_cost < *retTotalCost) { + *retIndexInfo = index; *retIndexQual = indexqual; - *retIndexid = index->indexoid; *retStartupCost = subclause_path.startup_cost; *retTotalCost = subclause_path.total_cost; first_time = false; |