/*------------------------------------------------------------------------- * * rewriteManip.c-- * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.2 1996/07/23 02:23:54 scrappy Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "nodes/pg_list.h" #include "utils/elog.h" #include "nodes/nodes.h" #include "nodes/relation.h" #include "nodes/primnodes.h" #include "parser/parsetree.h" /* for getrelid() */ #include "utils/lsyscache.h" #include "utils/builtins.h" #include "rewrite/rewriteHandler.h" #include "rewrite/rewriteSupport.h" #include "rewrite/locks.h" #include "nodes/plannodes.h" #include "optimizer/clauses.h" static void ResolveNew(RewriteInfo *info, List *targetlist, Node **node); void OffsetVarNodes(Node *node, int offset) { if (node==NULL) return; switch (nodeTag(node)) { case T_TargetEntry: { TargetEntry *tle = (TargetEntry *)node; OffsetVarNodes(tle->expr, offset); } break; case T_Expr: { Expr *expr = (Expr*)node; OffsetVarNodes((Node*)expr->args, offset); } break; case T_Var: { Var *var = (Var*)node; var->varno += offset; var->varnoold += offset; } break; case T_List: { List *l; foreach(l, (List*)node) { OffsetVarNodes(lfirst(l), offset); } } break; default: /* ignore the others */ break; } } void ChangeVarNodes(Node *node, int old_varno, int new_varno) { if (node==NULL) return; switch (nodeTag(node)) { case T_TargetEntry: { TargetEntry *tle = (TargetEntry *)node; ChangeVarNodes(tle->expr, old_varno, new_varno); } break; case T_Expr: { Expr *expr = (Expr*)node; ChangeVarNodes((Node*)expr->args, old_varno, new_varno); } break; case T_Var: { Var *var = (Var*)node; if (var->varno == old_varno) { var->varno = new_varno; var->varnoold = new_varno; } } break; case T_List: { List *l; foreach (l, (List*)node) { ChangeVarNodes(lfirst(l), old_varno, new_varno); } } break; default: /* ignore the others */ break; } } void AddQual(Query *parsetree, Node *qual) { Node *copy, *old; if (qual == NULL) return; copy = copyObject(qual); old = parsetree->qual; if (old == NULL) parsetree->qual = copy; else parsetree->qual = (Node*)make_andclause(makeList(parsetree->qual, copy, -1)); } void AddNotQual(Query *parsetree, Node *qual) { Node *copy; if (qual == NULL) return; copy = (Node*)make_notclause(copyObject(qual)); AddQual(parsetree,copy); } static Node * make_null(Oid type) { Const *c = makeNode(Const); c->consttype = type; c->constlen = get_typlen(type); c->constvalue = PointerGetDatum(NULL); c->constisnull = true; c->constbyval = get_typbyval(type); return (Node*)c; } void FixResdomTypes (List *tlist) { List *i; foreach (i, tlist) { TargetEntry *tle = lfirst(i); if (nodeTag(tle->expr) == T_Var) { Var *var = (Var*)tle->expr; tle->resdom->restype = var->vartype; tle->resdom->reslen = get_typlen(var->vartype); } } } static Node * FindMatchingNew(List *tlist, int attno) { List *i; foreach (i, tlist ) { TargetEntry *tle = lfirst(i); if (tle->resdom->resno == attno ) { return (tle->expr); } } return NULL; } static Node * FindMatchingTLEntry(List *tlist, char *e_attname) { List *i; foreach (i, tlist) { TargetEntry *tle = lfirst(i); char *resname; resname = tle->resdom->resname; if (!strcmp(e_attname, resname)) return (tle->expr); } return NULL; } static void ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr) { Node *node = *nodePtr; if (node == NULL) return; switch(nodeTag(node)) { case T_TargetEntry: ResolveNew(info, targetlist, &((TargetEntry*)node)->expr); break; case T_Expr: ResolveNew(info, targetlist, (Node**)(&(((Expr*)node)->args))); break; case T_Var: { int this_varno = (int)((Var*)node)->varno; Node *n; if (this_varno == info->new_varno) { n = FindMatchingNew(targetlist, ((Var*)node)->varattno); if (n == NULL) { if (info->event == CMD_UPDATE) { ((Var*)node)->varno = info->current_varno; ((Var*)node)->varnoold = info->current_varno; } else { *nodePtr = make_null(((Var*)node)->vartype); } } else { *nodePtr = n; } } break; } case T_List: { List *l; foreach(l, (List*)node) { ResolveNew(info, targetlist, (Node**)&(lfirst(l))); } break; } default: /* ignore the others */ break; } } void FixNew(RewriteInfo* info, Query *parsetree) { ResolveNew(info, parsetree->targetList, (Node**)&(info->rule_action->targetList)); ResolveNew(info, parsetree->targetList, &info->rule_action->qual); } static void nodeHandleRIRAttributeRule(Node **nodePtr, List *rtable, List *targetlist, int rt_index, int attr_num, int *modified, int *badsql) { Node *node = *nodePtr; if (node == NULL) return; switch (nodeTag(node)) { case T_List: { List *i; foreach(i, (List*)node) { nodeHandleRIRAttributeRule((Node**)(&(lfirst(i))), rtable, targetlist, rt_index, attr_num, modified, badsql); } } break; case T_TargetEntry: { TargetEntry *tle = (TargetEntry *)node; nodeHandleRIRAttributeRule(&tle->expr, rtable, targetlist, rt_index, attr_num, modified, badsql); } break; case T_Expr: { Expr *expr = (Expr *)node; nodeHandleRIRAttributeRule((Node**)(&(expr->args)), rtable, targetlist, rt_index, attr_num, modified, badsql); } break; case T_Var: { int this_varno = (int) ((Var*)node)->varno; NameData name_to_look_for; memset(name_to_look_for.data, 0, NAMEDATALEN); if (this_varno == rt_index && ((Var*) node)->varattno == attr_num) { if (((Var*)node)->vartype == 32) { /* HACK */ *nodePtr = make_null(((Var*)node)->vartype); *modified = TRUE; *badsql = TRUE; break; } else { 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; } } break; default: /* ignore the others */ break; } } /* * Handles 'on retrieve to relation.attribute * do instead retrieve (attribute = expression) w/qual' */ 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); nodeHandleRIRAttributeRule(&parsetree->qual, rtable, targetlist, rt_index, attr_num, modified, badsql); } static void nodeHandleViewRule(Node **nodePtr, List *rtable, List *targetlist, int rt_index, int *modified) { Node *node = *nodePtr; if (node == NULL) return; switch (nodeTag(node)) { case T_List: { List *l; foreach (l, (List*)node) { nodeHandleViewRule((Node**) (&(lfirst(l))), rtable, targetlist, rt_index, modified); } } break; case T_TargetEntry: { TargetEntry *tle = (TargetEntry *)node; nodeHandleViewRule(&(tle->expr), rtable, targetlist, rt_index, modified); } break; case T_Expr: { Expr *expr = (Expr*)node; nodeHandleViewRule((Node**)(&(expr->args)), rtable, targetlist, rt_index, modified); } break; case T_Var: { Var *var = (Var*)node; int this_varno = var->varno; Node *n; if (this_varno == rt_index) { n = FindMatchingTLEntry(targetlist, get_attname(getrelid(this_varno, rtable), var->varattno)); if (n == NULL) { *nodePtr = make_null(((Var*) node)->vartype); } else { *nodePtr = n; } *modified = TRUE; } break; } default: /* ignore the others */ break; } } void HandleViewRule(Query *parsetree, List *rtable, List *targetlist, int rt_index, int *modified) { nodeHandleViewRule(&parsetree->qual, rtable, targetlist, rt_index, modified); nodeHandleViewRule((Node**)(&(parsetree->targetList)), rtable, targetlist, rt_index, modified); }