mirror of
https://github.com/postgres/postgres.git
synced 2025-11-19 13:42:17 +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:
@@ -14,7 +14,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.59 2000/09/12 21:06:54 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.60 2000/09/29 18:21:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -32,8 +32,8 @@
|
||||
#include "utils/memutils.h"
|
||||
|
||||
|
||||
static Plan *subplanner(Query *root, List *flat_tlist, List *qual,
|
||||
double tuple_fraction);
|
||||
static Plan *subplanner(Query *root, List *flat_tlist,
|
||||
double tuple_fraction);
|
||||
|
||||
|
||||
/*--------------------
|
||||
@@ -75,46 +75,36 @@ query_planner(Query *root,
|
||||
List *tlist,
|
||||
double tuple_fraction)
|
||||
{
|
||||
List *normal_qual;
|
||||
List *noncachable_qual;
|
||||
List *constant_qual;
|
||||
List *constant_quals;
|
||||
List *var_only_tlist;
|
||||
Plan *subplan;
|
||||
|
||||
/*
|
||||
* If the query contains no relation references at all, it must be
|
||||
* something like "SELECT 2+2;". Build a trivial "Result" plan.
|
||||
* If the query has an empty join tree, then it's something easy like
|
||||
* "SELECT 2+2;" or "INSERT ... VALUES()". Fall through quickly.
|
||||
*/
|
||||
if (root->rtable == NIL)
|
||||
if (root->jointree->fromlist == NIL)
|
||||
{
|
||||
/* If it's not a select, it should have had a target relation... */
|
||||
if (root->commandType != CMD_SELECT)
|
||||
elog(ERROR, "Empty range table for non-SELECT query");
|
||||
|
||||
root->query_pathkeys = NIL; /* signal unordered result */
|
||||
|
||||
/* Make childless Result node to evaluate given tlist. */
|
||||
return (Plan *) make_result(tlist, root->qual, (Plan *) NULL);
|
||||
return (Plan *) make_result(tlist, root->jointree->quals,
|
||||
(Plan *) NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pull out any non-variable qual clauses so these can be put in a
|
||||
* Pull out any non-variable WHERE clauses so these can be put in a
|
||||
* toplevel "Result" node, where they will gate execution of the whole
|
||||
* plan (the Result will not invoke its descendant plan unless the
|
||||
* quals are true). Note that any *really* non-variable quals will
|
||||
* have been optimized away by eval_const_expressions(). What we're
|
||||
* mostly interested in here is quals that depend only on outer-level
|
||||
* vars, although if the qual reduces to "WHERE FALSE" this path will
|
||||
* also be taken. We also need a special case for quals that contain
|
||||
* noncachable functions but no vars, such as "WHERE random() < 0.5".
|
||||
* These cannot be treated as normal restriction or join quals, but
|
||||
* they're not constants either. Instead, attach them to the qpqual
|
||||
* of the top plan, so that they get evaluated once per potential
|
||||
* output tuple.
|
||||
* also be taken.
|
||||
*/
|
||||
normal_qual = pull_constant_clauses((List *) root->qual,
|
||||
&noncachable_qual,
|
||||
&constant_qual);
|
||||
root->jointree->quals = (Node *)
|
||||
pull_constant_clauses((List *) root->jointree->quals,
|
||||
&constant_quals);
|
||||
|
||||
/*
|
||||
* Create a target list that consists solely of (resdom var) target
|
||||
@@ -132,18 +122,12 @@ query_planner(Query *root,
|
||||
/*
|
||||
* Choose the best access path and build a plan for it.
|
||||
*/
|
||||
subplan = subplanner(root, var_only_tlist, normal_qual, tuple_fraction);
|
||||
|
||||
/*
|
||||
* Handle the noncachable quals.
|
||||
*/
|
||||
if (noncachable_qual)
|
||||
subplan->qual = nconc(subplan->qual, noncachable_qual);
|
||||
subplan = subplanner(root, var_only_tlist, tuple_fraction);
|
||||
|
||||
/*
|
||||
* Build a result node to control the plan if we have constant quals.
|
||||
*/
|
||||
if (constant_qual)
|
||||
if (constant_quals)
|
||||
{
|
||||
|
||||
/*
|
||||
@@ -151,7 +135,7 @@ query_planner(Query *root,
|
||||
* originally requested tlist.
|
||||
*/
|
||||
subplan = (Plan *) make_result(tlist,
|
||||
(Node *) constant_qual,
|
||||
(Node *) constant_quals,
|
||||
subplan);
|
||||
}
|
||||
else
|
||||
@@ -175,7 +159,6 @@ query_planner(Query *root,
|
||||
* for processing a single level of attributes.
|
||||
*
|
||||
* flat_tlist is the flattened target list
|
||||
* qual is the qualification to be satisfied (restrict and join quals only)
|
||||
* tuple_fraction is the fraction of tuples we expect will be retrieved
|
||||
*
|
||||
* See query_planner() comments about the interpretation of tuple_fraction.
|
||||
@@ -185,7 +168,6 @@ query_planner(Query *root,
|
||||
static Plan *
|
||||
subplanner(Query *root,
|
||||
List *flat_tlist,
|
||||
List *qual,
|
||||
double tuple_fraction)
|
||||
{
|
||||
List *joined_rels;
|
||||
@@ -210,9 +192,8 @@ subplanner(Query *root,
|
||||
root->equi_key_list = NIL;
|
||||
|
||||
build_base_rel_tlists(root, flat_tlist);
|
||||
(void) add_join_quals_to_rels(root, (Node *) root->jointree);
|
||||
/* this must happen after add_join_quals_to_rels: */
|
||||
add_restrict_and_join_to_rels(root, qual);
|
||||
|
||||
(void) distribute_quals_to_rels(root, (Node *) root->jointree);
|
||||
|
||||
/*
|
||||
* Make sure we have RelOptInfo nodes for all relations to be joined.
|
||||
@@ -270,26 +251,7 @@ subplanner(Query *root,
|
||||
final_rel = make_one_rel(root);
|
||||
|
||||
if (!final_rel)
|
||||
{
|
||||
|
||||
/*
|
||||
* We expect to end up here for a trivial INSERT ... VALUES query
|
||||
* (which will have a target relation, so it gets past
|
||||
* query_planner's check for empty range table; but the target rel
|
||||
* is not in the join tree, so we find there is nothing to join).
|
||||
*
|
||||
* It's also possible to get here if the query was rewritten by the
|
||||
* rule processor (creating dummy rangetable entries that are not in
|
||||
* the join tree) but the rules either did nothing or were simplified
|
||||
* to nothing by constant-expression folding. So, don't complain.
|
||||
*/
|
||||
root->query_pathkeys = NIL; /* signal unordered result */
|
||||
|
||||
/* Make childless Result node to evaluate given tlist. */
|
||||
resultplan = (Plan *) make_result(flat_tlist, (Node *) qual,
|
||||
(Plan *) NULL);
|
||||
goto plan_built;
|
||||
}
|
||||
elog(ERROR, "subplanner: failed to construct a relation");
|
||||
|
||||
#ifdef NOT_USED /* fix xfunc */
|
||||
|
||||
@@ -395,7 +357,10 @@ plan_built:
|
||||
|
||||
/*
|
||||
* Must copy the completed plan tree and its pathkeys out of temporary
|
||||
* context.
|
||||
* context. We also have to copy the rtable in case it contains any
|
||||
* subqueries. (If it does, they'll have been modified during the
|
||||
* recursive invocation of planner.c, and hence will contain substructure
|
||||
* allocated in my temporary context...)
|
||||
*/
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
@@ -403,6 +368,8 @@ plan_built:
|
||||
|
||||
root->query_pathkeys = copyObject(root->query_pathkeys);
|
||||
|
||||
root->rtable = copyObject(root->rtable);
|
||||
|
||||
/*
|
||||
* Now we can release the Path storage.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user