diff options
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 28 | ||||
-rw-r--r-- | src/backend/optimizer/path/clausesel.c | 4 | ||||
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 91 | ||||
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 67 | ||||
-rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 6 | ||||
-rw-r--r-- | src/backend/optimizer/plan/subselect.c | 9 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 4 | ||||
-rw-r--r-- | src/backend/optimizer/util/pathnode.c | 21 | ||||
-rw-r--r-- | src/backend/optimizer/util/relnode.c | 10 |
9 files changed, 215 insertions, 25 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 9368723188f..1e9074186c2 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.83 2001/12/10 22:54:12 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.84 2002/05/12 20:10:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -42,6 +42,8 @@ static void set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, List *inheritlist); static void set_subquery_pathlist(Query *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte); +static void set_function_pathlist(Query *root, RelOptInfo *rel, + RangeTblEntry *rte); static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed, List *initial_rels); @@ -98,11 +100,16 @@ set_base_rel_pathlists(Query *root) rti = lfirsti(rel->relids); rte = rt_fetch(rti, root->rtable); - if (rel->issubquery) + if (rel->rtekind == RTE_SUBQUERY) { /* Subquery --- generate a separate plan for it */ set_subquery_pathlist(root, rel, rti, rte); } + else if (rel->rtekind == RTE_FUNCTION) + { + /* RangeFunction --- generate a separate plan for it */ + set_function_pathlist(root, rel, rte); + } else if ((inheritlist = expand_inherted_rtentry(root, rti, true)) != NIL) { @@ -386,6 +393,23 @@ set_subquery_pathlist(Query *root, RelOptInfo *rel, } /* + * set_function_pathlist + * Build the (single) access path for a function RTE + */ +static void +set_function_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte) +{ + /* Mark rel with estimated output rows, width, etc */ + set_function_size_estimates(root, rel); + + /* Generate appropriate path */ + add_path(rel, create_functionscan_path(root, rel)); + + /* Select cheapest path (pretty easy in this case...) */ + set_cheapest(rel); +} + +/* * make_fromexpr_rel * Build access paths for a FromExpr jointree node. */ diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index 85584bfdcfc..35a98031004 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.49 2002/03/06 06:09:50 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.50 2002/05/12 20:10:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -381,7 +381,7 @@ clause_selectivity(Query *root, { RangeTblEntry *rte = rt_fetch(var->varno, root->rtable); - if (rte->subquery) + if (rte->rtekind == RTE_SUBQUERY) { /* * XXX not smart about subquery references... any way to diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 2bc0bb8a137..b14322f45b5 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.83 2002/03/12 00:51:42 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.84 2002/05/12 20:10:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -111,7 +111,7 @@ cost_seqscan(Path *path, Query *root, /* Should only be applied to base relations */ Assert(length(baserel->relids) == 1); - Assert(!baserel->issubquery); + Assert(baserel->rtekind == RTE_RELATION); if (!enable_seqscan) startup_cost += disable_cost; @@ -224,9 +224,10 @@ cost_index(Path *path, Query *root, b; /* Should only be applied to base relations */ - Assert(IsA(baserel, RelOptInfo) &&IsA(index, IndexOptInfo)); + Assert(IsA(baserel, RelOptInfo) && + IsA(index, IndexOptInfo)); Assert(length(baserel->relids) == 1); - Assert(!baserel->issubquery); + Assert(baserel->rtekind == RTE_RELATION); if (!enable_indexscan && !is_injoin) startup_cost += disable_cost; @@ -372,6 +373,10 @@ cost_tidscan(Path *path, Query *root, Cost cpu_per_tuple; int ntuples = length(tideval); + /* Should only be applied to base relations */ + Assert(length(baserel->relids) == 1); + Assert(baserel->rtekind == RTE_RELATION); + if (!enable_tidscan) startup_cost += disable_cost; @@ -387,6 +392,36 @@ cost_tidscan(Path *path, Query *root, } /* + * cost_functionscan + * Determines and returns the cost of scanning a function RTE. + */ +void +cost_functionscan(Path *path, Query *root, RelOptInfo *baserel) +{ + Cost startup_cost = 0; + Cost run_cost = 0; + Cost cpu_per_tuple; + + /* Should only be applied to base relations that are functions */ + Assert(length(baserel->relids) == 1); + Assert(baserel->rtekind == RTE_FUNCTION); + + /* + * For now, estimate function's cost at one operator eval per function + * call. Someday we should revive the function cost estimate columns in + * pg_proc... + */ + cpu_per_tuple = cpu_operator_cost; + + /* Add scanning CPU costs */ + cpu_per_tuple += cpu_tuple_cost + baserel->baserestrictcost; + run_cost += cpu_per_tuple * baserel->tuples; + + path->startup_cost = startup_cost; + path->total_cost = startup_cost + run_cost; +} + +/* * cost_sort * Determines and returns the cost of sorting a relation. * @@ -1299,6 +1334,54 @@ set_joinrel_size_estimates(Query *root, RelOptInfo *rel, } /* + * set_function_size_estimates + * Set the size estimates for a base relation that is a function call. + * + * The rel's targetlist and restrictinfo list must have been constructed + * already. + * + * We set the following fields of the rel node: + * rows: the estimated number of output tuples (after applying + * restriction clauses). + * width: the estimated average output tuple width in bytes. + * baserestrictcost: estimated cost of evaluating baserestrictinfo clauses. + */ +void +set_function_size_estimates(Query *root, RelOptInfo *rel) +{ + /* Should only be applied to base relations that are functions */ + Assert(length(rel->relids) == 1); + Assert(rel->rtekind == RTE_FUNCTION); + + /* + * Estimate number of rows the function itself will return. + * + * XXX no idea how to do this yet; but should at least check whether + * function returns set or not... + */ + rel->tuples = 1000; + + /* Now estimate number of output rows */ + rel->rows = rel->tuples * + restrictlist_selectivity(root, + rel->baserestrictinfo, + lfirsti(rel->relids)); + + /* + * Force estimate to be at least one row, to make explain output look + * better and to avoid possible divide-by-zero when interpolating + * cost. + */ + if (rel->rows < 1.0) + rel->rows = 1.0; + + rel->baserestrictcost = cost_qual_eval(rel->baserestrictinfo); + + set_rel_width(root, rel); +} + + +/* * set_rel_width * Set the estimated output width of the relation. * diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index c20abacca39..cd8b0e6612f 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.113 2002/04/28 19:54:28 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.114 2002/05/12 20:10:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -43,6 +43,8 @@ static TidScan *create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses); static SubqueryScan *create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses); +static FunctionScan *create_functionscan_plan(Path *best_path, + List *tlist, List *scan_clauses); static NestLoop *create_nestloop_plan(Query *root, NestPath *best_path, List *tlist, List *joinclauses, List *otherclauses, @@ -77,6 +79,8 @@ static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid, ScanDirection indexscandir); static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid, List *tideval); +static FunctionScan *make_functionscan(List *qptlist, List *qpqual, + Index scanrelid); static NestLoop *make_nestloop(List *tlist, List *joinclauses, List *otherclauses, Plan *lefttree, Plan *righttree, @@ -119,6 +123,7 @@ create_plan(Query *root, Path *best_path) case T_SeqScan: case T_TidScan: case T_SubqueryScan: + case T_FunctionScan: plan = (Plan *) create_scan_plan(root, best_path); break; case T_HashJoin: @@ -200,6 +205,12 @@ create_scan_plan(Query *root, Path *best_path) scan_clauses); break; + case T_FunctionScan: + plan = (Scan *) create_functionscan_plan(best_path, + tlist, + scan_clauses); + break; + default: elog(ERROR, "create_scan_plan: unknown node type: %d", best_path->pathtype); @@ -353,7 +364,7 @@ create_seqscan_plan(Path *best_path, List *tlist, List *scan_clauses) /* there should be exactly one base rel involved... */ Assert(length(best_path->parent->relids) == 1); - Assert(!best_path->parent->issubquery); + Assert(best_path->parent->rtekind == RTE_RELATION); scan_relid = (Index) lfirsti(best_path->parent->relids); @@ -397,7 +408,7 @@ create_indexscan_plan(Query *root, /* there should be exactly one base rel involved... */ Assert(length(best_path->path.parent->relids) == 1); - Assert(!best_path->path.parent->issubquery); + Assert(best_path->path.parent->rtekind == RTE_RELATION); baserelid = lfirsti(best_path->path.parent->relids); @@ -515,7 +526,7 @@ create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses) /* there should be exactly one base rel involved... */ Assert(length(best_path->path.parent->relids) == 1); - Assert(!best_path->path.parent->issubquery); + Assert(best_path->path.parent->rtekind == RTE_RELATION); scan_relid = (Index) lfirsti(best_path->path.parent->relids); @@ -546,7 +557,7 @@ create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses) /* there should be exactly one base rel involved... */ Assert(length(best_path->parent->relids) == 1); /* and it must be a subquery */ - Assert(best_path->parent->issubquery); + Assert(best_path->parent->rtekind == RTE_SUBQUERY); scan_relid = (Index) lfirsti(best_path->parent->relids); @@ -558,6 +569,31 @@ create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses) return scan_plan; } +/* + * create_functionscan_plan + * Returns a functionscan plan for the base relation scanned by 'best_path' + * with restriction clauses 'scan_clauses' and targetlist 'tlist'. + */ +static FunctionScan * +create_functionscan_plan(Path *best_path, List *tlist, List *scan_clauses) +{ + FunctionScan *scan_plan; + Index scan_relid; + + /* there should be exactly one base rel involved... */ + Assert(length(best_path->parent->relids) == 1); + /* and it must be a function */ + Assert(best_path->parent->rtekind == RTE_FUNCTION); + + scan_relid = (Index) lfirsti(best_path->parent->relids); + + scan_plan = make_functionscan(tlist, scan_clauses, scan_relid); + + copy_path_costsize(&scan_plan->scan.plan, best_path); + + return scan_plan; +} + /***************************************************************************** * * JOIN METHODS @@ -791,6 +827,7 @@ create_mergejoin_plan(Query *root, { case T_SeqScan: case T_IndexScan: + case T_FunctionScan: case T_Material: case T_Sort: /* OK, these inner plans support mark/restore */ @@ -1305,6 +1342,26 @@ make_subqueryscan(List *qptlist, return node; } +static FunctionScan * +make_functionscan(List *qptlist, + List *qpqual, + Index scanrelid) +{ + FunctionScan *node = makeNode(FunctionScan); + Plan *plan = &node->scan.plan; + + /* cost should be inserted by caller */ + plan->state = (EState *) NULL; + plan->targetlist = qptlist; + plan->qual = qpqual; + plan->lefttree = NULL; + plan->righttree = NULL; + node->scan.scanrelid = scanrelid; + node->scan.scanstate = (CommonScanState *) NULL; + + return node; +} + Append * make_append(List *appendplans, bool isTarget, List *tlist) { diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 807876e4a72..3e07b2425e5 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.75 2002/04/28 19:54:28 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.76 2002/05/12 20:10:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -120,6 +120,10 @@ set_plan_references(Query *root, Plan *plan) /* Recurse into subplan too */ set_plan_references(root, ((SubqueryScan *) plan)->subplan); break; + case T_FunctionScan: + fix_expr_references(plan, (Node *) plan->targetlist); + fix_expr_references(plan, (Node *) plan->qual); + break; case T_NestLoop: set_join_references(root, (Join *) plan); fix_expr_references(plan, (Node *) plan->targetlist); diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index a67eb5d8e54..57930e9a502 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.51 2002/04/16 23:08:11 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.52 2002/05/12 20:10:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -352,13 +352,13 @@ make_subplan(SubLink *slink) } break; case T_Material: + case T_FunctionScan: case T_Sort: /* * Don't add another Material node if there's one - * already, nor if the top node is a Sort, since Sort - * materializes its output anyway. (I doubt either - * case can happen in practice for a subplan, but...) + * already, nor if the top node is any other type that + * materializes its output anyway. */ use_material = false; break; @@ -686,6 +686,7 @@ SS_finalize_plan(Plan *plan) case T_SetOp: case T_Limit: case T_Group: + case T_FunctionScan: break; default: diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 1b7cc14e2e7..1a278e9ca2e 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.97 2002/04/28 19:54:28 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.98 2002/05/12 20:10:03 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -1922,6 +1922,7 @@ query_tree_walker(Query *query, { case RTE_RELATION: case RTE_SPECIAL: + case RTE_FUNCTION: /* nothing to do */ break; case RTE_SUBQUERY: @@ -2309,6 +2310,7 @@ query_tree_mutator(Query *query, { case RTE_RELATION: case RTE_SPECIAL: + case RTE_FUNCTION: /* nothing to do, don't bother to make a copy */ break; case RTE_SUBQUERY: diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index c86ee450082..07d05b38a87 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.76 2001/10/25 05:49:34 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.77 2002/05/12 20:10:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -455,6 +455,25 @@ create_subqueryscan_path(RelOptInfo *rel) } /* + * create_functionscan_path + * Creates a path corresponding to a sequential scan of a function, + * returning the pathnode. + */ +Path * +create_functionscan_path(Query *root, RelOptInfo *rel) +{ + Path *pathnode = makeNode(Path); + + pathnode->pathtype = T_FunctionScan; + pathnode->parent = rel; + pathnode->pathkeys = NIL; /* for now, assume unordered result */ + + cost_functionscan(pathnode, root, rel); + + return pathnode; +} + +/* * create_nestloop_path * Creates a pathnode corresponding to a nestloop join between two * relations. diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 0fad16fbdd0..38e988b26fc 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.36 2002/03/12 00:51:51 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.37 2002/05/12 20:10:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -140,7 +140,7 @@ make_base_rel(Query *root, int relid) rel->cheapest_startup_path = NULL; rel->cheapest_total_path = NULL; rel->pruneable = true; - rel->issubquery = false; + rel->rtekind = rte->rtekind; rel->indexlist = NIL; rel->pages = 0; rel->tuples = 0; @@ -168,8 +168,8 @@ make_base_rel(Query *root, int relid) break; } case RTE_SUBQUERY: - /* Subquery --- mark it as such for later processing */ - rel->issubquery = true; + case RTE_FUNCTION: + /* Subquery or function --- nothing to do here */ break; case RTE_JOIN: /* Join --- must be an otherrel */ @@ -351,7 +351,7 @@ build_join_rel(Query *root, joinrel->cheapest_startup_path = NULL; joinrel->cheapest_total_path = NULL; joinrel->pruneable = true; - joinrel->issubquery = false; + joinrel->rtekind = RTE_JOIN; joinrel->indexlist = NIL; joinrel->pages = 0; joinrel->tuples = 0; |