Commit 524f4b2d authored by Bruce Momjian's avatar Bruce Momjian

The patch does 2 things:

        Fixes  a  bug  in  the rule system that caused a crashing
        backend when a join-view with calculated column  is  used
        in subselect.

        Modifies  EXPLAIN to explain rewritten queries instead of
        the plain SeqScan on a view. Rules can produce very  deep
MORE

Jan.
parent 858a3b57
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.24 1998/09/01 04:27:53 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.25 1998/10/21 16:21:20 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <optimizer/planner.h> #include <optimizer/planner.h>
#include <access/xact.h> #include <access/xact.h>
#include <utils/relcache.h> #include <utils/relcache.h>
#include <rewrite/rewriteHandler.h>
typedef struct ExplainState typedef struct ExplainState
{ {
...@@ -37,6 +38,8 @@ typedef struct ExplainState ...@@ -37,6 +38,8 @@ typedef struct ExplainState
} ExplainState; } ExplainState;
static char *Explain_PlanToString(Plan *plan, ExplainState *es); static char *Explain_PlanToString(Plan *plan, ExplainState *es);
static void ExplainOneQuery(Query *query, bool verbose, CommandDest dest);
/* /*
* ExplainQuery - * ExplainQuery -
...@@ -46,11 +49,8 @@ static char *Explain_PlanToString(Plan *plan, ExplainState *es); ...@@ -46,11 +49,8 @@ static char *Explain_PlanToString(Plan *plan, ExplainState *es);
void void
ExplainQuery(Query *query, bool verbose, CommandDest dest) ExplainQuery(Query *query, bool verbose, CommandDest dest)
{ {
char *s = NULL, List *rewritten;
*s2; List *l;
Plan *plan;
ExplainState *es;
int len;
if (IsAbortedTransactionBlockState()) if (IsAbortedTransactionBlockState())
{ {
...@@ -64,6 +64,35 @@ ExplainQuery(Query *query, bool verbose, CommandDest dest) ...@@ -64,6 +64,35 @@ ExplainQuery(Query *query, bool verbose, CommandDest dest)
return; return;
} }
/* Rewrite through rule system */
rewritten = QueryRewrite(query);
/* In the case of an INSTEAD NOTHING, tell at least that */
if (rewritten == NIL)
{
elog(NOTICE, "query rewrites to nothing");
return;
}
/* Explain every plan */
foreach(l, rewritten)
ExplainOneQuery(lfirst(l), verbose, dest);
}
/*
* ExplainOneQuery -
* print out the execution plan for one query
*
*/
static void
ExplainOneQuery(Query *query, bool verbose, CommandDest dest)
{
char *s = NULL,
*s2;
Plan *plan;
ExplainState *es;
int len;
/* plan the queries (XXX we've ignored rewrite!!) */ /* plan the queries (XXX we've ignored rewrite!!) */
plan = planner(query); plan = planner(query);
...@@ -202,9 +231,14 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es) ...@@ -202,9 +231,14 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
{ {
RangeTblEntry *rte = nth(((Scan *) plan)->scanrelid - 1, es->rtable); RangeTblEntry *rte = nth(((Scan *) plan)->scanrelid - 1, es->rtable);
sprintf(buf, " on %s", rte->refname); appendStringInfo(str, " on ");
if (strcmp(rte->refname, rte->relname) != 0)
{
sprintf(buf, "%s ", rte->relname);
appendStringInfo(str, buf); appendStringInfo(str, buf);
} }
appendStringInfo(str, rte->refname);
}
break; break;
default: default:
break; break;
...@@ -232,7 +266,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es) ...@@ -232,7 +266,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
for (i = 0; i < indent; i++) for (i = 0; i < indent; i++)
appendStringInfo(str, " "); appendStringInfo(str, " ");
appendStringInfo(str, " -> "); appendStringInfo(str, " -> ");
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, indent + 4, es); explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, indent + 2, es);
} }
es->rtable = saved_rtable; es->rtable = saved_rtable;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.24 1998/09/01 04:27:56 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.25 1998/10/21 16:21:21 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -350,8 +350,8 @@ tg_rewriteQuery(TgRecipe * r, ...@@ -350,8 +350,8 @@ tg_rewriteQuery(TgRecipe * r,
* need to offset the var nodes in the qual and targetlist * need to offset the var nodes in the qual and targetlist
* because they are indexed off the original rtable * because they are indexed off the original rtable
*/ */
OffsetVarNodes((Node *) inputQ->qual, rt_length); OffsetVarNodes((Node *) inputQ->qual, rt_length, 0);
OffsetVarNodes((Node *) inputQ->targetList, rt_length); OffsetVarNodes((Node *) inputQ->targetList, rt_length, 0);
/* append the range tables from the children nodes */ /* append the range tables from the children nodes */
rtable = nconc(rtable, input_rtable); rtable = nconc(rtable, input_rtable);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.25 1998/09/01 04:28:10 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.26 1998/10/21 16:21:22 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -219,10 +219,10 @@ UpdateRangeTableOfViewParse(char *viewName, Query *viewParse) ...@@ -219,10 +219,10 @@ UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
/* /*
* first offset all var nodes by 2 * first offset all var nodes by 2
*/ */
OffsetVarNodes((Node *) viewParse->targetList, 2); OffsetVarNodes((Node *) viewParse->targetList, 2, 0);
OffsetVarNodes(viewParse->qual, 2); OffsetVarNodes(viewParse->qual, 2, 0);
OffsetVarNodes(viewParse->havingQual, 2); OffsetVarNodes(viewParse->havingQual, 2, 0);
/* /*
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.24 1998/10/20 17:21:43 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.25 1998/10/21 16:21:24 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -48,8 +48,6 @@ static RewriteInfo *gatherRewriteMeta(Query *parsetree, ...@@ -48,8 +48,6 @@ static RewriteInfo *gatherRewriteMeta(Query *parsetree,
bool *instead_flag); bool *instead_flag);
static bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up); 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 bool attribute_used(Node *node, int rt_index, int attno, int sublevels_up);
static void offset_varnodes(Node *node, int offset, int sublevels_up);
static void change_varnodes(Node *node, int rt_index, int new_index, int sublevels_up);
static void modifyAggregUplevel(Node *node); static void modifyAggregUplevel(Node *node);
static void modifyAggregChangeVarnodes(Node **nodePtr, int rt_index, int new_index, int sublevels_up); static void modifyAggregChangeVarnodes(Node **nodePtr, int rt_index, int new_index, int sublevels_up);
static void modifyAggregDropQual(Node **nodePtr, Node *orignode, Expr *expr); static void modifyAggregDropQual(Node **nodePtr, Node *orignode, Expr *expr);
...@@ -107,9 +105,9 @@ gatherRewriteMeta(Query *parsetree, ...@@ -107,9 +105,9 @@ gatherRewriteMeta(Query *parsetree,
info->rt = append(info->rt, info->rule_action->rtable); info->rt = append(info->rt, info->rule_action->rtable);
info->new_varno = PRS2_NEW_VARNO + rt_length; info->new_varno = PRS2_NEW_VARNO + rt_length;
OffsetVarNodes(info->rule_action->qual, rt_length); OffsetVarNodes(info->rule_action->qual, rt_length, 0);
OffsetVarNodes((Node *) info->rule_action->targetList, rt_length); OffsetVarNodes((Node *) info->rule_action->targetList, rt_length, 0);
OffsetVarNodes(info->rule_qual, rt_length); OffsetVarNodes(info->rule_qual, rt_length, 0);
ChangeVarNodes((Node *) info->rule_action->qual, ChangeVarNodes((Node *) info->rule_action->qual,
PRS2_CURRENT_VARNO + rt_length, rt_index, 0); PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
ChangeVarNodes((Node *) info->rule_action->targetList, ChangeVarNodes((Node *) info->rule_action->targetList,
...@@ -550,364 +548,6 @@ attribute_used(Node *node, int rt_index, int attno, int sublevels_up) ...@@ -550,364 +548,6 @@ attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
} }
/*
* offset_varnodes -
* We need another version of OffsetVarNodes() when processing
* RIR rules
*/
static void
offset_varnodes(Node *node, int offset, int sublevels_up)
{
if (node == NULL)
return;
switch(nodeTag(node)) {
case T_TargetEntry:
{
TargetEntry *tle = (TargetEntry *)node;
offset_varnodes(
(Node *)(tle->expr),
offset,
sublevels_up);
}
break;
case T_Aggreg:
{
Aggreg *agg = (Aggreg *)node;
offset_varnodes(
(Node *)(agg->target),
offset,
sublevels_up);
}
break;
case T_GroupClause:
{
GroupClause *grp = (GroupClause *)node;
offset_varnodes(
(Node *)(grp->entry),
offset,
sublevels_up);
}
break;
case T_Expr:
{
Expr *exp = (Expr *)node;
offset_varnodes(
(Node *)(exp->args),
offset,
sublevels_up);
}
break;
case T_Iter:
{
Iter *iter = (Iter *)node;
offset_varnodes(
(Node *)(iter->iterexpr),
offset,
sublevels_up);
}
break;
case T_ArrayRef:
{
ArrayRef *ref = (ArrayRef *)node;
offset_varnodes(
(Node *)(ref->refupperindexpr),
offset,
sublevels_up);
offset_varnodes(
(Node *)(ref->reflowerindexpr),
offset,
sublevels_up);
offset_varnodes(
(Node *)(ref->refexpr),
offset,
sublevels_up);
offset_varnodes(
(Node *)(ref->refassgnexpr),
offset,
sublevels_up);
}
break;
case T_Var:
{
Var *var = (Var *)node;
if (var->varlevelsup == sublevels_up) {
var->varno += offset;
var->varnoold += offset;
}
}
break;
case T_Param:
break;
case T_Const:
break;
case T_List:
{
List *l;
foreach (l, (List *)node)
offset_varnodes(
(Node *)lfirst(l),
offset,
sublevels_up);
}
break;
case T_SubLink:
{
SubLink *sub = (SubLink *)node;
offset_varnodes(
(Node *)(sub->lefthand),
offset,
sublevels_up);
offset_varnodes(
(Node *)(sub->subselect),
offset,
sublevels_up + 1);
}
break;
case T_Query:
{
Query *qry = (Query *)node;
offset_varnodes(
(Node *)(qry->targetList),
offset,
sublevels_up);
offset_varnodes(
(Node *)(qry->qual),
offset,
sublevels_up);
offset_varnodes(
(Node *)(qry->havingQual),
offset,
sublevels_up);
offset_varnodes(
(Node *)(qry->groupClause),
offset,
sublevels_up);
}
break;
default:
elog(NOTICE, "unknown node tag %d in offset_varnodes()", nodeTag(node));
elog(NOTICE, "Node is: %s", nodeToString(node));
break;
}
}
/*
* change_varnodes -
* and another ChangeVarNodes() too
*/
static void
change_varnodes(Node *node, int rt_index, int new_index, int sublevels_up)
{
if (node == NULL)
return;
switch(nodeTag(node)) {
case T_TargetEntry:
{
TargetEntry *tle = (TargetEntry *)node;
change_varnodes(
(Node *)(tle->expr),
rt_index,
new_index,
sublevels_up);
}
break;
case T_Aggreg:
{
Aggreg *agg = (Aggreg *)node;
change_varnodes(
(Node *)(agg->target),
rt_index,
new_index,
sublevels_up);
}
break;
case T_GroupClause:
{
GroupClause *grp = (GroupClause *)node;
change_varnodes(
(Node *)(grp->entry),
rt_index,
new_index,
sublevels_up);
}
break;
case T_Expr:
{
Expr *exp = (Expr *)node;
change_varnodes(
(Node *)(exp->args),
rt_index,
new_index,
sublevels_up);
}
break;
case T_Iter:
{
Iter *iter = (Iter *)node;
change_varnodes(
(Node *)(iter->iterexpr),
rt_index,
new_index,
sublevels_up);
}
break;
case T_ArrayRef:
{
ArrayRef *ref = (ArrayRef *)node;
change_varnodes(
(Node *)(ref->refupperindexpr),
rt_index,
new_index,
sublevels_up);
change_varnodes(
(Node *)(ref->reflowerindexpr),
rt_index,
new_index,
sublevels_up);
change_varnodes(
(Node *)(ref->refexpr),
rt_index,
new_index,
sublevels_up);
change_varnodes(
(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->varno = new_index;
var->varnoold = new_index;
}
}
break;
case T_Param:
break;
case T_Const:
break;
case T_List:
{
List *l;
foreach (l, (List *)node)
change_varnodes(
(Node *)lfirst(l),
rt_index,
new_index,
sublevels_up);
}
break;
case T_SubLink:
{
SubLink *sub = (SubLink *)node;
change_varnodes(
(Node *)(sub->lefthand),
rt_index,
new_index,
sublevels_up);
change_varnodes(
(Node *)(sub->subselect),
rt_index,
new_index,
sublevels_up + 1);
}
break;
case T_Query:
{
Query *qry = (Query *)node;
change_varnodes(
(Node *)(qry->targetList),
rt_index,
new_index,
sublevels_up);
change_varnodes(
(Node *)(qry->qual),
rt_index,
new_index,
sublevels_up);
change_varnodes(
(Node *)(qry->havingQual),
rt_index,
new_index,
sublevels_up);
change_varnodes(
(Node *)(qry->groupClause),
rt_index,
new_index,
sublevels_up);
}
break;
default:
elog(NOTICE, "unknown node tag %d in change_varnodes()", nodeTag(node));
elog(NOTICE, "Node is: %s", nodeToString(node));
break;
}
}
/* /*
* modifyAggregUplevel - * modifyAggregUplevel -
* In the newly created sublink for an aggregate column used in * In the newly created sublink for an aggregate column used in
...@@ -1655,6 +1295,121 @@ make_null(Oid type) ...@@ -1655,6 +1295,121 @@ make_null(Oid type)
} }
static void
apply_RIR_adjust_sublevel(Node *node, int sublevels_up)
{
if (node == NULL)
return;
switch(nodeTag(node)) {
case T_TargetEntry:
{
TargetEntry *tle = (TargetEntry *)node;
apply_RIR_adjust_sublevel(
(Node *)(tle->expr),
sublevels_up);
}
break;
case T_Aggreg:
{
Aggreg *agg = (Aggreg *)node;
apply_RIR_adjust_sublevel(
(Node *)(agg->target),
sublevels_up);
}
break;
case T_GroupClause:
{
GroupClause *grp = (GroupClause *)node;
apply_RIR_adjust_sublevel(
(Node *)(grp->entry),
sublevels_up);
}
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;
default:
elog(NOTICE, "unknown node tag %d in attribute_used()", nodeTag(node));
elog(NOTICE, "Node is: %s", nodeToString(node));
break;
}
}
static void static void
apply_RIR_view(Node **nodePtr, int rt_index, RangeTblEntry *rte, List *tlist, int *modified, int sublevels_up) apply_RIR_view(Node **nodePtr, int rt_index, RangeTblEntry *rte, List *tlist, int *modified, int sublevels_up)
{ {
...@@ -1790,10 +1545,8 @@ apply_RIR_view(Node **nodePtr, int rt_index, RangeTblEntry *rte, List *tlist, in ...@@ -1790,10 +1545,8 @@ apply_RIR_view(Node **nodePtr, int rt_index, RangeTblEntry *rte, List *tlist, in
} }
exp = copyObject(exp); exp = copyObject(exp);
if (var->varlevelsup > 0 && if (var->varlevelsup > 0)
nodeTag(exp) == T_Var) { apply_RIR_adjust_sublevel(exp, var->varlevelsup);
((Var *)exp)->varlevelsup = var->varlevelsup;
}
*nodePtr = exp; *nodePtr = exp;
*modified = TRUE; *modified = TRUE;
} }
...@@ -1885,8 +1638,6 @@ apply_RIR_view(Node **nodePtr, int rt_index, RangeTblEntry *rte, List *tlist, in ...@@ -1885,8 +1638,6 @@ apply_RIR_view(Node **nodePtr, int rt_index, RangeTblEntry *rte, List *tlist, in
elog(NOTICE, "unknown node tag %d in apply_RIR_view()", nodeTag(node)); elog(NOTICE, "unknown node tag %d in apply_RIR_view()", nodeTag(node));
elog(NOTICE, "Node is: %s", nodeToString(node)); elog(NOTICE, "Node is: %s", nodeToString(node));
break; break;
} }
} }
...@@ -1938,12 +1689,12 @@ ApplyRetrieveRule(Query *parsetree, ...@@ -1938,12 +1689,12 @@ ApplyRetrieveRule(Query *parsetree,
parsetree->rtable = rtable; parsetree->rtable = rtable;
rule_action->rtable = rtable; rule_action->rtable = rtable;
offset_varnodes((Node *) rule_qual, rt_length, 0); OffsetVarNodes((Node *) rule_qual, rt_length, 0);
offset_varnodes((Node *) rule_action, rt_length, 0); OffsetVarNodes((Node *) rule_action, rt_length, 0);
change_varnodes((Node *) rule_qual, ChangeVarNodes((Node *) rule_qual,
PRS2_CURRENT_VARNO + rt_length, rt_index, 0); PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
change_varnodes((Node *) rule_action, ChangeVarNodes((Node *) rule_action,
PRS2_CURRENT_VARNO + rt_length, rt_index, 0); PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
if (relation_level) if (relation_level)
...@@ -2246,7 +1997,7 @@ CopyAndAddQual(Query *parsetree, ...@@ -2246,7 +1997,7 @@ CopyAndAddQual(Query *parsetree,
rt_length = length(rtable); rt_length = length(rtable);
rtable = append(rtable, listCopy(rule_action->rtable)); rtable = append(rtable, listCopy(rule_action->rtable));
new_tree->rtable = rtable; new_tree->rtable = rtable;
OffsetVarNodes(new_qual, rt_length); OffsetVarNodes(new_qual, rt_length, 0);
ChangeVarNodes(new_qual, PRS2_CURRENT_VARNO + rt_length, rt_index, 0); ChangeVarNodes(new_qual, PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
} }
/* XXX -- where current doesn't work for instead nothing.... yet */ /* XXX -- where current doesn't work for instead nothing.... yet */
...@@ -2385,6 +2136,28 @@ fireRules(Query *parsetree, ...@@ -2385,6 +2136,28 @@ fireRules(Query *parsetree,
if (rule_action->commandType == CMD_NOTHING) if (rule_action->commandType == CMD_NOTHING)
continue; continue;
/*--------------------------------------------------
* We copy the qualifications of the parsetree
* to the action and vice versa. So force
* hasSubLinks if one of them has it.
*
* As of 6.4 only parsetree qualifications can
* have sublinks. If this changes, we must make
* this a node lookup at the end of rewriting.
*
* Jan
*--------------------------------------------------
*/
if (parsetree->hasSubLinks && !rule_action->hasSubLinks)
{
rule_action = copyObject(rule_action);
rule_action->hasSubLinks = TRUE;
}
if (!parsetree->hasSubLinks && rule_action->hasSubLinks)
{
parsetree->hasSubLinks = TRUE;
}
/*-------------------------------------------------- /*--------------------------------------------------
* Step 1: * Step 1:
* Rewrite current.attribute or current to tuple variable * Rewrite current.attribute or current to tuple variable
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.21 1998/10/20 17:21:44 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.22 1998/10/21 16:21:26 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -32,222 +32,362 @@ static void ResolveNew(RewriteInfo *info, List *targetlist, ...@@ -32,222 +32,362 @@ static void ResolveNew(RewriteInfo *info, List *targetlist,
Node **node, int sublevels_up); Node **node, int sublevels_up);
/*
* OffsetVarnodes -
*/
void void
OffsetVarNodes(Node *node, int offset) OffsetVarNodes(Node *node, int offset, int sublevels_up)
{ {
if (node == NULL) if (node == NULL)
return; return;
switch (nodeTag(node))
{ switch(nodeTag(node)) {
case T_TargetEntry: case T_TargetEntry:
{ {
TargetEntry *tle = (TargetEntry *) node; TargetEntry *tle = (TargetEntry *)node;
OffsetVarNodes(tle->expr, offset); OffsetVarNodes(
(Node *)(tle->expr),
offset,
sublevels_up);
} }
break; break;
case T_Aggreg: case T_Aggreg:
{ {
Aggreg *agg = (Aggreg *) node; Aggreg *agg = (Aggreg *)node;
OffsetVarNodes(agg->target, offset); OffsetVarNodes(
(Node *)(agg->target),
offset,
sublevels_up);
} }
break; break;
/*
* This has to be done to make queries using groupclauses work
* on views
*/
case T_GroupClause: case T_GroupClause:
{ {
GroupClause *group = (GroupClause *) node; GroupClause *grp = (GroupClause *)node;
OffsetVarNodes((Node *) (group->entry), offset); OffsetVarNodes(
(Node *)(grp->entry),
offset,
sublevels_up);
} }
break; break;
case T_Expr: case T_Expr:
{ {
Expr *expr = (Expr *) node; Expr *exp = (Expr *)node;
OffsetVarNodes((Node *) expr->args, offset); OffsetVarNodes(
(Node *)(exp->args),
offset,
sublevels_up);
} }
break; break;
case T_Iter: case T_Iter:
{ {
Iter *iter = (Iter *) node; Iter *iter = (Iter *)node;
OffsetVarNodes((Node *) iter->iterexpr, offset); OffsetVarNodes(
(Node *)(iter->iterexpr),
offset,
sublevels_up);
} }
break; break;
case T_ArrayRef: case T_ArrayRef:
{ {
ArrayRef *ref = (ArrayRef *) node; ArrayRef *ref = (ArrayRef *)node;
OffsetVarNodes((Node *) ref->refupperindexpr, offset); OffsetVarNodes(
OffsetVarNodes((Node *) ref->reflowerindexpr, offset); (Node *)(ref->refupperindexpr),
OffsetVarNodes((Node *) ref->refexpr, offset); offset,
OffsetVarNodes((Node *) ref->refassgnexpr, offset); sublevels_up);
OffsetVarNodes(
(Node *)(ref->reflowerindexpr),
offset,
sublevels_up);
OffsetVarNodes(
(Node *)(ref->refexpr),
offset,
sublevels_up);
OffsetVarNodes(
(Node *)(ref->refassgnexpr),
offset,
sublevels_up);
} }
break; break;
case T_Var: case T_Var:
{ {
Var *var = (Var *) node; Var *var = (Var *)node;
if (var->varlevelsup == sublevels_up) {
var->varno += offset; var->varno += offset;
var->varnoold += offset; var->varnoold += offset;
} }
}
break;
case T_Param:
break;
case T_Const:
break; break;
case T_List: case T_List:
{ {
List *l; List *l;
foreach(l, (List *) node) foreach (l, (List *)node)
OffsetVarNodes(lfirst(l), offset); OffsetVarNodes(
(Node *)lfirst(l),
offset,
sublevels_up);
} }
break; break;
case T_SubLink: case T_SubLink:
{ {
SubLink *sublink = (SubLink *) node; SubLink *sub = (SubLink *)node;
/* OffsetVarNodes(
* We also have to adapt the variables used in (Node *)(sub->lefthand),
* sublink->lefthand and sublink->oper offset,
*/ sublevels_up);
OffsetVarNodes((Node *) (sublink->lefthand), offset);
/* OffsetVarNodes(
* Make sure the first argument of sublink->oper points to (Node *)(sub->subselect),
* the same var as sublink->lefthand does otherwise we offset,
* will run into troubles using aggregates (aggno will not sublevels_up + 1);
* be set correctly)
*/
lfirst(((Expr *) lfirst(sublink->oper))->args) =
lfirst(sublink->lefthand);
} }
break; break;
case T_Query:
{
Query *qry = (Query *)node;
OffsetVarNodes(
(Node *)(qry->targetList),
offset,
sublevels_up);
OffsetVarNodes(
(Node *)(qry->qual),
offset,
sublevels_up);
OffsetVarNodes(
(Node *)(qry->havingQual),
offset,
sublevels_up);
OffsetVarNodes(
(Node *)(qry->groupClause),
offset,
sublevels_up);
}
break;
default: default:
/* ignore the others */ elog(NOTICE, "unknown node tag %d in OffsetVarNodes()", nodeTag(node));
elog(NOTICE, "Node is: %s", nodeToString(node));
break; break;
} }
} }
/*
* ChangeVarNodes -
*/
void void
ChangeVarNodes(Node *node, int old_varno, int new_varno, int sublevels_up) ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
{ {
if (node == NULL) if (node == NULL)
return; return;
switch (nodeTag(node))
{ switch(nodeTag(node)) {
case T_TargetEntry: case T_TargetEntry:
{ {
TargetEntry *tle = (TargetEntry *) node; TargetEntry *tle = (TargetEntry *)node;
ChangeVarNodes(tle->expr, old_varno, new_varno, sublevels_up); ChangeVarNodes(
(Node *)(tle->expr),
rt_index,
new_index,
sublevels_up);
} }
break; break;
case T_Aggreg: case T_Aggreg:
{ {
Aggreg *agg = (Aggreg *) node; Aggreg *agg = (Aggreg *)node;
ChangeVarNodes(agg->target, old_varno, new_varno, sublevels_up); ChangeVarNodes(
(Node *)(agg->target),
rt_index,
new_index,
sublevels_up);
} }
break; break;
/*
* This has to be done to make queries using groupclauses work
* on views
*/
case T_GroupClause: case T_GroupClause:
{ {
GroupClause *group = (GroupClause *) node; GroupClause *grp = (GroupClause *)node;
ChangeVarNodes((Node *) (group->entry), old_varno, new_varno, ChangeVarNodes(
(Node *)(grp->entry),
rt_index,
new_index,
sublevels_up); sublevels_up);
} }
break; break;
case T_Expr: case T_Expr:
{ {
Expr *expr = (Expr *) node; Expr *exp = (Expr *)node;
ChangeVarNodes((Node *) expr->args, old_varno, new_varno, sublevels_up); ChangeVarNodes(
(Node *)(exp->args),
rt_index,
new_index,
sublevels_up);
} }
break; break;
case T_Iter: case T_Iter:
{ {
Iter *iter = (Iter *) node; Iter *iter = (Iter *)node;
ChangeVarNodes((Node *) iter->iterexpr, old_varno, new_varno, sublevels_up); ChangeVarNodes(
(Node *)(iter->iterexpr),
rt_index,
new_index,
sublevels_up);
} }
break; break;
case T_ArrayRef: case T_ArrayRef:
{ {
ArrayRef *ref = (ArrayRef *) node; ArrayRef *ref = (ArrayRef *)node;
ChangeVarNodes((Node *) ref->refupperindexpr, old_varno, new_varno, sublevels_up); ChangeVarNodes(
ChangeVarNodes((Node *) ref->reflowerindexpr, old_varno, new_varno, sublevels_up); (Node *)(ref->refupperindexpr),
ChangeVarNodes((Node *) ref->refexpr, old_varno, new_varno, sublevels_up); rt_index,
ChangeVarNodes((Node *) ref->refassgnexpr, old_varno, new_varno, sublevels_up); new_index,
sublevels_up);
ChangeVarNodes(
(Node *)(ref->reflowerindexpr),
rt_index,
new_index,
sublevels_up);
ChangeVarNodes(
(Node *)(ref->refexpr),
rt_index,
new_index,
sublevels_up);
ChangeVarNodes(
(Node *)(ref->refassgnexpr),
rt_index,
new_index,
sublevels_up);
} }
break; break;
case T_Var: case T_Var:
{ {
Var *var = (Var *) node; Var *var = (Var *)node;
if (var->varno == old_varno && if (var->varlevelsup == sublevels_up &&
var->varlevelsup == sublevels_up) var->varno == rt_index) {
{ var->varno = new_index;
var->varno = new_varno; var->varnoold = new_index;
var->varnoold = new_varno;
} }
if (var->varlevelsup > 0)
OffsetVarNodes((Node *) var, 3);
} }
break; break;
case T_Param:
break;
case T_Const:
break;
case T_List: case T_List:
{ {
List *l; List *l;
foreach(l, (List *) node) foreach (l, (List *)node)
ChangeVarNodes(lfirst(l), old_varno, new_varno, sublevels_up); ChangeVarNodes(
(Node *)lfirst(l),
rt_index,
new_index,
sublevels_up);
} }
break; break;
case T_SubLink: case T_SubLink:
{ {
SubLink *sublink = (SubLink *) node; SubLink *sub = (SubLink *)node;
Query *query = (Query *) sublink->subselect;
ChangeVarNodes(
(Node *)(sub->lefthand),
rt_index,
new_index,
sublevels_up);
ChangeVarNodes((Node *) query->qual, old_varno, new_varno, ChangeVarNodes(
(Node *)(sub->subselect),
rt_index,
new_index,
sublevels_up + 1); sublevels_up + 1);
}
break;
/* case T_Query:
* We also have to adapt the variables used in {
* sublink->lefthand and sublink->oper Query *qry = (Query *)node;
*/
ChangeVarNodes((Node *) (sublink->lefthand), old_varno, new_varno, ChangeVarNodes(
(Node *)(qry->targetList),
rt_index,
new_index,
sublevels_up); sublevels_up);
/* ChangeVarNodes(
* Make sure the first argument of sublink->oper points to (Node *)(qry->qual),
* the same var as sublink->lefthand does otherwise we rt_index,
* will run into troubles using aggregates (aggno will not new_index,
* be set correctly sublevels_up);
*/
/* ChangeVarNodes(
* lfirst(((Expr *) lfirst(sublink->oper))->args) = (Node *)(qry->havingQual),
* lfirst(sublink->lefthand); rt_index,
*/ new_index,
sublevels_up);
ChangeVarNodes(
(Node *)(qry->groupClause),
rt_index,
new_index,
sublevels_up);
} }
break; break;
default: default:
/* ignore the others */ elog(NOTICE, "unknown node tag %d in ChangeVarNodes()", nodeTag(node));
elog(NOTICE, "Node is: %s", nodeToString(node));
break; break;
} }
} }
void void
AddQual(Query *parsetree, Node *qual) AddQual(Query *parsetree, Node *qual)
{ {
......
...@@ -6,7 +6,7 @@ ...@@ -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.10 1998/10/08 18:30:41 momjian Exp $ * $Id: rewriteManip.h,v 1.11 1998/10/21 16:21:29 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include "rewrite/rewriteHandler.h" #include "rewrite/rewriteHandler.h"
/* RewriteManip.c */ /* RewriteManip.c */
void OffsetVarNodes(Node *node, int offset); void OffsetVarNodes(Node *node, int offset, int sublevels_up);
void ChangeVarNodes(Node *node, int old_varno, int new_varno, void ChangeVarNodes(Node *node, int old_varno, int new_varno,
int sublevels_up); int sublevels_up);
void AddQual(Query *parsetree, Node *qual); void AddQual(Query *parsetree, Node *qual);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment