mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +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:
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.48 2000/09/12 21:07:04 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.49 2000/09/29 18:21:24 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -473,8 +473,7 @@ attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
|
||||
void
|
||||
AddQual(Query *parsetree, Node *qual)
|
||||
{
|
||||
Node *copy,
|
||||
*old;
|
||||
Node *copy;
|
||||
|
||||
if (qual == NULL)
|
||||
return;
|
||||
@ -482,11 +481,8 @@ AddQual(Query *parsetree, Node *qual)
|
||||
/* INTERSECT want's the original, but we need to copy - Jan */
|
||||
copy = copyObject(qual);
|
||||
|
||||
old = parsetree->qual;
|
||||
if (old == NULL)
|
||||
parsetree->qual = copy;
|
||||
else
|
||||
parsetree->qual = (Node *) make_andclause(makeList(old, copy, -1));
|
||||
parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
|
||||
copy);
|
||||
|
||||
/*
|
||||
* Make sure query is marked correctly if added qual has sublinks or
|
||||
@ -504,8 +500,7 @@ AddQual(Query *parsetree, Node *qual)
|
||||
void
|
||||
AddHavingQual(Query *parsetree, Node *havingQual)
|
||||
{
|
||||
Node *copy,
|
||||
*old;
|
||||
Node *copy;
|
||||
|
||||
if (havingQual == NULL)
|
||||
return;
|
||||
@ -513,11 +508,8 @@ AddHavingQual(Query *parsetree, Node *havingQual)
|
||||
/* INTERSECT want's the original, but we need to copy - Jan */
|
||||
copy = copyObject(havingQual);
|
||||
|
||||
old = parsetree->havingQual;
|
||||
if (old == NULL)
|
||||
parsetree->havingQual = copy;
|
||||
else
|
||||
parsetree->havingQual = (Node *) make_andclause(makeList(old, copy, -1));
|
||||
parsetree->havingQual = make_and_qual(parsetree->havingQual,
|
||||
copy);
|
||||
|
||||
/*
|
||||
* Make sure query is marked correctly if added qual has sublinks or
|
||||
@ -560,45 +552,7 @@ AddNotQual(Query *parsetree, Node *qual)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add all expressions used by the given GroupClause list to the
|
||||
* parsetree's targetlist and groupclause list.
|
||||
*
|
||||
* tlist is the old targetlist associated with the input groupclauses.
|
||||
*
|
||||
* XXX shouldn't we be checking to see if there are already matching
|
||||
* entries in parsetree->targetlist?
|
||||
*/
|
||||
void
|
||||
AddGroupClause(Query *parsetree, List *group_by, List *tlist)
|
||||
{
|
||||
List *l;
|
||||
|
||||
foreach(l, group_by)
|
||||
{
|
||||
GroupClause *groupclause = (GroupClause *) copyObject(lfirst(l));
|
||||
TargetEntry *tle = get_sortgroupclause_tle(groupclause, tlist);
|
||||
|
||||
/* copy the groupclause's TLE from the old tlist */
|
||||
tle = (TargetEntry *) copyObject(tle);
|
||||
|
||||
/*
|
||||
* The ressortgroupref number in the old tlist might be already
|
||||
* taken in the new tlist, so force assignment of a new number.
|
||||
*/
|
||||
tle->resdom->ressortgroupref = 0;
|
||||
groupclause->tleSortGroupRef =
|
||||
assignSortGroupRef(tle, parsetree->targetList);
|
||||
|
||||
/* Also need to set the resno and mark it resjunk. */
|
||||
tle->resdom->resno = length(parsetree->targetList) + 1;
|
||||
tle->resdom->resjunk = true;
|
||||
|
||||
parsetree->targetList = lappend(parsetree->targetList, tle);
|
||||
parsetree->groupClause = lappend(parsetree->groupClause, groupclause);
|
||||
}
|
||||
}
|
||||
|
||||
/* Build a NULL constant expression of the given type */
|
||||
static Node *
|
||||
make_null(Oid type)
|
||||
{
|
||||
@ -612,28 +566,6 @@ make_null(Oid type)
|
||||
return (Node *) c;
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
void
|
||||
FixResdomTypes(List *tlist)
|
||||
{
|
||||
List *i;
|
||||
|
||||
foreach(i, tlist)
|
||||
{
|
||||
TargetEntry *tle = lfirst(i);
|
||||
|
||||
if (nodeTag(tle->expr) == T_Var)
|
||||
{
|
||||
Var *var = (Var *) tle->expr;
|
||||
|
||||
tle->resdom->restype = var->vartype;
|
||||
tle->resdom->restypmod = var->vartypmod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Find a targetlist entry by resno */
|
||||
static Node *
|
||||
FindMatchingNew(List *tlist, int attno)
|
||||
@ -650,6 +582,8 @@ FindMatchingNew(List *tlist, int attno)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
|
||||
/* Find a targetlist entry by resname */
|
||||
static Node *
|
||||
FindMatchingTLEntry(List *tlist, char *e_attname)
|
||||
@ -662,25 +596,31 @@ FindMatchingTLEntry(List *tlist, char *e_attname)
|
||||
char *resname;
|
||||
|
||||
resname = tle->resdom->resname;
|
||||
if (!strcmp(e_attname, resname))
|
||||
if (strcmp(e_attname, resname) == 0)
|
||||
return tle->expr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* ResolveNew - replace Vars with corresponding items from a targetlist
|
||||
*
|
||||
* Vars matching info->new_varno and sublevels_up are replaced by the
|
||||
* Vars matching target_varno and sublevels_up are replaced by the
|
||||
* entry with matching resno from targetlist, if there is one.
|
||||
* If not, we either change the unmatched Var's varno to update_varno
|
||||
* (when event == CMD_UPDATE) or replace it with a constant NULL.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
RewriteInfo *info;
|
||||
List *targetlist;
|
||||
int target_varno;
|
||||
int sublevels_up;
|
||||
List *targetlist;
|
||||
int event;
|
||||
int update_varno;
|
||||
} ResolveNew_context;
|
||||
|
||||
static Node *
|
||||
@ -694,7 +634,7 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
|
||||
int this_varno = (int) var->varno;
|
||||
int this_varlevelsup = (int) var->varlevelsup;
|
||||
|
||||
if (this_varno == context->info->new_varno &&
|
||||
if (this_varno == context->target_varno &&
|
||||
this_varlevelsup == context->sublevels_up)
|
||||
{
|
||||
Node *n = FindMatchingNew(context->targetlist,
|
||||
@ -702,13 +642,13 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
|
||||
|
||||
if (n == NULL)
|
||||
{
|
||||
if (context->info->event == CMD_UPDATE)
|
||||
if (context->event == CMD_UPDATE)
|
||||
{
|
||||
/* For update, just change unmatched var's varno */
|
||||
n = copyObject(node);
|
||||
((Var *) n)->varno = context->info->current_varno;
|
||||
((Var *) n)->varnoold = context->info->current_varno;
|
||||
return n;
|
||||
var = (Var *) copyObject(node);
|
||||
var->varno = context->update_varno;
|
||||
var->varnoold = context->update_varno;
|
||||
return (Node *) var;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -755,54 +695,68 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
|
||||
FLATCOPY(newnode, query, Query);
|
||||
MUTATE(newnode->targetList, query->targetList, List *,
|
||||
ResolveNew_mutator, context);
|
||||
MUTATE(newnode->qual, query->qual, Node *,
|
||||
MUTATE(newnode->jointree, query->jointree, FromExpr *,
|
||||
ResolveNew_mutator, context);
|
||||
MUTATE(newnode->havingQual, query->havingQual, Node *,
|
||||
ResolveNew_mutator, context);
|
||||
MUTATE(newnode->jointree, query->jointree, List *,
|
||||
ResolveNew_mutator, context);
|
||||
return (Node *) newnode;
|
||||
}
|
||||
return expression_tree_mutator(node, ResolveNew_mutator,
|
||||
(void *) context);
|
||||
}
|
||||
|
||||
static Node *
|
||||
ResolveNew(Node *node, RewriteInfo *info, List *targetlist,
|
||||
int sublevels_up)
|
||||
Node *
|
||||
ResolveNew(Node *node, int target_varno, int sublevels_up,
|
||||
List *targetlist, int event, int update_varno)
|
||||
{
|
||||
ResolveNew_context context;
|
||||
|
||||
context.info = info;
|
||||
context.targetlist = targetlist;
|
||||
context.target_varno = target_varno;
|
||||
context.sublevels_up = sublevels_up;
|
||||
context.targetlist = targetlist;
|
||||
context.event = event;
|
||||
context.update_varno = update_varno;
|
||||
|
||||
/*
|
||||
* Note: if an entire Query is passed, the right things will happen,
|
||||
* because ResolveNew_mutator increments sublevels_up when it sees
|
||||
* a SubLink, not a Query.
|
||||
*/
|
||||
return ResolveNew_mutator(node, &context);
|
||||
}
|
||||
|
||||
/*
|
||||
* Alternate interface to ResolveNew: substitute Vars in info->rule_action
|
||||
* with targetlist items from the parsetree's targetlist.
|
||||
*/
|
||||
void
|
||||
FixNew(RewriteInfo *info, Query *parsetree)
|
||||
{
|
||||
ResolveNew_context context;
|
||||
|
||||
context.target_varno = info->new_varno;
|
||||
context.sublevels_up = 0;
|
||||
context.targetlist = parsetree->targetList;
|
||||
context.event = info->event;
|
||||
context.update_varno = info->current_varno;
|
||||
|
||||
info->rule_action->targetList = (List *)
|
||||
ResolveNew((Node *) info->rule_action->targetList,
|
||||
info, parsetree->targetList, 0);
|
||||
info->rule_action->qual = ResolveNew(info->rule_action->qual,
|
||||
info, parsetree->targetList, 0);
|
||||
info->rule_action->havingQual = ResolveNew(info->rule_action->havingQual,
|
||||
info, parsetree->targetList, 0);
|
||||
info->rule_action->jointree = (List *)
|
||||
ResolveNew((Node *) info->rule_action->jointree,
|
||||
info, parsetree->targetList, 0);
|
||||
ResolveNew_mutator((Node *) info->rule_action->targetList, &context);
|
||||
info->rule_action->jointree = (FromExpr *)
|
||||
ResolveNew_mutator((Node *) info->rule_action->jointree, &context);
|
||||
info->rule_action->havingQual =
|
||||
ResolveNew_mutator(info->rule_action->havingQual, &context);
|
||||
}
|
||||
|
||||
|
||||
#ifdef NOT_USED
|
||||
|
||||
/*
|
||||
* HandleRIRAttributeRule
|
||||
* Replace Vars matching a given RT index with copies of TL expressions.
|
||||
*
|
||||
* Handles 'on retrieve to relation.attribute
|
||||
* do instead retrieve (attribute = expression) w/qual'
|
||||
*
|
||||
* XXX Why is this not unified with apply_RIR_view()?
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
@ -897,12 +851,12 @@ HandleRIRAttributeRule_mutator(Node *node,
|
||||
FLATCOPY(newnode, query, Query);
|
||||
MUTATE(newnode->targetList, query->targetList, List *,
|
||||
HandleRIRAttributeRule_mutator, context);
|
||||
MUTATE(newnode->qual, query->qual, Node *,
|
||||
MUTATE(newnode->jointree, query->jointree, FromExpr *,
|
||||
HandleRIRAttributeRule_mutator, context);
|
||||
MUTATE(newnode->havingQual, query->havingQual, Node *,
|
||||
HandleRIRAttributeRule_mutator, context);
|
||||
MUTATE(newnode->jointree, query->jointree, List *,
|
||||
HandleRIRAttributeRule_mutator, context);
|
||||
|
||||
|
||||
return (Node *) newnode;
|
||||
}
|
||||
return expression_tree_mutator(node, HandleRIRAttributeRule_mutator,
|
||||
@ -931,13 +885,12 @@ HandleRIRAttributeRule(Query *parsetree,
|
||||
parsetree->targetList = (List *)
|
||||
HandleRIRAttributeRule_mutator((Node *) parsetree->targetList,
|
||||
&context);
|
||||
parsetree->qual =
|
||||
HandleRIRAttributeRule_mutator(parsetree->qual,
|
||||
parsetree->jointree = (FromExpr *)
|
||||
HandleRIRAttributeRule_mutator((Node *) parsetree->jointree,
|
||||
&context);
|
||||
parsetree->havingQual =
|
||||
HandleRIRAttributeRule_mutator(parsetree->havingQual,
|
||||
&context);
|
||||
parsetree->jointree = (List *)
|
||||
HandleRIRAttributeRule_mutator((Node *) parsetree->jointree,
|
||||
&context);
|
||||
}
|
||||
|
||||
#endif /* NOT_USED */
|
||||
|
Reference in New Issue
Block a user