mirror of
https://github.com/postgres/postgres.git
synced 2025-04-27 22:56:53 +03:00
Clean up rewriter routines to use expression_tree_walker and
expression_tree_mutator rather than ad-hoc tree walking code. This shortens the code materially and fixes a fair number of sins of omission. Also, change modifyAggrefQual to *not* recurse into subselects, since its mission is satisfied if it removes aggregate functions from the top level of a WHERE clause. This cures problems with queries of the form SELECT ... WHERE x IN (SELECT ... HAVING something-using-an-aggregate), which would formerly get mucked up by modifyAggrefQual. The routine is still fundamentally broken, of course, but I don't think there's any way to get rid of it before we implement subselects in FROM ...
This commit is contained in:
parent
ce1f5ed547
commit
389af07cf0
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.22 1999/09/18 19:07:18 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.23 1999/10/01 04:08:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "catalog/pg_shadow.h"
|
#include "catalog/pg_shadow.h"
|
||||||
|
#include "optimizer/clauses.h"
|
||||||
#include "rewrite/locks.h"
|
#include "rewrite/locks.h"
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
@ -22,102 +23,86 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ThisLockWasTriggered
|
* thisLockWasTriggered
|
||||||
*
|
*
|
||||||
* walk the tree, if there we find a varnode,
|
* walk the tree, if there we find a varnode,
|
||||||
* we check the varattno against the attnum
|
* we check the varattno against the attnum
|
||||||
* if we find at least one such match, we return true
|
* if we find at least one such match, we return true
|
||||||
* otherwise, we return false
|
* otherwise, we return false
|
||||||
|
*
|
||||||
|
* XXX this should be unified with attribute_used()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int varno;
|
||||||
|
int attnum;
|
||||||
|
int sublevels_up;
|
||||||
|
} thisLockWasTriggered_context;
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
nodeThisLockWasTriggered(Node *node, int varno, AttrNumber attnum,
|
thisLockWasTriggered_walker (Node *node,
|
||||||
int sublevels_up)
|
thisLockWasTriggered_context *context)
|
||||||
{
|
{
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return FALSE;
|
return false;
|
||||||
switch (nodeTag(node))
|
if (IsA(node, Var))
|
||||||
{
|
|
||||||
case T_Var:
|
|
||||||
{
|
{
|
||||||
Var *var = (Var *) node;
|
Var *var = (Var *) node;
|
||||||
|
|
||||||
if (varno == var->varno &&
|
if (var->varlevelsup == context->sublevels_up &&
|
||||||
(attnum == var->varattno || attnum == -1))
|
var->varno == context->varno &&
|
||||||
return TRUE;
|
(var->varattno == context->attnum || context->attnum == -1))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
if (IsA(node, SubLink))
|
||||||
case T_Expr:
|
|
||||||
{
|
{
|
||||||
Expr *expr = (Expr *) node;
|
|
||||||
|
|
||||||
return nodeThisLockWasTriggered((Node *) expr->args, varno,
|
|
||||||
attnum, sublevels_up);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case T_TargetEntry:
|
|
||||||
{
|
|
||||||
TargetEntry *tle = (TargetEntry *) node;
|
|
||||||
|
|
||||||
return nodeThisLockWasTriggered(tle->expr, varno, attnum,
|
|
||||||
sublevels_up);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case T_Aggref:
|
|
||||||
{
|
|
||||||
Aggref *aggref = (Aggref *) node;
|
|
||||||
|
|
||||||
return nodeThisLockWasTriggered(aggref->target, varno, attnum,
|
|
||||||
sublevels_up);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case T_List:
|
|
||||||
{
|
|
||||||
List *l;
|
|
||||||
|
|
||||||
foreach(l, (List *) node)
|
|
||||||
{
|
|
||||||
if (nodeThisLockWasTriggered(lfirst(l), varno, attnum,
|
|
||||||
sublevels_up))
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case T_SubLink:
|
|
||||||
{
|
|
||||||
SubLink *sublink = (SubLink *) node;
|
|
||||||
Query *query = (Query *) sublink->subselect;
|
|
||||||
|
|
||||||
return nodeThisLockWasTriggered(query->qual, varno, attnum,
|
|
||||||
sublevels_up + 1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* thisLockWasTriggered -
|
* Standard expression_tree_walker will not recurse into subselect,
|
||||||
* walk the tree, if there we find a varnode, we check the varattno
|
* but here we must do so.
|
||||||
* against the attnum if we find at least one such match, we return true
|
|
||||||
* otherwise, we return false
|
|
||||||
*/
|
*/
|
||||||
|
SubLink *sub = (SubLink *) node;
|
||||||
|
|
||||||
|
if (thisLockWasTriggered_walker((Node *) (sub->lefthand), context))
|
||||||
|
return true;
|
||||||
|
context->sublevels_up++;
|
||||||
|
if (thisLockWasTriggered_walker((Node *) (sub->subselect), context))
|
||||||
|
{
|
||||||
|
context->sublevels_up--; /* not really necessary */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
context->sublevels_up--;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (IsA(node, Query))
|
||||||
|
{
|
||||||
|
/* Reach here after recursing down into subselect above... */
|
||||||
|
Query *qry = (Query *) node;
|
||||||
|
|
||||||
|
if (thisLockWasTriggered_walker((Node *) (qry->targetList), context))
|
||||||
|
return true;
|
||||||
|
if (thisLockWasTriggered_walker((Node *) (qry->qual), context))
|
||||||
|
return true;
|
||||||
|
if (thisLockWasTriggered_walker((Node *) (qry->havingQual), context))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return expression_tree_walker(node, thisLockWasTriggered_walker,
|
||||||
|
(void *) context);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
thisLockWasTriggered(int varno,
|
thisLockWasTriggered(int varno,
|
||||||
AttrNumber attnum,
|
int attnum,
|
||||||
Query *parsetree)
|
Query *parsetree)
|
||||||
{
|
{
|
||||||
|
thisLockWasTriggered_context context;
|
||||||
|
|
||||||
if (nodeThisLockWasTriggered(parsetree->qual, varno, attnum, 0))
|
context.varno = varno;
|
||||||
return true;
|
context.attnum = attnum;
|
||||||
|
context.sublevels_up = 0;
|
||||||
if (nodeThisLockWasTriggered((Node *) parsetree->targetList, varno, attnum, 0))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
|
return thisLockWasTriggered_walker((Node *) parsetree, &context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: rewriteManip.h,v 1.17 1999/07/15 15:21:30 momjian Exp $
|
* $Id: rewriteManip.h,v 1.18 1999/10/01 04:08:15 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -16,19 +16,18 @@
|
|||||||
#include "rewrite/rewriteHandler.h"
|
#include "rewrite/rewriteHandler.h"
|
||||||
|
|
||||||
/* RewriteManip.c */
|
/* RewriteManip.c */
|
||||||
void OffsetVarNodes(Node *node, int offset, int sublevels_up);
|
extern void OffsetVarNodes(Node *node, int offset, int sublevels_up);
|
||||||
void ChangeVarNodes(Node *node, int old_varno, int new_varno,
|
extern void ChangeVarNodes(Node *node, int old_varno, int new_varno,
|
||||||
int sublevels_up);
|
int sublevels_up);
|
||||||
void AddQual(Query *parsetree, Node *qual);
|
extern void AddQual(Query *parsetree, Node *qual);
|
||||||
void AddHavingQual(Query *parsetree, Node *havingQual);
|
extern void AddHavingQual(Query *parsetree, Node *havingQual);
|
||||||
|
extern void AddNotQual(Query *parsetree, Node *qual);
|
||||||
|
extern void AddGroupClause(Query *parsetree, List *group_by, List *tlist);
|
||||||
|
|
||||||
void AddNotQual(Query *parsetree, Node *qual);
|
extern void FixNew(RewriteInfo *info, Query *parsetree);
|
||||||
void AddGroupClause(Query *parsetree, List *group_by, List *tlist);
|
|
||||||
|
|
||||||
void FixNew(RewriteInfo *info, Query *parsetree);
|
extern void HandleRIRAttributeRule(Query *parsetree, List *rtable,
|
||||||
|
List *targetlist, int rt_index,
|
||||||
void HandleRIRAttributeRule(Query *parsetree, List *rtable, List *targetlist,
|
int attr_num, int *modified, int *badsql);
|
||||||
int rt_index, int attr_num, int *modified,
|
|
||||||
int *badpostquel);
|
|
||||||
|
|
||||||
#endif /* REWRITEMANIP_H */
|
#endif /* REWRITEMANIP_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user