diff options
Diffstat (limited to 'src/backend/rewrite/rewriteHandler.c')
-rw-r--r-- | src/backend/rewrite/rewriteHandler.c | 2034 |
1 files changed, 497 insertions, 1537 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index a76121aa823..42e87244e18 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -6,7 +6,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.57 1999/09/19 17:20:58 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.58 1999/10/01 04:08:24 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -32,6 +32,19 @@ #include "utils/lsyscache.h" +extern void CheckSelectForUpdate(Query *rule_action); /* in analyze.c */ + + +/* macros borrowed from expression_tree_mutator */ + +#define FLATCOPY(newnode, node, nodetype) \ + ( (newnode) = makeNode(nodetype), \ + memcpy((newnode), (node), sizeof(nodetype)) ) + +#define MUTATE(newfield, oldfield, fieldtype, mutator, context) \ + ( (newfield) = (fieldtype) mutator((Node *) (oldfield), (context)) ) + + static RewriteInfo *gatherRewriteMeta(Query *parsetree, Query *rule_action, Node *rule_qual, @@ -39,12 +52,14 @@ static RewriteInfo *gatherRewriteMeta(Query *parsetree, CmdType event, bool *instead_flag); static bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up); -static bool attribute_used(Node *node, int rt_index, int attno, int sublevels_up); -static void modifyAggrefUplevel(Node *node); -static void modifyAggrefChangeVarnodes(Node **nodePtr, int rt_index, int new_index, int sublevels_up); -static void modifyAggrefDropQual(Node **nodePtr, Node *orignode, Expr *expr); +static bool attribute_used(Node *node, int rt_index, int attno, + int sublevels_up); +static bool modifyAggrefUplevel(Node *node, void *context); +static bool modifyAggrefChangeVarnodes(Node *node, int rt_index, int new_index, + int sublevels_up); +static Node *modifyAggrefDropQual(Node *node, Node *targetNode); static SubLink *modifyAggrefMakeSublink(Expr *origexp, Query *parsetree); -static void modifyAggrefQual(Node **nodePtr, Query *parsetree); +static Node *modifyAggrefQual(Node *node, Query *parsetree); static bool checkQueryHasAggs(Node *node); static bool checkQueryHasAggs_walker(Node *node, void *context); static bool checkQueryHasSubLink(Node *node); @@ -135,221 +150,68 @@ gatherRewriteMeta(Query *parsetree, * we need to process a RTE for RIR rules only if it is * referenced somewhere in var nodes of the query. */ + +typedef struct { + int rt_index; + int sublevels_up; +} rangeTableEntry_used_context; + static bool -rangeTableEntry_used(Node *node, int rt_index, int sublevels_up) +rangeTableEntry_used_walker (Node *node, + rangeTableEntry_used_context *context) { if (node == NULL) - return FALSE; - - switch (nodeTag(node)) + return false; + if (IsA(node, Var)) { - case T_TargetEntry: - { - TargetEntry *tle = (TargetEntry *) node; - - return rangeTableEntry_used( - (Node *) (tle->expr), - rt_index, - sublevels_up); - } - break; - - case T_Aggref: - { - Aggref *aggref = (Aggref *) node; - - return rangeTableEntry_used( - (Node *) (aggref->target), - rt_index, - sublevels_up); - } - break; - - case T_GroupClause: - return FALSE; - - case T_Expr: - { - Expr *exp = (Expr *) node; - - return rangeTableEntry_used( - (Node *) (exp->args), - rt_index, - sublevels_up); - } - break; - - case T_Iter: - { - Iter *iter = (Iter *) node; - - return rangeTableEntry_used( - (Node *) (iter->iterexpr), - rt_index, - sublevels_up); - } - break; - - case T_ArrayRef: - { - ArrayRef *ref = (ArrayRef *) node; - - if (rangeTableEntry_used( - (Node *) (ref->refupperindexpr), - rt_index, - sublevels_up)) - return TRUE; - - if (rangeTableEntry_used( - (Node *) (ref->reflowerindexpr), - rt_index, - sublevels_up)) - return TRUE; - - if (rangeTableEntry_used( - (Node *) (ref->refexpr), - rt_index, - sublevels_up)) - return TRUE; - - if (rangeTableEntry_used( - (Node *) (ref->refassgnexpr), - rt_index, - sublevels_up)) - return TRUE; - - return FALSE; - } - break; - - case T_Var: - { - Var *var = (Var *) node; - - if (var->varlevelsup == sublevels_up) - return var->varno == rt_index; - else - return FALSE; - } - break; - - case T_Param: - return FALSE; - - case T_Const: - return FALSE; - - case T_List: - { - List *l; - - foreach(l, (List *) node) - { - if (rangeTableEntry_used( - (Node *) lfirst(l), - rt_index, - sublevels_up)) - return TRUE; - } - return FALSE; - } - break; - - case T_SubLink: - { - SubLink *sub = (SubLink *) node; - - if (rangeTableEntry_used( - (Node *) (sub->lefthand), - rt_index, - sublevels_up)) - return TRUE; - - if (rangeTableEntry_used( - (Node *) (sub->subselect), - rt_index, - sublevels_up + 1)) - return TRUE; - - return FALSE; - } - break; - - case T_CaseExpr: - { - CaseExpr *exp = (CaseExpr *) node; - - if (rangeTableEntry_used( - (Node *) (exp->args), - rt_index, - sublevels_up)) - return TRUE; - - if (rangeTableEntry_used( - (Node *) (exp->defresult), - rt_index, - sublevels_up)) - return TRUE; - - return FALSE; - } - break; - - case T_CaseWhen: - { - CaseWhen *when = (CaseWhen *) node; - - if (rangeTableEntry_used( - (Node *) (when->expr), - rt_index, - sublevels_up)) - return TRUE; - - if (rangeTableEntry_used( - (Node *) (when->result), - rt_index, - sublevels_up)) - return TRUE; - - return FALSE; - } - break; - - case T_Query: - { - Query *qry = (Query *) node; - - if (rangeTableEntry_used( - (Node *) (qry->targetList), - rt_index, - sublevels_up)) - return TRUE; - - if (rangeTableEntry_used( - (Node *) (qry->qual), - rt_index, - sublevels_up)) - return TRUE; - - if (rangeTableEntry_used( - (Node *) (qry->havingQual), - rt_index, - sublevels_up)) - return TRUE; - - return FALSE; - } - break; - - default: - elog(NOTICE, "unknown node tag %d in rangeTableEntry_used()", nodeTag(node)); - elog(NOTICE, "Node is: %s", nodeToString(node)); - break; - + Var *var = (Var *) node; + if (var->varlevelsup == context->sublevels_up && + var->varno == context->rt_index) + return true; + return false; } + if (IsA(node, SubLink)) + { + /* + * Standard expression_tree_walker will not recurse into subselect, + * but here we must do so. + */ + SubLink *sub = (SubLink *) node; + + if (rangeTableEntry_used_walker((Node *) (sub->lefthand), context)) + return true; + if (rangeTableEntry_used((Node *) (sub->subselect), + context->rt_index, + context->sublevels_up + 1)) + return true; + return false; + } + if (IsA(node, Query)) + { + /* Reach here after recursing down into subselect above... */ + Query *qry = (Query *) node; + + if (rangeTableEntry_used_walker((Node *) (qry->targetList), context)) + return true; + if (rangeTableEntry_used_walker((Node *) (qry->qual), context)) + return true; + if (rangeTableEntry_used_walker((Node *) (qry->havingQual), context)) + return true; + return false; + } + return expression_tree_walker(node, rangeTableEntry_used_walker, + (void *) context); +} - return FALSE; +static bool +rangeTableEntry_used(Node *node, int rt_index, int sublevels_up) +{ + rangeTableEntry_used_context context; + + context.rt_index = rt_index; + context.sublevels_up = sublevels_up; + return rangeTableEntry_used_walker(node, &context); } @@ -358,667 +220,247 @@ rangeTableEntry_used(Node *node, int rt_index, int sublevels_up) * Check if a specific attribute number of a RTE is used * somewhere in the query */ + +typedef struct { + int rt_index; + int attno; + int sublevels_up; +} attribute_used_context; + static bool -attribute_used(Node *node, int rt_index, int attno, int sublevels_up) +attribute_used_walker (Node *node, + attribute_used_context *context) { if (node == NULL) - return FALSE; - - switch (nodeTag(node)) + return false; + if (IsA(node, Var)) { - case T_TargetEntry: - { - TargetEntry *tle = (TargetEntry *) node; - - return attribute_used( - (Node *) (tle->expr), - rt_index, - attno, - sublevels_up); - } - break; - - case T_Aggref: - { - Aggref *aggref = (Aggref *) node; - - return attribute_used( - (Node *) (aggref->target), - rt_index, - attno, - sublevels_up); - } - break; - - case T_GroupClause: - return FALSE; - - case T_Expr: - { - Expr *exp = (Expr *) node; - - return attribute_used( - (Node *) (exp->args), - rt_index, - attno, - sublevels_up); - } - break; - - case T_Iter: - { - Iter *iter = (Iter *) node; - - return attribute_used( - (Node *) (iter->iterexpr), - rt_index, - attno, - sublevels_up); - } - break; - - case T_ArrayRef: - { - ArrayRef *ref = (ArrayRef *) node; - - if (attribute_used( - (Node *) (ref->refupperindexpr), - rt_index, - attno, - sublevels_up)) - return TRUE; - - if (attribute_used( - (Node *) (ref->reflowerindexpr), - rt_index, - attno, - sublevels_up)) - return TRUE; - - if (attribute_used( - (Node *) (ref->refexpr), - rt_index, - attno, - sublevels_up)) - return TRUE; - - if (attribute_used( - (Node *) (ref->refassgnexpr), - rt_index, - attno, - sublevels_up)) - return TRUE; - - return FALSE; - } - break; - - case T_Var: - { - Var *var = (Var *) node; - - if (var->varlevelsup == sublevels_up) - return var->varno == rt_index; - else - return FALSE; - } - break; - - case T_Param: - return FALSE; - - case T_Const: - return FALSE; - - case T_List: - { - List *l; - - foreach(l, (List *) node) - { - if (attribute_used( - (Node *) lfirst(l), - rt_index, - attno, - sublevels_up)) - return TRUE; - } - return FALSE; - } - break; - - case T_SubLink: - { - SubLink *sub = (SubLink *) node; - - if (attribute_used( - (Node *) (sub->lefthand), - rt_index, - attno, - sublevels_up)) - return TRUE; - - if (attribute_used( - (Node *) (sub->subselect), - rt_index, - attno, - sublevels_up + 1)) - return TRUE; - - return FALSE; - } - break; - - case T_Query: - { - Query *qry = (Query *) node; - - if (attribute_used( - (Node *) (qry->targetList), - rt_index, - attno, - sublevels_up)) - return TRUE; - - if (attribute_used( - (Node *) (qry->qual), - rt_index, - attno, - sublevels_up)) - return TRUE; - - if (attribute_used( - (Node *) (qry->havingQual), - rt_index, - attno, - sublevels_up)) - return TRUE; - - return FALSE; - } - break; - - default: - elog(NOTICE, "unknown node tag %d in attribute_used()", nodeTag(node)); - elog(NOTICE, "Node is: %s", nodeToString(node)); - break; - + Var *var = (Var *) node; + if (var->varlevelsup == context->sublevels_up && + var->varno == context->rt_index && + var->varattno == context->attno) + return true; + return false; + } + if (IsA(node, SubLink)) + { + /* + * Standard expression_tree_walker will not recurse into subselect, + * but here we must do so. + */ + SubLink *sub = (SubLink *) node; + + if (attribute_used_walker((Node *) (sub->lefthand), context)) + return true; + if (attribute_used((Node *) (sub->subselect), + context->rt_index, + context->attno, + context->sublevels_up + 1)) + return true; + return false; + } + if (IsA(node, Query)) + { + /* Reach here after recursing down into subselect above... */ + Query *qry = (Query *) node; + + if (attribute_used_walker((Node *) (qry->targetList), context)) + return true; + if (attribute_used_walker((Node *) (qry->qual), context)) + return true; + if (attribute_used_walker((Node *) (qry->havingQual), context)) + return true; + return false; } + return expression_tree_walker(node, attribute_used_walker, + (void *) context); +} + +static bool +attribute_used(Node *node, int rt_index, int attno, int sublevels_up) +{ + attribute_used_context context; - return FALSE; + context.rt_index = rt_index; + context.attno = attno; + context.sublevels_up = sublevels_up; + return attribute_used_walker(node, &context); } /* * modifyAggrefUplevel - * In the newly created sublink for an aggregate column used in - * the qualification, we must adjust the varlevelsup in all the + * the qualification, we must increment the varlevelsup in all the * var nodes. + * + * NOTE: although this has the form of a walker, we cheat and modify the + * Var nodes in-place. The given expression tree should have been copied + * earlier to ensure that no unwanted side-effects occur! */ -static void -modifyAggrefUplevel(Node *node) +static bool +modifyAggrefUplevel(Node *node, void *context) { if (node == NULL) - return; - - switch (nodeTag(node)) + return false; + if (IsA(node, Var)) { - case T_TargetEntry: - { - TargetEntry *tle = (TargetEntry *) node; - - modifyAggrefUplevel( - (Node *) (tle->expr)); - } - break; - - case T_Aggref: - { - Aggref *aggref = (Aggref *) node; - - modifyAggrefUplevel( - (Node *) (aggref->target)); - } - break; - - case T_Expr: - { - Expr *exp = (Expr *) node; - - modifyAggrefUplevel( - (Node *) (exp->args)); - } - break; - - case T_Iter: - { - Iter *iter = (Iter *) node; - - modifyAggrefUplevel( - (Node *) (iter->iterexpr)); - } - break; - - case T_ArrayRef: - { - ArrayRef *ref = (ArrayRef *) node; - - modifyAggrefUplevel( - (Node *) (ref->refupperindexpr)); - modifyAggrefUplevel( - (Node *) (ref->reflowerindexpr)); - modifyAggrefUplevel( - (Node *) (ref->refexpr)); - modifyAggrefUplevel( - (Node *) (ref->refassgnexpr)); - } - break; - - case T_Var: - { - Var *var = (Var *) node; - - var->varlevelsup++; - } - break; - - case T_Param: - break; - - case T_Const: - break; - - case T_List: - { - List *l; - - foreach(l, (List *) node) - modifyAggrefUplevel( - (Node *) lfirst(l)); - } - break; - - case T_SubLink: - { - SubLink *sub = (SubLink *) node; - - modifyAggrefUplevel( - (Node *) (sub->lefthand)); - - modifyAggrefUplevel( - (Node *) (sub->subselect)); - } - break; - - case T_Query: - { - Query *qry = (Query *) node; - - modifyAggrefUplevel( - (Node *) (qry->targetList)); - - modifyAggrefUplevel( - (Node *) (qry->qual)); - - modifyAggrefUplevel( - (Node *) (qry->havingQual)); - - } - break; - - default: - elog(NOTICE, "unknown node tag %d in modifyAggrefUplevel()", nodeTag(node)); - elog(NOTICE, "Node is: %s", nodeToString(node)); - break; + Var *var = (Var *) node; + var->varlevelsup++; + return false; + } + if (IsA(node, SubLink)) + { + /* + * Standard expression_tree_walker will not recurse into subselect, + * but here we must do so. + */ + SubLink *sub = (SubLink *) node; + if (modifyAggrefUplevel((Node *) (sub->lefthand), context)) + return true; + if (modifyAggrefUplevel((Node *) (sub->subselect), context)) + return true; + return false; } + if (IsA(node, Query)) + { + /* Reach here after recursing down into subselect above... */ + Query *qry = (Query *) node; + + if (modifyAggrefUplevel((Node *) (qry->targetList), context)) + return true; + if (modifyAggrefUplevel((Node *) (qry->qual), context)) + return true; + if (modifyAggrefUplevel((Node *) (qry->havingQual), context)) + return true; + return false; + } + return expression_tree_walker(node, modifyAggrefUplevel, + (void *) context); } /* * modifyAggrefChangeVarnodes - * Change the var nodes in a sublink created for an aggregate column - * used in the qualification that is subject of the aggregate - * function to point to the correct local RTE. + * used in the qualification to point to the correct local RTE. + * + * NOTE: although this has the form of a walker, we cheat and modify the + * Var nodes in-place. The given expression tree should have been copied + * earlier to ensure that no unwanted side-effects occur! */ -static void -modifyAggrefChangeVarnodes(Node **nodePtr, int rt_index, int new_index, int sublevels_up) -{ - Node *node = *nodePtr; - if (node == NULL) - return; +typedef struct { + int rt_index; + int new_index; + int sublevels_up; +} modifyAggrefChangeVarnodes_context; - switch (nodeTag(node)) +static bool +modifyAggrefChangeVarnodes_walker(Node *node, + modifyAggrefChangeVarnodes_context *context) +{ + if (node == NULL) + return false; + if (IsA(node, Var)) { - case T_TargetEntry: - { - TargetEntry *tle = (TargetEntry *) node; + Var *var = (Var *) node; - modifyAggrefChangeVarnodes( - (Node **) (&(tle->expr)), - rt_index, - new_index, - sublevels_up); - } - break; - - case T_Aggref: - { - Aggref *aggref = (Aggref *) node; - - modifyAggrefChangeVarnodes( - (Node **) (&(aggref->target)), - rt_index, - new_index, - sublevels_up); - } - break; - - case T_GroupClause: - break; - - case T_Expr: - { - Expr *exp = (Expr *) node; - - modifyAggrefChangeVarnodes( - (Node **) (&(exp->args)), - rt_index, - new_index, - sublevels_up); - } - break; - - case T_Iter: - { - Iter *iter = (Iter *) node; - - modifyAggrefChangeVarnodes( - (Node **) (&(iter->iterexpr)), - rt_index, - new_index, - sublevels_up); - } - break; - - case T_ArrayRef: - { - ArrayRef *ref = (ArrayRef *) node; - - modifyAggrefChangeVarnodes( - (Node **) (&(ref->refupperindexpr)), - rt_index, - new_index, - sublevels_up); - modifyAggrefChangeVarnodes( - (Node **) (&(ref->reflowerindexpr)), - rt_index, - new_index, - sublevels_up); - modifyAggrefChangeVarnodes( - (Node **) (&(ref->refexpr)), - rt_index, - new_index, - sublevels_up); - modifyAggrefChangeVarnodes( - (Node **) (&(ref->refassgnexpr)), - rt_index, - new_index, - sublevels_up); - } - break; - - case T_Var: - { - Var *var = (Var *) node; - - if (var->varlevelsup == sublevels_up && - var->varno == rt_index) - { - var = copyObject(var); - var->varno = new_index; - var->varnoold = new_index; - var->varlevelsup = 0; - - *nodePtr = (Node *) var; - } - } - break; - - case T_Param: - break; - - case T_Const: - break; - - case T_List: - { - List *l; - - foreach(l, (List *) node) - modifyAggrefChangeVarnodes( - (Node **) (&lfirst(l)), - rt_index, - new_index, - sublevels_up); - } - break; - - case T_SubLink: - { - SubLink *sub = (SubLink *) node; - - modifyAggrefChangeVarnodes( - (Node **) (&(sub->lefthand)), - rt_index, - new_index, - sublevels_up); - - modifyAggrefChangeVarnodes( - (Node **) (&(sub->subselect)), - rt_index, - new_index, - sublevels_up + 1); - } - break; - - case T_Query: - { - Query *qry = (Query *) node; - - modifyAggrefChangeVarnodes( - (Node **) (&(qry->targetList)), - rt_index, - new_index, - sublevels_up); - - modifyAggrefChangeVarnodes( - (Node **) (&(qry->qual)), - rt_index, - new_index, - sublevels_up); - - modifyAggrefChangeVarnodes( - (Node **) (&(qry->havingQual)), - rt_index, - new_index, - sublevels_up); - } - break; - - default: - elog(NOTICE, "unknown node tag %d in modifyAggrefChangeVarnodes()", nodeTag(node)); - elog(NOTICE, "Node is: %s", nodeToString(node)); - break; + if (var->varlevelsup == context->sublevels_up && + var->varno == context->rt_index) + { + var->varno = context->new_index; + var->varnoold = context->new_index; + var->varlevelsup = 0; + } + return false; + } + if (IsA(node, SubLink)) + { + /* + * Standard expression_tree_walker will not recurse into subselect, + * but here we must do so. + */ + SubLink *sub = (SubLink *) node; + + if (modifyAggrefChangeVarnodes_walker((Node *) (sub->lefthand), + context)) + return true; + if (modifyAggrefChangeVarnodes((Node *) (sub->subselect), + context->rt_index, + context->new_index, + context->sublevels_up + 1)) + return true; + return false; + } + if (IsA(node, Query)) + { + /* Reach here after recursing down into subselect above... */ + Query *qry = (Query *) node; + + if (modifyAggrefChangeVarnodes_walker((Node *) (qry->targetList), + context)) + return true; + if (modifyAggrefChangeVarnodes_walker((Node *) (qry->qual), + context)) + return true; + if (modifyAggrefChangeVarnodes_walker((Node *) (qry->havingQual), + context)) + return true; + return false; + } + return expression_tree_walker(node, modifyAggrefChangeVarnodes_walker, + (void *) context); +} +static bool +modifyAggrefChangeVarnodes(Node *node, int rt_index, int new_index, + int sublevels_up) +{ + modifyAggrefChangeVarnodes_context context; - } + context.rt_index = rt_index; + context.new_index = new_index; + context.sublevels_up = sublevels_up; + return modifyAggrefChangeVarnodes_walker(node, &context); } /* * modifyAggrefDropQual - - * remove the pure aggref clase from a qualification + * remove the pure aggref clause from a qualification + * + * targetNode is a boolean expression node somewhere within the given + * expression tree. When we find it, replace it with a constant TRUE. + * The return tree is a modified copy of the given tree; the given tree + * is not altered. + * + * Note: we don't recurse into subselects looking for targetNode; that's + * not necessary in the current usage, since in fact targetNode will be + * within the same select level as the given toplevel node. */ -static void -modifyAggrefDropQual(Node **nodePtr, Node *orignode, Expr *expr) +static Node * +modifyAggrefDropQual(Node *node, Node *targetNode) { - Node *node = *nodePtr; - if (node == NULL) - return; - - switch (nodeTag(node)) + return NULL; + if (node == targetNode) { - case T_Var: - break; - - case T_Aggref: - { - Aggref *aggref = (Aggref *) node; - Aggref *oaggref = (Aggref *) orignode; - - modifyAggrefDropQual( - (Node **) (&(aggref->target)), - (Node *) (oaggref->target), - expr); - } - break; - - case T_Param: - break; - - case T_Const: - break; - - case T_GroupClause: - break; - - case T_Expr: - { - Expr *this_expr = (Expr *) node; - Expr *orig_expr = (Expr *) orignode; - - if (orig_expr == expr) - { - Const *ctrue; - - if (expr->typeOid != BOOLOID) - elog(ERROR, - "aggregate expression in qualification isn't of type bool"); - ctrue = makeNode(Const); - ctrue->consttype = BOOLOID; - ctrue->constlen = 1; - ctrue->constisnull = FALSE; - ctrue->constvalue = (Datum) TRUE; - ctrue->constbyval = TRUE; - - *nodePtr = (Node *) ctrue; - } - else - modifyAggrefDropQual( - (Node **) (&(this_expr->args)), - (Node *) (orig_expr->args), - expr); - } - break; - - case T_Iter: - { - Iter *iter = (Iter *) node; - Iter *oiter = (Iter *) orignode; - - modifyAggrefDropQual( - (Node **) (&(iter->iterexpr)), - (Node *) (oiter->iterexpr), - expr); - } - break; - - case T_ArrayRef: - { - ArrayRef *ref = (ArrayRef *) node; - ArrayRef *oref = (ArrayRef *) orignode; - - modifyAggrefDropQual( - (Node **) (&(ref->refupperindexpr)), - (Node *) (oref->refupperindexpr), - expr); - modifyAggrefDropQual( - (Node **) (&(ref->reflowerindexpr)), - (Node *) (oref->reflowerindexpr), - expr); - modifyAggrefDropQual( - (Node **) (&(ref->refexpr)), - (Node *) (oref->refexpr), - expr); - modifyAggrefDropQual( - (Node **) (&(ref->refassgnexpr)), - (Node *) (oref->refassgnexpr), - expr); - } - break; - - case T_List: - { - List *l; - List *ol = (List *) orignode; - int li = 0; - - foreach(l, (List *) node) - { - modifyAggrefDropQual( - (Node **) (&(lfirst(l))), - (Node *) nth(li, ol), - expr); - li++; - } - } - break; - - case T_SubLink: - { - SubLink *sub = (SubLink *) node; - SubLink *osub = (SubLink *) orignode; - - /* what about the lefthand? */ - modifyAggrefDropQual( - (Node **) (&(sub->subselect)), - (Node *) (osub->subselect), - expr); - } - break; - - case T_Query: - { - Query *qry = (Query *) node; - Query *oqry = (Query *) orignode; - - modifyAggrefDropQual( - (Node **) (&(qry->qual)), - (Node *) (oqry->qual), - expr); - - modifyAggrefDropQual( - (Node **) (&(qry->havingQual)), - (Node *) (oqry->havingQual), - expr); - } - break; - - default: - elog(NOTICE, "unknown node tag %d in modifyAggrefDropQual()", nodeTag(node)); - elog(NOTICE, "Node is: %s", nodeToString(node)); - break; - + Expr *expr = (Expr *) node; + if (! IsA(expr, Expr) || expr->typeOid != BOOLOID) + elog(ERROR, + "aggregate expression in qualification isn't of type bool"); + return (Node *) makeConst(BOOLOID, 1, (Datum) true, + false, true, false, false); } + return expression_tree_mutator(node, modifyAggrefDropQual, + (void *) targetNode); } - /* * modifyAggrefMakeSublink - * Create a sublink node for a qualification expression that @@ -1029,7 +471,6 @@ modifyAggrefMakeSublink(Expr *origexp, Query *parsetree) { SubLink *sublink; Query *subquery; - Node *subqual; RangeTblEntry *rte; Aggref *aggref; Var *target; @@ -1037,24 +478,22 @@ modifyAggrefMakeSublink(Expr *origexp, Query *parsetree) Resdom *resdom; Expr *exp = copyObject(origexp); - if (nodeTag(nth(0, exp->args)) == T_Aggref) + if (IsA(nth(0, exp->args), Aggref)) { - if (nodeTag(nth(1, exp->args)) == T_Aggref) - elog(ERROR, "rewrite: comparision of 2 aggregate columns not supported"); + if (IsA(nth(1, exp->args), Aggref)) + elog(ERROR, "rewrite: comparison of 2 aggregate columns not supported"); else elog(ERROR, "rewrite: aggregate column of view must be at right side in qual"); + /* XXX could try to commute operator, instead of failing */ } aggref = (Aggref *) nth(1, exp->args); target = (Var *) (aggref->target); - /* XXX bogus --- agg's target might not be a Var! */ + if (! IsA(target, Var)) + elog(ERROR, "rewrite: aggregates of views only allowed on simple variables for now"); rte = (RangeTblEntry *) nth(target->varno - 1, parsetree->rtable); - tle = makeNode(TargetEntry); resdom = makeNode(Resdom); - - aggref->usenulls = TRUE; /* XXX safe for all aggs?? */ - resdom->resno = 1; resdom->restype = aggref->aggtype; resdom->restypmod = -1; @@ -1063,15 +502,14 @@ modifyAggrefMakeSublink(Expr *origexp, Query *parsetree) resdom->reskeyop = 0; resdom->resjunk = false; + tle = makeNode(TargetEntry); tle->resdom = resdom; - tle->expr = (Node *) aggref; - - subqual = copyObject(parsetree->qual); - modifyAggrefDropQual((Node **) &subqual, (Node *) parsetree->qual, origexp); + tle->expr = (Node *) aggref; /* note this is from the copied expr */ sublink = makeNode(SubLink); sublink->subLinkType = EXPR_SUBLINK; - sublink->useor = FALSE; + sublink->useor = false; + /* note lefthand and oper are made from the copied expr */ sublink->lefthand = lcons(lfirst(exp->args), NIL); sublink->oper = lcons(exp->oper, NIL); @@ -1088,21 +526,25 @@ modifyAggrefMakeSublink(Expr *origexp, Query *parsetree) subquery->unionall = FALSE; subquery->uniqueFlag = NULL; subquery->sortClause = NULL; - subquery->rtable = lappend(NIL, rte); - subquery->targetList = lappend(NIL, tle); - subquery->qual = subqual; + subquery->rtable = lcons(rte, NIL); + subquery->targetList = lcons(tle, NIL); + subquery->qual = modifyAggrefDropQual((Node *) parsetree->qual, + (Node *) origexp); subquery->groupClause = NIL; subquery->havingQual = NULL; subquery->hasAggs = TRUE; subquery->hasSubLinks = FALSE; subquery->unionClause = NULL; - - modifyAggrefUplevel((Node *) sublink); - - modifyAggrefChangeVarnodes((Node **) &(sublink->lefthand), target->varno, - 1, target->varlevelsup); - modifyAggrefChangeVarnodes((Node **) &(sublink->subselect), target->varno, + modifyAggrefUplevel((Node *) subquery, NULL); + /* + * Note: it might appear that we should be passing target->varlevelsup+1 + * here, since modifyAggrefUplevel has increased all the varlevelsup + * values in the subquery. However, target itself is a pointer to a + * Var node in the subquery, so it's been incremented too! What a kluge + * this all is ... we need to make subquery RTEs so it can go away... + */ + modifyAggrefChangeVarnodes((Node *) subquery, target->varno, 1, target->varlevelsup); return sublink; @@ -1112,166 +554,37 @@ modifyAggrefMakeSublink(Expr *origexp, Query *parsetree) /* * modifyAggrefQual - * Search for qualification expressions that contain aggregate - * functions and substiture them by sublinks. These expressions + * functions and substitute them by sublinks. These expressions * originally come from qualifications that use aggregate columns * of a view. + * + * The return value is a modified copy of the given expression tree. */ -static void -modifyAggrefQual(Node **nodePtr, Query *parsetree) +static Node * +modifyAggrefQual(Node *node, Query *parsetree) { - Node *node = *nodePtr; - if (node == NULL) - return; - - switch (nodeTag(node)) + return NULL; + if (IsA(node, Expr)) { - case T_Var: - break; - - case T_Param: - break; - - case T_Const: - break; - - case T_GroupClause: - break; - - case T_Expr: - { - Expr *exp = (Expr *) node; - SubLink *sub; - - - if (length(exp->args) != 2) - { - modifyAggrefQual( - (Node **) (&(exp->args)), - parsetree); - break; - } - - if (nodeTag(nth(0, exp->args)) != T_Aggref && - nodeTag(nth(1, exp->args)) != T_Aggref) - { - - modifyAggrefQual( - (Node **) (&(exp->args)), - parsetree); - break; - } - - sub = modifyAggrefMakeSublink(exp, - parsetree); - - *nodePtr = (Node *) sub; - parsetree->hasSubLinks = TRUE; - } - break; - - case T_CaseExpr: - { - - /* - * We're calling recursively, and this routine knows how - * to handle lists so let it do the work to handle the - * WHEN clauses... - */ - modifyAggrefQual( - (Node **) (&(((CaseExpr *) node)->args)), - parsetree); - - modifyAggrefQual( - (Node **) (&(((CaseExpr *) node)->defresult)), - parsetree); - } - break; - - case T_CaseWhen: - { - modifyAggrefQual( - (Node **) (&(((CaseWhen *) node)->expr)), - parsetree); - - modifyAggrefQual( - (Node **) (&(((CaseWhen *) node)->result)), - parsetree); - } - break; - - case T_Iter: - { - Iter *iter = (Iter *) node; - - modifyAggrefQual( - (Node **) (&(iter->iterexpr)), - parsetree); - } - break; - - case T_ArrayRef: - { - ArrayRef *ref = (ArrayRef *) node; - - modifyAggrefQual( - (Node **) (&(ref->refupperindexpr)), - parsetree); - modifyAggrefQual( - (Node **) (&(ref->reflowerindexpr)), - parsetree); - modifyAggrefQual( - (Node **) (&(ref->refexpr)), - parsetree); - modifyAggrefQual( - (Node **) (&(ref->refassgnexpr)), - parsetree); - } - break; - - case T_List: - { - List *l; - - foreach(l, (List *) node) - modifyAggrefQual( - (Node **) (&(lfirst(l))), - parsetree); - } - break; - - case T_SubLink: - { - SubLink *sub = (SubLink *) node; - - /* lefthand ??? */ - modifyAggrefQual( - (Node **) (&(sub->subselect)), - (Query *) (sub->subselect)); - } - break; - - case T_Query: - { - Query *qry = (Query *) node; - - modifyAggrefQual( - (Node **) (&(qry->qual)), - parsetree); - - modifyAggrefQual( - (Node **) (&(qry->havingQual)), - parsetree); - } - break; - - default: - elog(NOTICE, "unknown node tag %d in modifyAggrefQual()", nodeTag(node)); - elog(NOTICE, "Node is: %s", nodeToString(node)); - break; - + Expr *expr = (Expr *) node; + if (length(expr->args) == 2 && + (IsA(lfirst(expr->args), Aggref) || + IsA(lsecond(expr->args), Aggref))) + { + SubLink *sub = modifyAggrefMakeSublink(expr, + parsetree); + parsetree->hasSubLinks = true; + return (Node *) sub; + } + /* otherwise, fall through and copy the expr normally */ } + /* We do NOT recurse into subselects in this routine. It's sufficient + * to get rid of aggregates that are in the qual expression proper. + */ + return expression_tree_mutator(node, modifyAggrefQual, + (void *) parsetree); } @@ -1350,406 +663,141 @@ make_null(Oid type) } -static void -apply_RIR_adjust_sublevel(Node *node, int sublevels_up) +/* + * apply_RIR_adjust_sublevel - + * Set the varlevelsup field of all Var nodes in the given expression tree + * to sublevels_up. We do NOT recurse into subselects. + * + * NOTE: although this has the form of a walker, we cheat and modify the + * Var nodes in-place. The given expression tree should have been copied + * earlier to ensure that no unwanted side-effects occur! + */ +static bool +apply_RIR_adjust_sublevel_walker(Node *node, int *sublevels_up) { if (node == NULL) - return; - - switch (nodeTag(node)) + return false; + if (IsA(node, Var)) { - case T_TargetEntry: - { - TargetEntry *tle = (TargetEntry *) node; - - apply_RIR_adjust_sublevel( - (Node *) (tle->expr), - sublevels_up); - } - break; - - case T_Aggref: - { - Aggref *aggref = (Aggref *) node; - - apply_RIR_adjust_sublevel( - (Node *) (aggref->target), - sublevels_up); - } - break; - - case T_GroupClause: - break; - - case T_Expr: - { - Expr *exp = (Expr *) node; - - apply_RIR_adjust_sublevel( - (Node *) (exp->args), - sublevels_up); - } - break; - - case T_Iter: - { - Iter *iter = (Iter *) node; - - apply_RIR_adjust_sublevel( - (Node *) (iter->iterexpr), - sublevels_up); - } - break; - - case T_ArrayRef: - { - ArrayRef *ref = (ArrayRef *) node; - - apply_RIR_adjust_sublevel( - (Node *) (ref->refupperindexpr), - sublevels_up); - - apply_RIR_adjust_sublevel( - (Node *) (ref->reflowerindexpr), - sublevels_up); - - apply_RIR_adjust_sublevel( - (Node *) (ref->refexpr), - sublevels_up); - - apply_RIR_adjust_sublevel( - (Node *) (ref->refassgnexpr), - sublevels_up); - } - break; - - case T_Var: - { - Var *var = (Var *) node; - - var->varlevelsup = sublevels_up; - } - break; - - case T_Param: - break; - - case T_Const: - break; - - case T_List: - { - List *l; - - foreach(l, (List *) node) - { - apply_RIR_adjust_sublevel( - (Node *) lfirst(l), - sublevels_up); - } - } - break; - - case T_CaseExpr: - { - CaseExpr *exp = (CaseExpr *) node; - - apply_RIR_adjust_sublevel( - (Node *) (exp->args), - sublevels_up); - - apply_RIR_adjust_sublevel( - (Node *) (exp->defresult), - sublevels_up); - } - break; - - case T_CaseWhen: - { - CaseWhen *exp = (CaseWhen *) node; - - apply_RIR_adjust_sublevel( - (Node *) (exp->expr), - sublevels_up); - - apply_RIR_adjust_sublevel( - (Node *) (exp->result), - sublevels_up); - } - break; - - default: - elog(NOTICE, "unknown node tag %d in attribute_used()", nodeTag(node)); - elog(NOTICE, "Node is: %s", nodeToString(node)); - break; - + Var *var = (Var *) node; + var->varlevelsup = *sublevels_up; + return false; } + return expression_tree_walker(node, apply_RIR_adjust_sublevel_walker, + (void *) sublevels_up); } - static void -apply_RIR_view(Node **nodePtr, int rt_index, RangeTblEntry *rte, List *tlist, int *modified, int sublevels_up) +apply_RIR_adjust_sublevel(Node *node, int sublevels_up) { - Node *node = *nodePtr; - - if (node == NULL) - return; - - switch (nodeTag(node)) - { - case T_TargetEntry: - { - TargetEntry *tle = (TargetEntry *) node; - - apply_RIR_view( - (Node **) (&(tle->expr)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - } - break; - - case T_Aggref: - { - Aggref *aggref = (Aggref *) node; - - apply_RIR_view( - (Node **) (&(aggref->target)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - } - break; - - case T_GroupClause: - break; - - case T_Expr: - { - Expr *exp = (Expr *) node; - - apply_RIR_view( - (Node **) (&(exp->args)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - } - break; + apply_RIR_adjust_sublevel_walker(node, &sublevels_up); +} - case T_Iter: - { - Iter *iter = (Iter *) node; - - apply_RIR_view( - (Node **) (&(iter->iterexpr)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - } - break; - case T_ArrayRef: - { - ArrayRef *ref = (ArrayRef *) node; - - apply_RIR_view( - (Node **) (&(ref->refupperindexpr)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - apply_RIR_view( - (Node **) (&(ref->reflowerindexpr)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - apply_RIR_view( - (Node **) (&(ref->refexpr)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - apply_RIR_view( - (Node **) (&(ref->refassgnexpr)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - } - break; - - case T_Var: - { - Var *var = (Var *) node; +/* + * apply_RIR_view + * Replace Vars matching a given RT index with copies of TL expressions. + */ - if (var->varlevelsup == sublevels_up && - var->varno == rt_index) - { - Node *exp; - - if (var->varattno < 0) - elog(ERROR, "system column %s not available - %s is a view", get_attname(rte->relid, var->varattno), rte->relname); - exp = FindMatchingTLEntry( - tlist, - get_attname(rte->relid, - var->varattno)); - - if (exp == NULL) - { - *nodePtr = make_null(var->vartype); - return; - } - - exp = copyObject(exp); - if (var->varlevelsup > 0) - apply_RIR_adjust_sublevel(exp, var->varlevelsup); - *nodePtr = exp; - *modified = TRUE; - } - } - break; +typedef struct { + int rt_index; + int sublevels_up; + RangeTblEntry *rte; + List *tlist; + int *modified; +} apply_RIR_view_context; - case T_Param: - break; +static Node * +apply_RIR_view_mutator(Node *node, + apply_RIR_view_context *context) +{ + if (node == NULL) + return NULL; + if (IsA(node, Var)) + { + Var *var = (Var *) node; - case T_Const: - break; + if (var->varlevelsup == context->sublevels_up && + var->varno == context->rt_index) + { + Node *expr; - case T_List: - { - List *l; - - foreach(l, (List *) node) - apply_RIR_view( - (Node **) (&(lfirst(l))), - rt_index, - rte, - tlist, - modified, - sublevels_up); - } - break; + if (var->varattno < 0) + elog(ERROR, "system column %s not available - %s is a view", + get_attname(context->rte->relid, var->varattno), + context->rte->relname); - case T_SubLink: + expr = FindMatchingTLEntry(context->tlist, + get_attname(context->rte->relid, + var->varattno)); + if (expr == NULL) { - SubLink *sub = (SubLink *) node; - - apply_RIR_view( - (Node **) (&(sub->lefthand)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - - apply_RIR_view( - (Node **) (&(sub->subselect)), - rt_index, - rte, - tlist, - modified, - sublevels_up + 1); + /* XXX shouldn't this be an error condition? */ + return make_null(var->vartype); } - break; - case T_Query: - { - Query *qry = (Query *) node; - - apply_RIR_view( - (Node **) (&(qry->targetList)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - - apply_RIR_view( - (Node **) (&(qry->qual)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - - apply_RIR_view( - (Node **) (&(qry->havingQual)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - } - break; + expr = copyObject(expr); + if (var->varlevelsup > 0) + apply_RIR_adjust_sublevel(expr, var->varlevelsup); + *(context->modified) = true; + return (Node *) expr; + } + /* otherwise fall through to copy the var normally */ + } + /* + * Since expression_tree_mutator won't touch subselects, we have to + * handle them specially. + */ + if (IsA(node, SubLink)) + { + SubLink *sublink = (SubLink *) node; + SubLink *newnode; + + FLATCOPY(newnode, sublink, SubLink); + MUTATE(newnode->lefthand, sublink->lefthand, List *, + apply_RIR_view_mutator, context); + context->sublevels_up++; + MUTATE(newnode->subselect, sublink->subselect, Node *, + apply_RIR_view_mutator, context); + context->sublevels_up--; + return (Node *) newnode; + } + if (IsA(node, Query)) + { + Query *query = (Query *) node; + Query *newnode; + + FLATCOPY(newnode, query, Query); + MUTATE(newnode->targetList, query->targetList, List *, + apply_RIR_view_mutator, context); + MUTATE(newnode->qual, query->qual, Node *, + apply_RIR_view_mutator, context); + MUTATE(newnode->havingQual, query->havingQual, Node *, + apply_RIR_view_mutator, context); + return (Node *) newnode; + } + return expression_tree_mutator(node, apply_RIR_view_mutator, + (void *) context); +} - case T_CaseExpr: - { - CaseExpr *exp = (CaseExpr *) node; - - apply_RIR_view( - (Node **) (&(exp->args)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - - apply_RIR_view( - (Node **) (&(exp->defresult)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - } - break; +static Node * +apply_RIR_view(Node *node, int rt_index, RangeTblEntry *rte, List *tlist, + int *modified, int sublevels_up) +{ + apply_RIR_view_context context; - case T_CaseWhen: - { - CaseWhen *exp = (CaseWhen *) node; - - apply_RIR_view( - (Node **) (&(exp->expr)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - - apply_RIR_view( - (Node **) (&(exp->result)), - rt_index, - rte, - tlist, - modified, - sublevels_up); - } - break; + context.rt_index = rt_index; + context.sublevels_up = sublevels_up; + context.rte = rte; + context.tlist = tlist; + context.modified = modified; - default: - elog(NOTICE, "unknown node tag %d in apply_RIR_view()", nodeTag(node)); - elog(NOTICE, "Node is: %s", nodeToString(node)); - break; - } + return apply_RIR_view_mutator(node, &context); } -extern void CheckSelectForUpdate(Query *rule_action); /* in analyze.c */ -static void +static Query * ApplyRetrieveRule(Query *parsetree, RewriteRule *rule, int rt_index, @@ -1764,7 +812,7 @@ ApplyRetrieveRule(Query *parsetree, *l; int nothing, rt_length; - int badsql = FALSE; + int badsql = false; rule_qual = rule->qual; if (rule->actions) @@ -1773,7 +821,7 @@ ApplyRetrieveRule(Query *parsetree, * rules with more than one * action? -ay */ - return; + return parsetree; rule_action = copyObject(lfirst(rule->actions)); nothing = FALSE; } @@ -1817,6 +865,7 @@ ApplyRetrieveRule(Query *parsetree, * them. */ ((RowMark *) lfirst(l))->info &= ~ROW_MARK_FOR_UPDATE; + foreach(l2, rule_action->rtable) { @@ -1847,12 +896,16 @@ ApplyRetrieveRule(Query *parsetree, if (relation_level) { - apply_RIR_view((Node **) &parsetree, rt_index, - (RangeTblEntry *) nth(rt_index - 1, rtable), - rule_action->targetList, modified, 0); - apply_RIR_view((Node **) &rule_action, rt_index, - (RangeTblEntry *) nth(rt_index - 1, rtable), - rule_action->targetList, modified, 0); + RangeTblEntry *rte = (RangeTblEntry *) nth(rt_index - 1, rtable); + + parsetree = (Query *) apply_RIR_view((Node *) parsetree, + rt_index, rte, + rule_action->targetList, + modified, 0); + rule_action = (Query *) apply_RIR_view((Node *) rule_action, + rt_index, rte, + rule_action->targetList, + modified, 0); } else { @@ -1868,153 +921,59 @@ ApplyRetrieveRule(Query *parsetree, parsetree->hasAggs = (rule_action->hasAggs || parsetree->hasAggs); parsetree->hasSubLinks = (rule_action->hasSubLinks || parsetree->hasSubLinks); } + + return parsetree; } -static void -fireRIRonSubselect(Node *node) +/* + * fireRIRonSubselect - + * Apply fireRIRrules() to each subselect found in the given tree. + * + * NOTE: although this has the form of a walker, we cheat and modify the + * SubLink nodes in-place. It is caller's responsibility to ensure that + * no unwanted side-effects occur! + */ +static bool +fireRIRonSubselect(Node *node, void *context) { if (node == NULL) - return; - - switch (nodeTag(node)) + return false; + if (IsA(node, SubLink)) { - case T_TargetEntry: - { - TargetEntry *tle = (TargetEntry *) node; - - fireRIRonSubselect( - (Node *) (tle->expr)); - } - break; - - case T_Aggref: - { - Aggref *aggref = (Aggref *) node; - - fireRIRonSubselect( - (Node *) (aggref->target)); - } - break; - - case T_GroupClause: - break; - - case T_Expr: - { - Expr *exp = (Expr *) node; - - fireRIRonSubselect( - (Node *) (exp->args)); - } - break; - - case T_Iter: - { - Iter *iter = (Iter *) node; - - fireRIRonSubselect( - (Node *) (iter->iterexpr)); - } - break; - - case T_ArrayRef: - { - ArrayRef *ref = (ArrayRef *) node; - - fireRIRonSubselect( - (Node *) (ref->refupperindexpr)); - fireRIRonSubselect( - (Node *) (ref->reflowerindexpr)); - fireRIRonSubselect( - (Node *) (ref->refexpr)); - fireRIRonSubselect( - (Node *) (ref->refassgnexpr)); - } - break; - - case T_Var: - break; - - case T_Param: - break; - - case T_Const: - break; - - case T_List: - { - List *l; - - foreach(l, (List *) node) - fireRIRonSubselect( - (Node *) (lfirst(l))); - } - break; - - case T_SubLink: - { - SubLink *sub = (SubLink *) node; - Query *qry; - - fireRIRonSubselect( - (Node *) (sub->lefthand)); - - qry = fireRIRrules((Query *) (sub->subselect)); - - fireRIRonSubselect( - (Node *) qry); - - sub->subselect = (Node *) qry; - } - break; - - case T_CaseExpr: - { - CaseExpr *exp = (CaseExpr *) node; - - fireRIRonSubselect( - (Node *) (exp->args)); - - fireRIRonSubselect( - (Node *) (exp->defresult)); - } - break; - - case T_CaseWhen: - { - CaseWhen *exp = (CaseWhen *) node; - - fireRIRonSubselect( - (Node *) (exp->expr)); - - fireRIRonSubselect( - (Node *) (exp->result)); - } - break; - - case T_Query: - { - Query *qry = (Query *) node; - - fireRIRonSubselect( - (Node *) (qry->targetList)); - - fireRIRonSubselect( - (Node *) (qry->qual)); - - fireRIRonSubselect( - (Node *) (qry->havingQual)); - } - break; - - default: - elog(NOTICE, "unknown node tag %d in fireRIRonSubselect()", nodeTag(node)); - elog(NOTICE, "Node is: %s", nodeToString(node)); - break; - - + /* + * Standard expression_tree_walker will not recurse into subselect, + * but here we must do so. + */ + SubLink *sub = (SubLink *) node; + Query *qry; + + /* Process lefthand args */ + if (fireRIRonSubselect((Node *) (sub->lefthand), context)) + return true; + /* Do what we came for */ + qry = fireRIRrules((Query *) (sub->subselect)); + sub->subselect = (Node *) qry; + /* Must recurse to handle any sub-subselects! */ + if (fireRIRonSubselect((Node *) qry, context)) + return true; + return false; } + if (IsA(node, Query)) + { + /* Reach here after recursing down into subselect above... */ + Query *qry = (Query *) node; + + if (fireRIRonSubselect((Node *) (qry->targetList), context)) + return true; + if (fireRIRonSubselect((Node *) (qry->qual), context)) + return true; + if (fireRIRonSubselect((Node *) (qry->havingQual), context)) + return true; + return false; + } + return expression_tree_walker(node, fireRIRonSubselect, + (void *) context); } @@ -2032,7 +991,7 @@ fireRIRrules(Query *parsetree) RuleLock *rules; RewriteRule *rule; RewriteRule RIRonly; - int modified; + int modified = false; int i; List *l; @@ -2104,19 +1063,20 @@ fireRIRrules(Query *parsetree) RIRonly.qual = rule->qual; RIRonly.actions = rule->actions; - ApplyRetrieveRule(parsetree, - &RIRonly, - rt_index, - RIRonly.attrno == -1, - rel, - &modified); + parsetree = ApplyRetrieveRule(parsetree, + &RIRonly, + rt_index, + RIRonly.attrno == -1, + rel, + &modified); } heap_close(rel, AccessShareLock); } - fireRIRonSubselect((Node *) parsetree); - modifyAggrefQual((Node **) &(parsetree->qual), parsetree); + fireRIRonSubselect((Node *) parsetree, NULL); + + parsetree->qual = modifyAggrefQual(parsetree->qual, parsetree); return parsetree; } @@ -2639,9 +1599,9 @@ BasicQueryRewrite(Query *parsetree) */ if (query->hasAggs) query->hasAggs = checkQueryHasAggs((Node *) (query->targetList)) - | checkQueryHasAggs((Node *) (query->havingQual)); + || checkQueryHasAggs((Node *) (query->havingQual)); query->hasSubLinks = checkQueryHasSubLink((Node *) (query->qual)) - | checkQueryHasSubLink((Node *) (query->havingQual)); + || checkQueryHasSubLink((Node *) (query->havingQual)); results = lappend(results, query); } return results; |