mirror of
https://github.com/postgres/postgres.git
synced 2025-11-13 16:22:44 +03:00
Subselects in FROM clause, per ISO syntax: FROM (SELECT ...) [AS] alias.
(Don't forget that an alias is required.) Views reimplemented as expanding to subselect-in-FROM. Grouping, aggregates, DISTINCT in views actually work now (he says optimistically). No UNION support in subselects/views yet, but I have some ideas about that. Rule-related permissions checking moved out of rewriter and into executor. INITDB REQUIRED!
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.64 2000/09/19 18:42:34 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.65 2000/09/29 18:21:31 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -19,6 +19,9 @@
|
||||
#include "optimizer/geqo.h"
|
||||
#include "optimizer/pathnode.h"
|
||||
#include "optimizer/paths.h"
|
||||
#include "optimizer/plancat.h"
|
||||
#include "optimizer/planner.h"
|
||||
#include "parser/parsetree.h"
|
||||
|
||||
|
||||
bool enable_geqo = true;
|
||||
@@ -26,7 +29,6 @@ int geqo_rels = DEFAULT_GEQO_RELS;
|
||||
|
||||
|
||||
static void set_base_rel_pathlist(Query *root);
|
||||
static List *build_jointree_rels(Query *root);
|
||||
static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed,
|
||||
List *initial_rels);
|
||||
|
||||
@@ -44,20 +46,7 @@ static void debug_print_rel(Query *root, RelOptInfo *rel);
|
||||
RelOptInfo *
|
||||
make_one_rel(Query *root)
|
||||
{
|
||||
int levels_needed;
|
||||
List *initial_rels;
|
||||
|
||||
/*
|
||||
* Count the number of top-level jointree nodes. This is the depth
|
||||
* of the dynamic-programming algorithm we must employ to consider
|
||||
* all ways of joining the top-level nodes. Currently, we build
|
||||
* JoinExpr joins in exactly the order implied by the join expression,
|
||||
* so no dynamic-programming search is needed within a JoinExpr.
|
||||
*/
|
||||
levels_needed = length(root->jointree);
|
||||
|
||||
if (levels_needed <= 0)
|
||||
return NULL; /* nothing to do? */
|
||||
RelOptInfo *rel;
|
||||
|
||||
/*
|
||||
* Generate access paths for the base rels.
|
||||
@@ -65,27 +54,18 @@ make_one_rel(Query *root)
|
||||
set_base_rel_pathlist(root);
|
||||
|
||||
/*
|
||||
* Construct a list of rels corresponding to the toplevel jointree nodes.
|
||||
* This may contain both base rels and rels constructed according to
|
||||
* explicit JOIN directives.
|
||||
* Generate access paths for the entire join tree.
|
||||
*/
|
||||
initial_rels = build_jointree_rels(root);
|
||||
Assert(root->jointree != NULL && IsA(root->jointree, FromExpr));
|
||||
|
||||
if (levels_needed == 1)
|
||||
{
|
||||
/*
|
||||
* Single jointree node, so we're done.
|
||||
*/
|
||||
return (RelOptInfo *) lfirst(initial_rels);
|
||||
}
|
||||
else
|
||||
{
|
||||
rel = make_fromexpr_rel(root, root->jointree);
|
||||
|
||||
/*
|
||||
* Generate join tree.
|
||||
*/
|
||||
return make_one_rel_by_joins(root, levels_needed, initial_rels);
|
||||
}
|
||||
/*
|
||||
* The result should join all the query's rels.
|
||||
*/
|
||||
Assert(length(rel->relids) == length(root->base_rel_list));
|
||||
|
||||
return rel;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -102,36 +82,67 @@ set_base_rel_pathlist(Query *root)
|
||||
foreach(rellist, root->base_rel_list)
|
||||
{
|
||||
RelOptInfo *rel = (RelOptInfo *) lfirst(rellist);
|
||||
List *indices = find_relation_indices(root, rel);
|
||||
RangeTblEntry *rte;
|
||||
|
||||
/* Mark rel with estimated output rows, width, etc */
|
||||
set_baserel_size_estimates(root, rel);
|
||||
Assert(length(rel->relids) == 1); /* better be base rel */
|
||||
rte = rt_fetch(lfirsti(rel->relids), root->rtable);
|
||||
|
||||
/*
|
||||
* Generate paths and add them to the rel's pathlist.
|
||||
*
|
||||
* Note: add_path() will discard any paths that are dominated by
|
||||
* another available path, keeping only those paths that are
|
||||
* superior along at least one dimension of cost or sortedness.
|
||||
*/
|
||||
if (rel->issubquery)
|
||||
{
|
||||
/* Subquery --- generate a separate plan for it */
|
||||
|
||||
/* Consider sequential scan */
|
||||
add_path(rel, create_seqscan_path(rel));
|
||||
/*
|
||||
* XXX for now, we just apply any restrict clauses that came
|
||||
* from the outer query as qpquals of the SubqueryScan node.
|
||||
* Later, think about pushing them down into the subquery itself.
|
||||
*/
|
||||
|
||||
/* Consider TID scans */
|
||||
create_tidscan_paths(root, rel);
|
||||
/* Generate the plan for the subquery */
|
||||
rel->subplan = planner(rte->subquery);
|
||||
|
||||
/* Consider index paths for both simple and OR index clauses */
|
||||
create_index_paths(root, rel, indices,
|
||||
rel->baserestrictinfo,
|
||||
rel->joininfo);
|
||||
/* Copy number of output rows from subplan */
|
||||
rel->tuples = rel->subplan->plan_rows;
|
||||
|
||||
/*
|
||||
* 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_or_index_paths(root, rel, rel->baserestrictinfo);
|
||||
/* Mark rel with estimated output rows, width, etc */
|
||||
set_baserel_size_estimates(root, rel);
|
||||
|
||||
/* Generate appropriate path */
|
||||
add_path(rel, create_subqueryscan_path(rel));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Plain relation */
|
||||
List *indices = find_secondary_indexes(rte->relid);
|
||||
|
||||
/* Mark rel with estimated output rows, width, etc */
|
||||
set_baserel_size_estimates(root, rel);
|
||||
|
||||
/*
|
||||
* Generate paths and add them to the rel's pathlist.
|
||||
*
|
||||
* Note: add_path() will discard any paths that are dominated by
|
||||
* another available path, keeping only those paths that are
|
||||
* superior along at least one dimension of cost or sortedness.
|
||||
*/
|
||||
|
||||
/* Consider sequential scan */
|
||||
add_path(rel, create_seqscan_path(rel));
|
||||
|
||||
/* Consider TID scans */
|
||||
create_tidscan_paths(root, rel);
|
||||
|
||||
/* Consider index paths for both simple and OR index clauses */
|
||||
create_index_paths(root, rel, indices,
|
||||
rel->baserestrictinfo,
|
||||
rel->joininfo);
|
||||
|
||||
/*
|
||||
* 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_or_index_paths(root, rel, rel->baserestrictinfo);
|
||||
}
|
||||
|
||||
/* Now find the cheapest of the paths for this rel */
|
||||
set_cheapest(rel);
|
||||
@@ -139,26 +150,57 @@ set_base_rel_pathlist(Query *root)
|
||||
}
|
||||
|
||||
/*
|
||||
* build_jointree_rels
|
||||
* Construct a RelOptInfo for each item in the query's jointree.
|
||||
*
|
||||
* At present, we handle explicit joins in the FROM clause exactly as
|
||||
* specified, with no search for other join orders. Only the cross-product
|
||||
* joins at the top level are involved in the dynamic-programming search.
|
||||
* make_fromexpr_rel
|
||||
* Build access paths for a FromExpr jointree node.
|
||||
*/
|
||||
static List *
|
||||
build_jointree_rels(Query *root)
|
||||
RelOptInfo *
|
||||
make_fromexpr_rel(Query *root, FromExpr *from)
|
||||
{
|
||||
List *rels = NIL;
|
||||
int levels_needed;
|
||||
List *initial_rels = NIL;
|
||||
List *jt;
|
||||
|
||||
foreach(jt, root->jointree)
|
||||
/*
|
||||
* Count the number of child jointree nodes. This is the depth
|
||||
* of the dynamic-programming algorithm we must employ to consider
|
||||
* all ways of joining the child nodes.
|
||||
*/
|
||||
levels_needed = length(from->fromlist);
|
||||
|
||||
if (levels_needed <= 0)
|
||||
return NULL; /* nothing to do? */
|
||||
|
||||
/*
|
||||
* Construct a list of rels corresponding to the child jointree nodes.
|
||||
* This may contain both base rels and rels constructed according to
|
||||
* explicit JOIN directives.
|
||||
*/
|
||||
foreach(jt, from->fromlist)
|
||||
{
|
||||
Node *jtnode = (Node *) lfirst(jt);
|
||||
|
||||
rels = lappend(rels, make_rel_from_jointree(root, jtnode));
|
||||
initial_rels = lappend(initial_rels,
|
||||
make_jointree_rel(root, jtnode));
|
||||
}
|
||||
|
||||
if (levels_needed == 1)
|
||||
{
|
||||
/*
|
||||
* Single jointree node, so we're done.
|
||||
*/
|
||||
return (RelOptInfo *) lfirst(initial_rels);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Consider the different orders in which we could join the rels,
|
||||
* using either GEQO or regular optimizer.
|
||||
*/
|
||||
if (enable_geqo && levels_needed >= geqo_rels)
|
||||
return geqo(root, levels_needed, initial_rels);
|
||||
else
|
||||
return make_one_rel_by_joins(root, levels_needed, initial_rels);
|
||||
}
|
||||
return rels;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -182,14 +224,6 @@ make_one_rel_by_joins(Query *root, int levels_needed, List *initial_rels)
|
||||
int lev;
|
||||
RelOptInfo *rel;
|
||||
|
||||
/*******************************************
|
||||
* genetic query optimizer entry point *
|
||||
* <utesch@aut.tu-freiberg.de> *
|
||||
* rest will be skipped in case of GEQO *
|
||||
*******************************************/
|
||||
if (enable_geqo && levels_needed >= geqo_rels)
|
||||
return geqo(root, levels_needed, initial_rels);
|
||||
|
||||
/*
|
||||
* We employ a simple "dynamic programming" algorithm: we first find
|
||||
* all ways to build joins of two jointree items, then all ways to
|
||||
@@ -243,12 +277,11 @@ make_one_rel_by_joins(Query *root, int levels_needed, List *initial_rels)
|
||||
}
|
||||
|
||||
/*
|
||||
* We should have a single rel at the final level,
|
||||
* representing the join of all the base rels.
|
||||
* We should have a single rel at the final level.
|
||||
*/
|
||||
Assert(length(joinitems[levels_needed]) == 1);
|
||||
|
||||
rel = (RelOptInfo *) lfirst(joinitems[levels_needed]);
|
||||
Assert(length(rel->relids) == length(root->base_rel_list));
|
||||
|
||||
return rel;
|
||||
}
|
||||
|
||||
@@ -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.62 2000/06/18 22:44:06 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.63 2000/09/29 18:21:32 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -115,6 +115,7 @@ cost_seqscan(Path *path, RelOptInfo *baserel)
|
||||
|
||||
/* Should only be applied to base relations */
|
||||
Assert(length(baserel->relids) == 1);
|
||||
Assert(!baserel->issubquery);
|
||||
|
||||
if (!enable_seqscan)
|
||||
startup_cost += disable_cost;
|
||||
@@ -223,6 +224,7 @@ cost_index(Path *path, Query *root,
|
||||
/* Should only be applied to base relations */
|
||||
Assert(IsA(baserel, RelOptInfo) &&IsA(index, IndexOptInfo));
|
||||
Assert(length(baserel->relids) == 1);
|
||||
Assert(!baserel->issubquery);
|
||||
|
||||
if (!enable_indexscan && !is_injoin)
|
||||
startup_cost += disable_cost;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.96 2000/09/15 18:45:25 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.97 2000/09/29 18:21:32 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -464,7 +464,7 @@ extract_or_indexqual_conditions(RelOptInfo *rel,
|
||||
else
|
||||
{
|
||||
/* we assume the caller passed a valid indexable qual */
|
||||
quals = lcons(orsubclause, NIL);
|
||||
quals = makeList1(orsubclause);
|
||||
}
|
||||
|
||||
return expand_indexqual_conditions(quals);
|
||||
@@ -1504,7 +1504,7 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
|
||||
RestrictInfo *clause = (RestrictInfo *) lfirst(temp);
|
||||
|
||||
indexquals = lappend(indexquals, clause->clause);
|
||||
if (! clause->isjoinqual)
|
||||
if (clause->ispusheddown)
|
||||
alljoinquals = false;
|
||||
}
|
||||
|
||||
@@ -1516,8 +1516,8 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
|
||||
* therefore, both indexid and indexqual should be single-element
|
||||
* lists.
|
||||
*/
|
||||
pathnode->indexid = lconsi(index->indexoid, NIL);
|
||||
pathnode->indexqual = lcons(indexquals, NIL);
|
||||
pathnode->indexid = makeListi1(index->indexoid);
|
||||
pathnode->indexqual = makeList1(indexquals);
|
||||
|
||||
/* We don't actually care what order the index scans in ... */
|
||||
pathnode->indexscandir = NoMovementScanDirection;
|
||||
@@ -1541,7 +1541,7 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
|
||||
*/
|
||||
pathnode->rows = rel->tuples *
|
||||
restrictlist_selectivity(root,
|
||||
LispUnion(rel->baserestrictinfo,
|
||||
set_union(rel->baserestrictinfo,
|
||||
clausegroup),
|
||||
lfirsti(rel->relids));
|
||||
/* Like costsize.c, force estimate to be at least one row */
|
||||
@@ -2034,7 +2034,7 @@ prefix_quals(Var *leftop, Oid expr_op,
|
||||
con = string_to_const(prefix, datatype);
|
||||
op = makeOper(oproid, InvalidOid, BOOLOID);
|
||||
expr = make_opclause(op, leftop, (Var *) con);
|
||||
result = lcons(expr, NIL);
|
||||
result = makeList1(expr);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2049,7 +2049,7 @@ prefix_quals(Var *leftop, Oid expr_op,
|
||||
con = string_to_const(prefix, datatype);
|
||||
op = makeOper(oproid, InvalidOid, BOOLOID);
|
||||
expr = make_opclause(op, leftop, (Var *) con);
|
||||
result = lcons(expr, NIL);
|
||||
result = makeList1(expr);
|
||||
|
||||
/*
|
||||
* If we can create a string larger than the prefix, say "x <
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.56 2000/09/12 21:06:53 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.57 2000/09/29 18:21:32 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -643,10 +643,10 @@ hash_inner_and_outer(Query *root,
|
||||
continue; /* not hashjoinable */
|
||||
|
||||
/*
|
||||
* If processing an outer join, only use explicit join clauses for
|
||||
* If processing an outer join, only use its own join clauses for
|
||||
* hashing. For inner joins we need not be so picky.
|
||||
*/
|
||||
if (isouterjoin && !restrictinfo->isjoinqual)
|
||||
if (isouterjoin && restrictinfo->ispusheddown)
|
||||
continue;
|
||||
|
||||
clause = restrictinfo->clause;
|
||||
@@ -665,7 +665,7 @@ hash_inner_and_outer(Query *root,
|
||||
continue; /* no good for these input relations */
|
||||
|
||||
/* always a one-element list of hash clauses */
|
||||
hashclauses = lcons(restrictinfo, NIL);
|
||||
hashclauses = makeList1(restrictinfo);
|
||||
|
||||
/* estimate disbursion of inner var for costing purposes */
|
||||
innerdisbursion = estimate_disbursion(root, inner);
|
||||
@@ -820,7 +820,7 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
|
||||
*right;
|
||||
|
||||
/*
|
||||
* If processing an outer join, only use explicit join clauses in the
|
||||
* If processing an outer join, only use its own join clauses in the
|
||||
* merge. For inner joins we need not be so picky.
|
||||
*
|
||||
* Furthermore, if it is a right/full join then *all* the explicit
|
||||
@@ -832,7 +832,7 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
|
||||
*/
|
||||
if (isouterjoin)
|
||||
{
|
||||
if (!restrictinfo->isjoinqual)
|
||||
if (restrictinfo->ispusheddown)
|
||||
continue;
|
||||
switch (jointype)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.47 2000/09/12 21:06:53 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.48 2000/09/29 18:21:32 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -307,13 +307,13 @@ make_rels_by_clauseless_joins(Query *root,
|
||||
|
||||
|
||||
/*
|
||||
* make_rel_from_jointree
|
||||
* make_jointree_rel
|
||||
* Find or build a RelOptInfojoin rel representing a specific
|
||||
* jointree item. For JoinExprs, we only consider the construction
|
||||
* path that corresponds exactly to what the user wrote.
|
||||
*/
|
||||
RelOptInfo *
|
||||
make_rel_from_jointree(Query *root, Node *jtnode)
|
||||
make_jointree_rel(Query *root, Node *jtnode)
|
||||
{
|
||||
if (IsA(jtnode, RangeTblRef))
|
||||
{
|
||||
@@ -321,6 +321,13 @@ make_rel_from_jointree(Query *root, Node *jtnode)
|
||||
|
||||
return get_base_rel(root, varno);
|
||||
}
|
||||
else if (IsA(jtnode, FromExpr))
|
||||
{
|
||||
FromExpr *f = (FromExpr *) jtnode;
|
||||
|
||||
/* Recurse back to multi-way-join planner */
|
||||
return make_fromexpr_rel(root, f);
|
||||
}
|
||||
else if (IsA(jtnode, JoinExpr))
|
||||
{
|
||||
JoinExpr *j = (JoinExpr *) jtnode;
|
||||
@@ -329,8 +336,8 @@ make_rel_from_jointree(Query *root, Node *jtnode)
|
||||
*rrel;
|
||||
|
||||
/* Recurse */
|
||||
lrel = make_rel_from_jointree(root, j->larg);
|
||||
rrel = make_rel_from_jointree(root, j->rarg);
|
||||
lrel = make_jointree_rel(root, j->larg);
|
||||
rrel = make_jointree_rel(root, j->rarg);
|
||||
|
||||
/* Make this join rel */
|
||||
rel = make_join_rel(root, lrel, rrel, j->jointype);
|
||||
@@ -346,7 +353,7 @@ make_rel_from_jointree(Query *root, Node *jtnode)
|
||||
return rel;
|
||||
}
|
||||
else
|
||||
elog(ERROR, "make_rel_from_jointree: unexpected node type %d",
|
||||
elog(ERROR, "make_jointree_rel: unexpected node type %d",
|
||||
nodeTag(jtnode));
|
||||
return NULL; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.25 2000/09/12 21:06:53 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.26 2000/09/29 18:21:32 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -122,7 +122,7 @@ add_equijoined_keys(Query *root, RestrictInfo *restrictinfo)
|
||||
newset = lcons(item1, lcons(item2, NIL));
|
||||
|
||||
/* Found a set to merge into our new set */
|
||||
newset = LispUnion(newset, curset);
|
||||
newset = set_union(newset, curset);
|
||||
|
||||
/*
|
||||
* Remove old set from equi_key_list. NOTE this does not
|
||||
|
||||
Reference in New Issue
Block a user