postgresql/src/backend/rewrite/rewriteManip.c

436 lines
8.6 KiB
C

/*-------------------------------------------------------------------------
*
* 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);
}