1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-09 06:21:09 +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:
Tom Lane
2000-09-29 18:21:41 +00:00
parent 6f64c2e54a
commit 3a94e789f5
77 changed files with 3176 additions and 2661 deletions

View File

@@ -4,7 +4,7 @@
# Makefile for optimizer/util
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/optimizer/util/Makefile,v 1.13 2000/08/31 16:10:14 petere Exp $
# $Header: /cvsroot/pgsql/src/backend/optimizer/util/Makefile,v 1.14 2000/09/29 18:21:23 tgl Exp $
#
#-------------------------------------------------------------------------
@@ -12,7 +12,7 @@ subdir = src/backend/optimizer/util
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
OBJS = restrictinfo.o clauses.o indexnode.o plancat.o \
OBJS = restrictinfo.o clauses.o plancat.o \
joininfo.o pathnode.o relnode.o tlist.o var.o
all: SUBSYS.o

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.75 2000/09/25 18:14:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.76 2000/09/29 18:21:23 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -119,9 +119,9 @@ make_opclause(Oper *op, Var *leftop, Var *rightop)
expr->opType = OP_EXPR;
expr->oper = (Node *) op;
if (rightop)
expr->args = lcons(leftop, lcons(rightop, NIL));
expr->args = makeList2(leftop, rightop);
else
expr->args = lcons(leftop, NIL);
expr->args = makeList1(leftop);
return expr;
}
@@ -264,7 +264,7 @@ make_notclause(Expr *notclause)
expr->typeOid = BOOLOID;
expr->opType = NOT_EXPR;
expr->oper = NULL;
expr->args = lcons(notclause, NIL);
expr->args = makeList1(notclause);
return expr;
}
@@ -303,7 +303,6 @@ and_clause(Node *clause)
* make_andclause
*
* Create an 'and' clause given its arguments in a list.
*
*/
Expr *
make_andclause(List *andclauses)
@@ -317,6 +316,23 @@ make_andclause(List *andclauses)
return expr;
}
/*
* make_and_qual
*
* Variant of make_andclause for ANDing two qual conditions together.
* Qual conditions have the property that a NULL nodetree is interpreted
* as 'true'.
*/
Node *
make_and_qual(Node *qual1, Node *qual2)
{
if (qual1 == NULL)
return qual2;
if (qual2 == NULL)
return qual1;
return (Node *) make_andclause(makeList2(qual1, qual2));
}
/*
* Sometimes (such as in the result of canonicalize_qual or the input of
* ExecQual), we use lists of expression nodes with implicit AND semantics.
@@ -356,7 +372,7 @@ make_ands_implicit(Expr *clause)
DatumGetBool(((Const *) clause)->constvalue))
return NIL; /* constant TRUE input -> NIL list */
else
return lcons(clause, NIL);
return makeList1(clause);
}
@@ -676,49 +692,32 @@ is_pseudo_constant_clause(Node *clause)
return false;
}
/*----------
/*
* pull_constant_clauses
* Scan through a list of qualifications and separate "constant" quals
* from those that are not.
*
* The input qual list is divided into three parts:
* * The function's return value is a list of all those quals that contain
* variable(s) of the current query level. (These quals will become
* restrict and join quals.)
* * *noncachableQual receives a list of quals that have no Vars, yet
* cannot be treated as constants because they contain noncachable
* function calls. (Example: WHERE random() < 0.5)
* * *constantQual receives a list of the remaining quals, which can be
* treated as constants for any one scan of the current query level.
* (They are really only pseudo-constant, since they may contain
* Params or outer-level Vars.)
*----------
* Returns a list of the pseudo-constant clauses in constantQual and the
* remaining quals as the return value.
*/
List *
pull_constant_clauses(List *quals,
List **noncachableQual,
List **constantQual)
pull_constant_clauses(List *quals, List **constantQual)
{
List *q;
List *normqual = NIL;
List *noncachequal = NIL;
List *constqual = NIL;
List *restqual = NIL;
List *q;
foreach(q, quals)
{
Node *qual = (Node *) lfirst(q);
Node *qual = (Node *) lfirst(q);
if (contain_var_clause(qual))
normqual = lappend(normqual, qual);
else if (contain_noncachable_functions(qual))
noncachequal = lappend(noncachequal, qual);
else
if (is_pseudo_constant_clause(qual))
constqual = lappend(constqual, qual);
else
restqual = lappend(restqual, qual);
}
*noncachableQual = noncachequal;
*constantQual = constqual;
return normqual;
return restqual;
}
@@ -1636,9 +1635,9 @@ simplify_op_or_func(Expr *expr, List *args)
* will have List structure at the top level, and it handles TargetEntry nodes
* so that a scan of a target list can be handled without additional code.
* (But only the "expr" part of a TargetEntry is examined, unless the walker
* chooses to process TargetEntry nodes specially.) Also, RangeTblRef and
* JoinExpr nodes are handled, so that qual expressions in a jointree can be
* processed without additional code.
* chooses to process TargetEntry nodes specially.) Also, RangeTblRef,
* FromExpr, and JoinExpr nodes are handled, so that qual expressions in a
* jointree can be processed without additional code.
*
* expression_tree_walker will handle SubLink and SubPlan nodes by recursing
* normally into the "lefthand" arguments (which belong to the outer plan).
@@ -1801,6 +1800,16 @@ expression_tree_walker(Node *node,
break;
case T_TargetEntry:
return walker(((TargetEntry *) node)->expr, context);
case T_FromExpr:
{
FromExpr *from = (FromExpr *) node;
if (walker(from->fromlist, context))
return true;
if (walker(from->quals, context))
return true;
}
break;
case T_JoinExpr:
{
JoinExpr *join = (JoinExpr *) node;
@@ -1844,14 +1853,12 @@ query_tree_walker(Query *query,
if (walker((Node *) query->targetList, context))
return true;
if (walker(query->qual, context))
if (walker((Node *) query->jointree, context))
return true;
if (walker(query->havingQual, context))
return true;
if (walker((Node *) query->jointree, context))
return true;
/*
* XXX for subselect-in-FROM, may need to examine rtable as well
* XXX for subselect-in-FROM, may need to examine rtable as well?
*/
return false;
}
@@ -2126,6 +2133,17 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
case T_FromExpr:
{
FromExpr *from = (FromExpr *) node;
FromExpr *newnode;
FLATCOPY(newnode, from, FromExpr);
MUTATE(newnode->fromlist, from->fromlist, List *);
MUTATE(newnode->quals, from->quals, Node *);
return (Node *) newnode;
}
break;
case T_JoinExpr:
{
JoinExpr *join = (JoinExpr *) node;

View File

@@ -1,34 +0,0 @@
/*-------------------------------------------------------------------------
*
* indexnode.c
* Routines to find all indices on a relation
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/indexnode.c,v 1.22 2000/01/26 05:56:40 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "optimizer/pathnode.h"
#include "optimizer/plancat.h"
/*
* find_relation_indices
* Returns a list of index nodes containing appropriate information for
* each (secondary) index defined on a relation.
*
*/
List *
find_relation_indices(Query *root, RelOptInfo *rel)
{
if (rel->indexed)
return find_secondary_indexes(root, lfirsti(rel->relids));
else
return NIL;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.65 2000/09/12 21:06:58 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.66 2000/09/29 18:21:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,6 +16,7 @@
#include "postgres.h"
#include "nodes/plannodes.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
@@ -272,7 +273,6 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
* create_seqscan_path
* Creates a path corresponding to a sequential scan, returning the
* pathnode.
*
*/
Path *
create_seqscan_path(RelOptInfo *rel)
@@ -343,8 +343,8 @@ create_index_path(Query *root,
* We are making a pathnode for a single-scan indexscan; 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);
pathnode->indexscandir = indexscandir;
@@ -390,6 +390,27 @@ create_tidscan_path(RelOptInfo *rel, List *tideval)
return pathnode;
}
/*
* create_subqueryscan_path
* Creates a path corresponding to a sequential scan of a subquery,
* returning the pathnode.
*/
Path *
create_subqueryscan_path(RelOptInfo *rel)
{
Path *pathnode = makeNode(Path);
pathnode->pathtype = T_SubqueryScan;
pathnode->parent = rel;
pathnode->pathkeys = NIL; /* for now, assume unordered result */
/* just copy the subplan's cost estimates */
pathnode->startup_cost = rel->subplan->startup_cost;
pathnode->total_cost = rel->subplan->total_cost;
return pathnode;
}
/*
* create_nestloop_path
* Creates a pathnode corresponding to a nestloop join between two

View File

@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.60 2000/07/27 23:16:04 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.61 2000/09/29 18:21:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,7 +25,6 @@
#include "catalog/pg_inherits.h"
#include "catalog/pg_index.h"
#include "optimizer/plancat.h"
#include "parser/parsetree.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/relcache.h"
@@ -37,16 +36,15 @@
/*
* relation_info -
* Retrieves catalog information for a given relation.
* Given the rangetable index of the relation, return the following info:
* Given the Oid of the relation, return the following info:
* whether the relation has secondary indices
* number of pages
* number of tuples
*/
void
relation_info(Query *root, Index relid,
relation_info(Oid relationObjectId,
bool *hasindex, long *pages, double *tuples)
{
Oid relationObjectId = getrelid(relid, root->rtable);
HeapTuple relationTuple;
Form_pg_class relation;
@@ -69,19 +67,18 @@ relation_info(Query *root, Index relid,
/*
* find_secondary_indexes
* Creates a list of IndexOptInfo nodes containing information for each
* secondary index defined on the given relation.
* secondary index defined on the specified relation.
*
* 'relid' is the RT index of the relation for which indices are being located
* 'relationObjectId' is the OID of the relation for which indices are wanted
*
* Returns a list of new IndexOptInfo nodes.
*/
List *
find_secondary_indexes(Query *root, Index relid)
find_secondary_indexes(Oid relationObjectId)
{
List *indexinfos = NIL;
List *indexoidlist,
*indexoidscan;
Oid indrelid = getrelid(relid, root->rtable);
Relation relation;
/*
@@ -89,12 +86,12 @@ find_secondary_indexes(Query *root, Index relid)
* a cached list of OID indexes for each relation. So, get that list
* and then use the syscache to obtain pg_index entries.
*/
relation = heap_open(indrelid, AccessShareLock);
relation = heap_open(relationObjectId, AccessShareLock);
indexoidlist = RelationGetIndexList(relation);
foreach(indexoidscan, indexoidlist)
{
Oid indexoid = lfirsti(indexoidscan);
Oid indexoid = lfirsti(indexoidscan);
HeapTuple indexTuple;
Form_pg_index index;
IndexOptInfo *info;

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.28 2000/09/12 21:06:58 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.29 2000/09/29 18:21:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,6 +19,7 @@
#include "optimizer/pathnode.h"
#include "optimizer/plancat.h"
#include "optimizer/tlist.h"
#include "parser/parsetree.h"
static List *new_join_tlist(List *tlist, int first_resdomno);
@@ -44,6 +45,7 @@ get_base_rel(Query *root, int relid)
{
List *baserels;
RelOptInfo *rel;
Oid relationObjectId;
foreach(baserels, root->base_rel_list)
{
@@ -59,7 +61,7 @@ get_base_rel(Query *root, int relid)
/* No existing RelOptInfo for this base rel, so make a new one */
rel = makeNode(RelOptInfo);
rel->relids = lconsi(relid, NIL);
rel->relids = makeListi1(relid);
rel->rows = 0;
rel->width = 0;
rel->targetlist = NIL;
@@ -67,18 +69,31 @@ get_base_rel(Query *root, int relid)
rel->cheapest_startup_path = NULL;
rel->cheapest_total_path = NULL;
rel->pruneable = true;
rel->issubquery = false;
rel->indexed = false;
rel->pages = 0;
rel->tuples = 0;
rel->subplan = NULL;
rel->baserestrictinfo = NIL;
rel->baserestrictcost = 0;
rel->outerjoinset = NIL;
rel->joininfo = NIL;
rel->innerjoin = NIL;
/* Retrieve relation statistics from the system catalogs. */
relation_info(root, relid,
&rel->indexed, &rel->pages, &rel->tuples);
/* Check rtable to see if it's a plain relation or a subquery */
relationObjectId = getrelid(relid, root->rtable);
if (relationObjectId != InvalidOid)
{
/* Plain relation --- retrieve statistics from the system catalogs */
relation_info(relationObjectId,
&rel->indexed, &rel->pages, &rel->tuples);
}
else
{
/* subquery --- mark it as such for later processing */
rel->issubquery = true;
}
root->base_rel_list = lcons(rel, root->base_rel_list);
@@ -174,9 +189,11 @@ get_join_rel(Query *root,
joinrel->cheapest_startup_path = NULL;
joinrel->cheapest_total_path = NULL;
joinrel->pruneable = true;
joinrel->issubquery = false;
joinrel->indexed = false;
joinrel->pages = 0;
joinrel->tuples = 0;
joinrel->subplan = NULL;
joinrel->baserestrictinfo = NIL;
joinrel->baserestrictcost = 0;
joinrel->outerjoinset = NIL;
@@ -310,7 +327,7 @@ build_joinrel_restrictlist(RelOptInfo *joinrel,
* We must eliminate duplicates, since we will see the same clauses
* arriving from both input relations...
*/
return LispUnion(subbuild_joinrel_restrictlist(joinrel,
return set_union(subbuild_joinrel_restrictlist(joinrel,
outer_rel->joininfo),
subbuild_joinrel_restrictlist(joinrel,
inner_rel->joininfo));
@@ -396,7 +413,7 @@ subbuild_joinrel_joinlist(RelOptInfo *joinrel,
new_joininfo = find_joininfo_node(joinrel, new_unjoined_relids);
new_joininfo->jinfo_restrictinfo =
LispUnion(new_joininfo->jinfo_restrictinfo,
set_union(new_joininfo->jinfo_restrictinfo,
joininfo->jinfo_restrictinfo);
}
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.11 2000/09/12 21:06:58 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.12 2000/09/29 18:21:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -59,7 +59,7 @@ get_actual_clauses(List *restrictinfo_list)
* get_actual_join_clauses
*
* Extract clauses from 'restrictinfo_list', separating those that
* came from JOIN/ON conditions from those that didn't.
* syntactically match the join level from those that were pushed down.
*/
void
get_actual_join_clauses(List *restrictinfo_list,
@@ -74,9 +74,9 @@ get_actual_join_clauses(List *restrictinfo_list,
{
RestrictInfo *clause = (RestrictInfo *) lfirst(temp);
if (clause->isjoinqual)
*joinquals = lappend(*joinquals, clause->clause);
else
if (clause->ispusheddown)
*otherquals = lappend(*otherquals, clause->clause);
else
*joinquals = lappend(*joinquals, clause->clause);
}
}