aboutsummaryrefslogtreecommitdiff
path: root/src/backend/rewrite/rewriteManip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/rewrite/rewriteManip.c')
-rw-r--r--src/backend/rewrite/rewriteManip.c1212
1 files changed, 395 insertions, 817 deletions
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index 16b31eae84d..3f9b4da2698 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.40 1999/08/25 23:21:43 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.41 1999/10/01 04:08:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,410 +19,182 @@
#include "utils/builtins.h"
#include "utils/lsyscache.h"
-static void ResolveNew(RewriteInfo *info, List *targetlist,
- Node **node, int sublevels_up);
+/* macros borrowed from expression_tree_mutator */
-/*
- * OffsetVarnodes -
- */
-void
-OffsetVarNodes(Node *node, int offset, int sublevels_up)
-{
- if (node == NULL)
- return;
-
- switch (nodeTag(node))
- {
- case T_TargetEntry:
- {
- TargetEntry *tle = (TargetEntry *) node;
-
- OffsetVarNodes(
- (Node *) (tle->expr),
- offset,
- sublevels_up);
- }
- break;
-
- case T_Aggref:
- {
- Aggref *aggref = (Aggref *) node;
-
- OffsetVarNodes(
- (Node *) (aggref->target),
- offset,
- sublevels_up);
- }
- break;
-
- case T_GroupClause:
- break;
-
- case T_Expr:
- {
- Expr *exp = (Expr *) node;
-
- OffsetVarNodes(
- (Node *) (exp->args),
- offset,
- sublevels_up);
- }
- break;
-
- case T_Iter:
- {
- Iter *iter = (Iter *) node;
-
- OffsetVarNodes(
- (Node *) (iter->iterexpr),
- offset,
- sublevels_up);
- }
- break;
-
- case T_ArrayRef:
- {
- ArrayRef *ref = (ArrayRef *) node;
-
- OffsetVarNodes(
- (Node *) (ref->refupperindexpr),
- 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;
-
- 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;
+#define FLATCOPY(newnode, node, nodetype) \
+ ( (newnode) = makeNode(nodetype), \
+ memcpy((newnode), (node), sizeof(nodetype)) )
- case T_List:
- {
- List *l;
-
- foreach(l, (List *) node)
- OffsetVarNodes(
- (Node *) lfirst(l),
- offset,
- sublevels_up);
- }
- break;
-
- case T_SubLink:
- {
- SubLink *sub = (SubLink *) node;
-
- OffsetVarNodes(
- (Node *) (sub->lefthand),
- offset,
- sublevels_up);
-
- OffsetVarNodes(
- (Node *) (sub->subselect),
- offset,
- sublevels_up + 1);
- }
- 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);
- }
- break;
-
- case T_CaseExpr:
- {
- CaseExpr *exp = (CaseExpr *) node;
-
- OffsetVarNodes(
- (Node *) (exp->args),
- offset,
- sublevels_up);
-
- OffsetVarNodes(
- (Node *) (exp->defresult),
- offset,
- sublevels_up);
- }
- break;
-
- case T_CaseWhen:
- {
- CaseWhen *exp = (CaseWhen *) node;
+#define MUTATE(newfield, oldfield, fieldtype, mutator, context) \
+ ( (newfield) = (fieldtype) mutator((Node *) (oldfield), (context)) )
- OffsetVarNodes(
- (Node *) (exp->expr),
- offset,
- sublevels_up);
- OffsetVarNodes(
- (Node *) (exp->result),
- offset,
- sublevels_up);
- }
- break;
+/*
+ * OffsetVarNodes - adjust Vars when appending one query's RT to another
+ *
+ * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
+ * and increment their varno fields (rangetable indexes) by 'offset'.
+ * The varnoold fields are adjusted similarly.
+ *
+ * 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!
+ */
- default:
- elog(NOTICE, "unknown node tag %d in OffsetVarNodes()", nodeTag(node));
- elog(NOTICE, "Node is: %s", nodeToString(node));
- break;
+typedef struct {
+ int offset;
+ int sublevels_up;
+} OffsetVarNodes_context;
+static bool
+OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
+{
+ if (node == NULL)
+ return false;
+ if (IsA(node, Var))
+ {
+ Var *var = (Var *) node;
+ if (var->varlevelsup == context->sublevels_up)
+ {
+ var->varno += context->offset;
+ var->varnoold += context->offset;
+ }
+ 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 (OffsetVarNodes_walker((Node *) (sub->lefthand),
+ context))
+ return true;
+ OffsetVarNodes((Node *) (sub->subselect),
+ context->offset,
+ context->sublevels_up + 1);
+ return false;
+ }
+ if (IsA(node, Query))
+ {
+ /* Reach here after recursing down into subselect above... */
+ Query *qry = (Query *) node;
+
+ if (OffsetVarNodes_walker((Node *) (qry->targetList),
+ context))
+ return true;
+ if (OffsetVarNodes_walker((Node *) (qry->qual),
+ context))
+ return true;
+ if (OffsetVarNodes_walker((Node *) (qry->havingQual),
+ context))
+ return true;
+ return false;
+ }
+ return expression_tree_walker(node, OffsetVarNodes_walker,
+ (void *) context);
}
-
-/*
- * ChangeVarNodes -
- */
void
-ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
+OffsetVarNodes(Node *node, int offset, int sublevels_up)
{
- if (node == NULL)
- return;
-
- switch (nodeTag(node))
- {
- case T_TargetEntry:
- {
- TargetEntry *tle = (TargetEntry *) node;
-
- ChangeVarNodes(
- (Node *) (tle->expr),
- rt_index,
- new_index,
- sublevels_up);
- }
- break;
-
- case T_Aggref:
- {
- Aggref *aggref = (Aggref *) node;
-
- ChangeVarNodes(
- (Node *) (aggref->target),
- rt_index,
- new_index,
- sublevels_up);
- }
- break;
-
- case T_GroupClause:
- break;
-
- case T_Expr:
- {
- Expr *exp = (Expr *) node;
-
- ChangeVarNodes(
- (Node *) (exp->args),
- rt_index,
- new_index,
- sublevels_up);
- }
- break;
-
- case T_Iter:
- {
- Iter *iter = (Iter *) node;
-
- ChangeVarNodes(
- (Node *) (iter->iterexpr),
- rt_index,
- new_index,
- sublevels_up);
- }
- break;
-
- case T_ArrayRef:
- {
- ArrayRef *ref = (ArrayRef *) node;
-
- ChangeVarNodes(
- (Node *) (ref->refupperindexpr),
- rt_index,
- 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;
-
- 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)
- ChangeVarNodes(
- (Node *) lfirst(l),
- rt_index,
- new_index,
- sublevels_up);
- }
- break;
+ OffsetVarNodes_context context;
- case T_SubLink:
- {
- SubLink *sub = (SubLink *) node;
-
- ChangeVarNodes(
- (Node *) (sub->lefthand),
- rt_index,
- new_index,
- sublevels_up);
-
- ChangeVarNodes(
- (Node *) (sub->subselect),
- rt_index,
- new_index,
- sublevels_up + 1);
- }
- break;
-
- case T_Query:
- {
- Query *qry = (Query *) node;
-
- ChangeVarNodes(
- (Node *) (qry->targetList),
- rt_index,
- new_index,
- sublevels_up);
-
- ChangeVarNodes(
- (Node *) (qry->qual),
- rt_index,
- new_index,
- sublevels_up);
-
- ChangeVarNodes(
- (Node *) (qry->havingQual),
- rt_index,
- new_index,
- sublevels_up);
- }
- break;
-
- case T_CaseExpr:
- {
- CaseExpr *exp = (CaseExpr *) node;
-
- ChangeVarNodes(
- (Node *) (exp->args),
- rt_index,
- new_index,
- sublevels_up);
-
- ChangeVarNodes(
- (Node *) (exp->defresult),
- rt_index,
- new_index,
- sublevels_up);
- }
- break;
+ context.offset = offset;
+ context.sublevels_up = sublevels_up;
+ OffsetVarNodes_walker(node, &context);
+}
- case T_CaseWhen:
- {
- CaseWhen *exp = (CaseWhen *) node;
-
- ChangeVarNodes(
- (Node *) (exp->expr),
- rt_index,
- new_index,
- sublevels_up);
-
- ChangeVarNodes(
- (Node *) (exp->result),
- rt_index,
- new_index,
- sublevels_up);
- }
- break;
+/*
+ * ChangeVarNodes - adjust Var nodes for a specific change of RT index
+ *
+ * Find all Var nodes in the given tree belonging to a specific relation
+ * (identified by sublevels_up and rt_index), and change their varno fields
+ * to 'new_index'. The varnoold fields are changed too.
+ *
+ * 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!
+ */
- default:
- elog(NOTICE, "unknown node tag %d in ChangeVarNodes()", nodeTag(node));
- elog(NOTICE, "Node is: %s", nodeToString(node));
- break;
+typedef struct {
+ int rt_index;
+ int new_index;
+ int sublevels_up;
+} ChangeVarNodes_context;
+static bool
+ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
+{
+ if (node == NULL)
+ return false;
+ if (IsA(node, Var))
+ {
+ Var *var = (Var *) node;
+ if (var->varlevelsup == context->sublevels_up &&
+ var->varno == context->rt_index)
+ {
+ var->varno = context->new_index;
+ var->varnoold = context->new_index;
+ }
+ 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 (ChangeVarNodes_walker((Node *) (sub->lefthand),
+ context))
+ return true;
+ ChangeVarNodes((Node *) (sub->subselect),
+ context->rt_index,
+ context->new_index,
+ context->sublevels_up + 1);
+ return false;
}
+ if (IsA(node, Query))
+ {
+ /* Reach here after recursing down into subselect above... */
+ Query *qry = (Query *) node;
+
+ if (ChangeVarNodes_walker((Node *) (qry->targetList),
+ context))
+ return true;
+ if (ChangeVarNodes_walker((Node *) (qry->qual),
+ context))
+ return true;
+ if (ChangeVarNodes_walker((Node *) (qry->havingQual),
+ context))
+ return true;
+ return false;
+ }
+ return expression_tree_walker(node, ChangeVarNodes_walker,
+ (void *) context);
}
+void
+ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
+{
+ ChangeVarNodes_context context;
+ context.rt_index = rt_index;
+ context.new_index = new_index;
+ context.sublevels_up = sublevels_up;
+ ChangeVarNodes_walker(node, &context);
+}
+/*
+ * Add the given qualifier condition to the query's WHERE clause
+ */
void
AddQual(Query *parsetree, Node *qual)
{
@@ -433,18 +205,19 @@ AddQual(Query *parsetree, Node *qual)
return;
/* INTERSECT want's the original, but we need to copy - Jan */
- /* copy = qual; */
copy = copyObject(qual);
old = parsetree->qual;
if (old == NULL)
parsetree->qual = copy;
else
- parsetree->qual = (Node *) make_andclause(makeList(parsetree->qual, copy, -1));
+ parsetree->qual = (Node *) make_andclause(makeList(old, copy, -1));
}
-/* Adds the given havingQual to the one already contained in the parsetree just as
- * AddQual does for the normal 'where' qual */
+/*
+ * Add the given havingQual to the one already contained in the parsetree
+ * just as AddQual does for the normal 'where' qual
+ */
void
AddHavingQual(Query *parsetree, Node *havingQual)
{
@@ -455,46 +228,43 @@ AddHavingQual(Query *parsetree, Node *havingQual)
return;
/* INTERSECT want's the original, but we need to copy - Jan */
- /* copy = havingQual; */
copy = copyObject(havingQual);
old = parsetree->havingQual;
if (old == NULL)
parsetree->havingQual = copy;
else
- parsetree->havingQual = (Node *) make_andclause(makeList(parsetree->havingQual, copy, -1));
+ parsetree->havingQual = (Node *) make_andclause(makeList(old, copy, -1));
}
#ifdef NOT_USED
void
AddNotHavingQual(Query *parsetree, Node *havingQual)
{
- Node *copy;
+ Node *notqual;
if (havingQual == NULL)
return;
- /* INTERSECT want's the original, but we need to copy - Jan */
- /* copy = (Node *) make_notclause((Expr *)havingQual); */
- copy = (Node *) make_notclause((Expr *) copyObject(havingQual));
+ /* Need not copy input qual, because AddHavingQual will... */
+ notqual = (Node *) make_notclause((Expr *) havingQual);
- AddHavingQual(parsetree, copy);
+ AddHavingQual(parsetree, notqual);
}
#endif
void
AddNotQual(Query *parsetree, Node *qual)
{
- Node *copy;
+ Node *notqual;
if (qual == NULL)
return;
- /* INTERSECT want's the original, but we need to copy - Jan */
- /* copy = (Node *) make_notclause((Expr *)qual); */
- copy = (Node *) make_notclause((Expr *) copyObject(qual));
+ /* Need not copy input qual, because AddQual will... */
+ notqual = (Node *) make_notclause((Expr *) qual);
- AddQual(parsetree, copy);
+ AddQual(parsetree, notqual);
}
@@ -583,6 +353,7 @@ FixResdomTypes(List *tlist)
#endif
+/* Find a targetlist entry by resno */
static Node *
FindMatchingNew(List *tlist, int attno)
{
@@ -598,6 +369,7 @@ FindMatchingNew(List *tlist, int attno)
return NULL;
}
+/* Find a targetlist entry by resname */
static Node *
FindMatchingTLEntry(List *tlist, char *e_attname)
{
@@ -615,464 +387,270 @@ FindMatchingTLEntry(List *tlist, char *e_attname)
return NULL;
}
-static void
-ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr,
- int sublevels_up)
-{
- Node *node = *nodePtr;
-
- if (node == NULL)
- return;
-
- switch (nodeTag(node))
- {
- case T_TargetEntry:
- ResolveNew(info, targetlist, &((TargetEntry *) node)->expr,
- sublevels_up);
- break;
- case T_Aggref:
- ResolveNew(info, targetlist, &((Aggref *) node)->target,
- sublevels_up);
- break;
- case T_Expr:
- ResolveNew(info, targetlist, (Node **) (&(((Expr *) node)->args)),
- sublevels_up);
- break;
- case T_Iter:
- ResolveNew(info, targetlist, (Node **) (&(((Iter *) node)->iterexpr)),
- sublevels_up);
- break;
- case T_ArrayRef:
- ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refupperindexpr)),
- sublevels_up);
- ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->reflowerindexpr)),
- sublevels_up);
- ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refexpr)),
- sublevels_up);
- ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refassgnexpr)),
- sublevels_up);
- break;
- case T_Var:
- {
- int this_varno = (int) ((Var *) node)->varno;
- int this_varlevelsup = (int) ((Var *) node)->varlevelsup;
- Node *n;
-
- if (this_varno == info->new_varno &&
- this_varlevelsup == sublevels_up)
- {
- n = FindMatchingNew(targetlist,
- ((Var *) node)->varattno);
- if (n == NULL)
- {
- if (info->event == CMD_UPDATE)
- {
- *nodePtr = n = copyObject(node);
- ((Var *) n)->varno = info->current_varno;
- ((Var *) n)->varnoold = info->current_varno;
- }
- else
- *nodePtr = make_null(((Var *) node)->vartype);
- }
- else
- {
- *nodePtr = copyObject(n);
- ((Var *) *nodePtr)->varlevelsup = this_varlevelsup;
- }
- }
- break;
- }
- case T_List:
- {
- List *l;
-
- foreach(l, (List *) node)
- ResolveNew(info, targetlist, (Node **) &(lfirst(l)),
- sublevels_up);
- break;
- }
- case T_SubLink:
- {
- SubLink *sublink = (SubLink *) node;
- Query *query = (Query *) sublink->subselect;
- /* XXX what about lefthand? What about rest of subquery? */
- ResolveNew(info, targetlist, (Node **) &(query->qual), sublevels_up + 1);
- }
- break;
- case T_GroupClause:
- break;
- default:
- /* ignore the others */
- break;
- }
-}
+/*
+ * ResolveNew - replace Vars with corresponding items from a targetlist
+ *
+ * Vars matching info->new_varno and sublevels_up are replaced by the
+ * entry with matching resno from targetlist, if there is one.
+ */
-void
-FixNew(RewriteInfo *info, Query *parsetree)
-{
- ResolveNew(info, parsetree->targetList,
- (Node **) &(info->rule_action->targetList), 0);
- ResolveNew(info, parsetree->targetList,
- (Node **) &info->rule_action->qual, 0);
- ResolveNew(info, parsetree->targetList,
- (Node **) &(info->rule_action->groupClause), 0);
-}
+typedef struct {
+ RewriteInfo *info;
+ List *targetlist;
+ int sublevels_up;
+} ResolveNew_context;
-static void
-nodeHandleRIRAttributeRule(Node **nodePtr,
- List *rtable,
- List *targetlist,
- int rt_index,
- int attr_num,
- int *modified,
- int *badsql,
- int sublevels_up)
+static Node *
+ResolveNew_mutator(Node *node, ResolveNew_context *context)
{
- Node *node = *nodePtr;
-
if (node == NULL)
- return;
- switch (nodeTag(node))
+ return NULL;
+ if (IsA(node, Var))
{
- case T_TargetEntry:
- {
- TargetEntry *tle = (TargetEntry *) node;
-
- nodeHandleRIRAttributeRule(&tle->expr, rtable, targetlist,
- rt_index, attr_num, modified, badsql,
- sublevels_up);
- }
- break;
- case T_Aggref:
- {
- Aggref *aggref = (Aggref *) node;
+ Var *var = (Var *) node;
+ int this_varno = (int) var->varno;
+ int this_varlevelsup = (int) var->varlevelsup;
- nodeHandleRIRAttributeRule(&aggref->target, rtable, targetlist,
- rt_index, attr_num, modified, badsql,
- sublevels_up);
- }
- break;
- case T_Expr:
- {
- Expr *expr = (Expr *) node;
-
- nodeHandleRIRAttributeRule((Node **) (&(expr->args)), rtable,
- targetlist, rt_index, attr_num,
- modified, badsql,
- sublevels_up);
- }
- break;
- case T_Iter:
- {
- Iter *iter = (Iter *) node;
+ if (this_varno == context->info->new_varno &&
+ this_varlevelsup == context->sublevels_up)
+ {
+ Node *n = FindMatchingNew(context->targetlist,
+ var->varattno);
- nodeHandleRIRAttributeRule((Node **) (&(iter->iterexpr)), rtable,
- targetlist, rt_index, attr_num,
- modified, badsql,
- sublevels_up);
- }
- break;
- case T_ArrayRef:
- {
- ArrayRef *ref = (ArrayRef *) node;
-
- nodeHandleRIRAttributeRule((Node **) (&(ref->refupperindexpr)), rtable,
- targetlist, rt_index, attr_num,
- modified, badsql,
- sublevels_up);
- nodeHandleRIRAttributeRule((Node **) (&(ref->reflowerindexpr)), rtable,
- targetlist, rt_index, attr_num,
- modified, badsql,
- sublevels_up);
- nodeHandleRIRAttributeRule((Node **) (&(ref->refexpr)), rtable,
- targetlist, rt_index, attr_num,
- modified, badsql,
- sublevels_up);
- nodeHandleRIRAttributeRule((Node **) (&(ref->refassgnexpr)), rtable,
- targetlist, rt_index, attr_num,
- modified, badsql,
- sublevels_up);
- }
- break;
- case T_Var:
+ if (n == NULL)
{
- int this_varno = ((Var *) node)->varno;
- int this_varattno = ((Var *) node)->varattno;
- int this_varlevelsup = ((Var *) node)->varlevelsup;
-
- if (this_varno == rt_index &&
- this_varattno == attr_num &&
- this_varlevelsup == sublevels_up)
+ if (context->info->event == CMD_UPDATE)
{
- if (((Var *) node)->vartype == 32)
- { /* HACK */
- *nodePtr = make_null(((Var *) node)->vartype);
- *modified = TRUE;
- *badsql = TRUE;
- break;
- }
- else
- {
- NameData name_to_look_for;
-
- name_to_look_for.data[0] = '\0';
- namestrcpy(&name_to_look_for,
- (char *) get_attname(getrelid(this_varno,
- rtable),
- attr_num));
- if (name_to_look_for.data[0])
- {
- Node *n;
-
- n = FindMatchingTLEntry(targetlist, (char *) &name_to_look_for);
- if (n == NULL)
- *nodePtr = make_null(((Var *) node)->vartype);
- else
- *nodePtr = n;
- *modified = TRUE;
- }
- }
+ /* 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;
+ }
+ else
+ {
+ /* Otherwise replace unmatched var with a null */
+ return make_null(var->vartype);
}
}
- break;
- case T_List:
+ else
{
- List *i;
-
- foreach(i, (List *) node)
+ /* Make a copy of the tlist item to return */
+ n = copyObject(n);
+ if (IsA(n, Var))
{
- nodeHandleRIRAttributeRule((Node **) (&(lfirst(i))), rtable,
- targetlist, rt_index, attr_num,
- modified, badsql, sublevels_up);
+ ((Var *) n)->varlevelsup = this_varlevelsup;
}
+ /* XXX what to do if tlist item is NOT a var?
+ * Should we be using something like apply_RIR_adjust_sublevel?
+ */
+ return n;
}
- break;
- case T_SubLink:
- {
- SubLink *sublink = (SubLink *) node;
- Query *query = (Query *) sublink->subselect;
+ }
+ /* 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 *,
+ ResolveNew_mutator, context);
+ context->sublevels_up++;
+ MUTATE(newnode->subselect, sublink->subselect, Node *,
+ ResolveNew_mutator, context);
+ context->sublevels_up--;
+ return (Node *) newnode;
+ }
+ if (IsA(node, Query))
+ {
+ Query *query = (Query *) node;
+ Query *newnode;
- /* XXX what about lefthand? What about rest of subquery? */
- nodeHandleRIRAttributeRule((Node **) &(query->qual), rtable, targetlist,
- rt_index, attr_num, modified, badsql,
- sublevels_up + 1);
- }
- break;
- default:
- /* ignore the others */
- break;
+ /*
+ * XXX original code for ResolveNew only recursed into qual field
+ * of subquery. I'm assuming that was an oversight ... tgl 9/99
+ */
+
+ FLATCOPY(newnode, query, Query);
+ MUTATE(newnode->targetList, query->targetList, List *,
+ ResolveNew_mutator, context);
+ MUTATE(newnode->qual, query->qual, Node *,
+ ResolveNew_mutator, context);
+ MUTATE(newnode->havingQual, query->havingQual, Node *,
+ 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)
+{
+ ResolveNew_context context;
+
+ context.info = info;
+ context.targetlist = targetlist;
+ context.sublevels_up = sublevels_up;
+
+ return ResolveNew_mutator(node, &context);
+}
+
+void
+FixNew(RewriteInfo *info, Query *parsetree)
+{
+ 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);
+ /* XXX original code didn't fix havingQual; presumably an oversight? */
+ info->rule_action->havingQual = ResolveNew(info->rule_action->havingQual,
+ info, parsetree->targetList, 0);
}
/*
+ * 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()?
*/
-void
-HandleRIRAttributeRule(Query *parsetree,
- List *rtable,
- List *targetlist,
- int rt_index,
- int attr_num,
- int *modified,
- int *badsql)
-{
- nodeHandleRIRAttributeRule((Node **) (&(parsetree->targetList)), rtable,
- targetlist, rt_index, attr_num,
- modified, badsql, 0);
- nodeHandleRIRAttributeRule(&parsetree->qual, rtable, targetlist,
- rt_index, attr_num, modified, badsql, 0);
-}
+typedef struct {
+ List *rtable;
+ List *targetlist;
+ int rt_index;
+ int attr_num;
+ int *modified;
+ int *badsql;
+ int sublevels_up;
+} HandleRIRAttributeRule_context;
-#ifdef NOT_USED
-static void
-nodeHandleViewRule(Node **nodePtr,
- List *rtable,
- List *targetlist,
- int rt_index,
- int *modified,
- int sublevels_up)
+static Node *
+HandleRIRAttributeRule_mutator(Node *node,
+ HandleRIRAttributeRule_context *context)
{
- Node *node = *nodePtr;
-
if (node == NULL)
- return;
-
- switch (nodeTag(node))
+ return NULL;
+ if (IsA(node, Var))
{
- case T_TargetEntry:
- {
- TargetEntry *tle = (TargetEntry *) node;
-
- nodeHandleViewRule(&(tle->expr), rtable, targetlist,
- rt_index, modified, sublevels_up);
- }
- break;
- case T_Aggref:
- {
- Aggref *aggref = (Aggref *) node;
-
- nodeHandleViewRule(&(aggref->target), rtable, targetlist,
- rt_index, modified, sublevels_up);
- }
- break;
-
- /*
- * This has to be done to make queries using groupclauses work
- * on views
- */
- case T_GroupClause:
- {
- GroupClause *group = (GroupClause *) node;
-
- nodeHandleViewRule((Node **) (&(group->entry)), rtable, targetlist,
- rt_index, modified, sublevels_up);
- }
- break;
- case T_Expr:
- {
- Expr *expr = (Expr *) node;
-
- nodeHandleViewRule((Node **) (&(expr->args)),
- rtable, targetlist,
- rt_index, modified, sublevels_up);
- }
- break;
- case T_Iter:
- {
- Iter *iter = (Iter *) node;
-
- nodeHandleViewRule((Node **) (&(iter->iterexpr)),
- rtable, targetlist,
- rt_index, modified, sublevels_up);
- }
- break;
- case T_ArrayRef:
- {
- ArrayRef *ref = (ArrayRef *) node;
-
- nodeHandleViewRule((Node **) (&(ref->refupperindexpr)),
- rtable, targetlist,
- rt_index, modified, sublevels_up);
- nodeHandleViewRule((Node **) (&(ref->reflowerindexpr)),
- rtable, targetlist,
- rt_index, modified, sublevels_up);
- nodeHandleViewRule((Node **) (&(ref->refexpr)),
- rtable, targetlist,
- rt_index, modified, sublevels_up);
- nodeHandleViewRule((Node **) (&(ref->refassgnexpr)),
- rtable, targetlist,
- rt_index, modified, sublevels_up);
- }
- break;
- case T_Var:
- {
- Var *var = (Var *) node;
- int this_varno = var->varno;
- int this_varlevelsup = var->varlevelsup;
- Node *n;
-
- if (this_varno == rt_index &&
- this_varlevelsup == sublevels_up)
+ Var *var = (Var *) node;
+ int this_varno = var->varno;
+ int this_varattno = var->varattno;
+ int this_varlevelsup = var->varlevelsup;
+
+ if (this_varno == context->rt_index &&
+ this_varattno == context->attr_num &&
+ this_varlevelsup == context->sublevels_up)
+ {
+ if (var->vartype == 32)
+ { /* HACK: disallow SET variables */
+ *context->modified = TRUE;
+ *context->badsql = TRUE;
+ return make_null(var->vartype);
+ }
+ else
+ {
+ NameData name_to_look_for;
+
+ name_to_look_for.data[0] = '\0';
+ namestrcpy(&name_to_look_for,
+ (char *) get_attname(getrelid(this_varno,
+ context->rtable),
+ this_varattno));
+ if (name_to_look_for.data[0])
{
- n = FindMatchingTLEntry(targetlist,
- get_attname(getrelid(this_varno,
- rtable),
- var->varattno));
+ Node *n;
+
+ *context->modified = TRUE;
+ n = FindMatchingTLEntry(context->targetlist,
+ (char *) &name_to_look_for);
if (n == NULL)
- *nodePtr = make_null(((Var *) node)->vartype);
+ return make_null(var->vartype);
else
- {
-
- /*
- * This is a hack: The varlevelsup of the orignal
- * variable and the new one should be the same.
- * Normally we adapt the node by changing a
- * pointer to point to a var contained in
- * 'targetlist'. In the targetlist all
- * varlevelsups are 0 so if we want to change it
- * to the original value we have to copy the node
- * before! (Maybe this will cause troubles with
- * some sophisticated queries on views?)
- */
- if (this_varlevelsup > 0)
- *nodePtr = copyObject(n);
- else
- *nodePtr = n;
-
- if (nodeTag(nodePtr) == T_Var)
- ((Var *) *nodePtr)->varlevelsup = this_varlevelsup;
- else
- nodeHandleViewRule(&n, rtable, targetlist,
- rt_index, modified, sublevels_up);
- }
- *modified = TRUE;
- }
- break;
- }
- case T_List:
- {
- List *l;
-
- foreach(l, (List *) node)
- {
- nodeHandleViewRule((Node **) (&(lfirst(l))),
- rtable, targetlist,
- rt_index, modified, sublevels_up);
+ return copyObject(n);
}
}
- break;
- case T_SubLink:
- {
- SubLink *sublink = (SubLink *) node;
- Query *query = (Query *) sublink->subselect;
-
- nodeHandleViewRule((Node **) &(query->qual), rtable, targetlist,
- rt_index, modified, sublevels_up + 1);
-
- /***S*H*D***/
- nodeHandleViewRule((Node **) &(query->havingQual), rtable, targetlist,
- rt_index, modified, sublevels_up + 1);
- nodeHandleViewRule((Node **) &(query->targetList), rtable, targetlist,
- rt_index, modified, sublevels_up + 1);
+ }
+ /* 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 *,
+ HandleRIRAttributeRule_mutator, context);
+ context->sublevels_up++;
+ MUTATE(newnode->subselect, sublink->subselect, Node *,
+ HandleRIRAttributeRule_mutator, context);
+ context->sublevels_up--;
+ return (Node *) newnode;
+ }
+ if (IsA(node, Query))
+ {
+ Query *query = (Query *) node;
+ Query *newnode;
+ /*
+ * XXX original code for HandleRIRAttributeRule only recursed into
+ * qual field of subquery. I'm assuming that was an oversight ...
+ */
- /*
- * We also have to adapt the variables used in
- * sublink->lefthand
- */
- nodeHandleViewRule((Node **) &(sublink->lefthand), rtable,
- targetlist, rt_index, modified, sublevels_up);
- }
- break;
- default:
- /* ignore the others */
- break;
+ FLATCOPY(newnode, query, Query);
+ MUTATE(newnode->targetList, query->targetList, List *,
+ HandleRIRAttributeRule_mutator, context);
+ MUTATE(newnode->qual, query->qual, Node *,
+ HandleRIRAttributeRule_mutator, context);
+ MUTATE(newnode->havingQual, query->havingQual, Node *,
+ HandleRIRAttributeRule_mutator, context);
+ return (Node *) newnode;
}
+ return expression_tree_mutator(node, HandleRIRAttributeRule_mutator,
+ (void *) context);
}
void
-HandleViewRule(Query *parsetree,
- List *rtable,
- List *targetlist,
- int rt_index,
- int *modified)
+HandleRIRAttributeRule(Query *parsetree,
+ List *rtable,
+ List *targetlist,
+ int rt_index,
+ int attr_num,
+ int *modified,
+ int *badsql)
{
- nodeHandleViewRule(&parsetree->qual, rtable, targetlist, rt_index,
- modified, 0);
- nodeHandleViewRule((Node **) (&(parsetree->targetList)), rtable, targetlist,
- rt_index, modified, 0);
-
- /*
- * The variables in the havingQual and groupClause also have to be
- * adapted
- */
- nodeHandleViewRule(&parsetree->havingQual, rtable, targetlist, rt_index,
- modified, 0);
- nodeHandleViewRule((Node **) (&(parsetree->groupClause)), rtable, targetlist, rt_index,
- modified, 0);
+ HandleRIRAttributeRule_context context;
+
+ context.rtable = rtable;
+ context.targetlist = targetlist;
+ context.rt_index = rt_index;
+ context.attr_num = attr_num;
+ context.modified = modified;
+ context.badsql = badsql;
+ context.sublevels_up = 0;
+
+ parsetree->targetList = (List *)
+ HandleRIRAttributeRule_mutator((Node *) parsetree->targetList,
+ &context);
+ parsetree->qual = HandleRIRAttributeRule_mutator(parsetree->qual,
+ &context);
+ /* XXX original code did not fix havingQual ... oversight? */
+ parsetree->havingQual = HandleRIRAttributeRule_mutator(parsetree->havingQual,
+ &context);
}
-
-#endif