postgresql/src/backend/rewrite/rewriteManip.c

491 lines
9.0 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* rewriteManip.c--
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
1997-09-18 22:22:58 +02:00
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.8 1997/09/18 20:21:11 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#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/rewriteManip.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;
1997-09-18 22:22:58 +02:00
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);
}