1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* rewriteManip.c--
|
|
|
|
*
|
|
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
1998-09-01 05:29:17 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.16 1998/09/01 03:24:56 momjian Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1996-11-06 07:52:23 +01:00
|
|
|
#include <string.h>
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
#include "nodes/pg_list.h"
|
|
|
|
#include "utils/elog.h"
|
|
|
|
#include "nodes/nodes.h"
|
|
|
|
#include "nodes/relation.h"
|
|
|
|
#include "nodes/primnodes.h"
|
1997-09-07 07:04:48 +02:00
|
|
|
#include "parser/parsetree.h" /* for getrelid() */
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "utils/lsyscache.h"
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "rewrite/rewriteHandler.h"
|
1996-11-10 04:06:38 +01:00
|
|
|
#include "rewrite/rewriteManip.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "rewrite/rewriteSupport.h"
|
|
|
|
#include "rewrite/locks.h"
|
|
|
|
|
|
|
|
#include "nodes/plannodes.h"
|
|
|
|
#include "optimizer/clauses.h"
|
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
static void
|
|
|
|
ResolveNew(RewriteInfo *info, List *targetlist,
|
|
|
|
Node **node, int sublevels_up);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
OffsetVarNodes(Node *node, int offset)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (node == NULL)
|
|
|
|
return;
|
|
|
|
switch (nodeTag(node))
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_TargetEntry:
|
|
|
|
{
|
|
|
|
TargetEntry *tle = (TargetEntry *) node;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
OffsetVarNodes(tle->expr, offset);
|
|
|
|
}
|
|
|
|
break;
|
1998-01-04 05:31:43 +01:00
|
|
|
case T_Aggreg:
|
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
Aggreg *agg = (Aggreg *) node;
|
1998-01-04 05:31:43 +01:00
|
|
|
|
|
|
|
OffsetVarNodes(agg->target, offset);
|
|
|
|
}
|
|
|
|
break;
|
1998-07-19 07:49:26 +02:00
|
|
|
/* This has to be done to make queries using groupclauses work on views */
|
|
|
|
case T_GroupClause:
|
|
|
|
{
|
|
|
|
GroupClause *group = (GroupClause *) node;
|
|
|
|
|
|
|
|
OffsetVarNodes((Node *)(group->entry), offset);
|
|
|
|
}
|
|
|
|
break;
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_Expr:
|
|
|
|
{
|
|
|
|
Expr *expr = (Expr *) node;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
OffsetVarNodes((Node *) expr->args, offset);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_Var:
|
|
|
|
{
|
|
|
|
Var *var = (Var *) node;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
var->varno += offset;
|
|
|
|
var->varnoold += offset;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_List:
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
List *l;
|
|
|
|
|
|
|
|
foreach(l, (List *) node)
|
|
|
|
OffsetVarNodes(lfirst(l), offset);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
1998-07-19 07:49:26 +02:00
|
|
|
case T_SubLink:
|
|
|
|
{
|
|
|
|
SubLink *sublink = (SubLink *) node;
|
|
|
|
|
|
|
|
/* We also have to adapt the variables used in sublink->lefthand
|
|
|
|
* and sublink->oper */
|
|
|
|
OffsetVarNodes((Node *)(sublink->lefthand), offset);
|
|
|
|
|
|
|
|
/* Make sure the first argument of sublink->oper points to the
|
|
|
|
* same var as sublink->lefthand does otherwise we will
|
|
|
|
* run into troubles using aggregates (aggno will not be
|
|
|
|
* set correctly) */
|
|
|
|
lfirst(((Expr *) lfirst(sublink->oper))->args) =
|
|
|
|
lfirst(sublink->lefthand);
|
|
|
|
}
|
|
|
|
break;
|
1997-09-08 04:41:22 +02:00
|
|
|
default:
|
|
|
|
/* ignore the others */
|
|
|
|
break;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-01-21 05:24:46 +01:00
|
|
|
ChangeVarNodes(Node *node, int old_varno, int new_varno, int sublevels_up)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (node == NULL)
|
|
|
|
return;
|
|
|
|
switch (nodeTag(node))
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_TargetEntry:
|
|
|
|
{
|
|
|
|
TargetEntry *tle = (TargetEntry *) node;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-01-21 05:24:46 +01:00
|
|
|
ChangeVarNodes(tle->expr, old_varno, new_varno, sublevels_up);
|
1997-09-08 04:41:22 +02:00
|
|
|
}
|
|
|
|
break;
|
1998-01-04 05:31:43 +01:00
|
|
|
case T_Aggreg:
|
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
Aggreg *agg = (Aggreg *) node;
|
1998-01-04 05:31:43 +01:00
|
|
|
|
1998-01-21 05:24:46 +01:00
|
|
|
ChangeVarNodes(agg->target, old_varno, new_varno, sublevels_up);
|
1998-01-04 05:31:43 +01:00
|
|
|
}
|
|
|
|
break;
|
1998-07-19 07:49:26 +02:00
|
|
|
/* This has to be done to make queries using groupclauses work on views */
|
|
|
|
case T_GroupClause:
|
|
|
|
{
|
|
|
|
GroupClause *group = (GroupClause *) node;
|
|
|
|
|
|
|
|
ChangeVarNodes((Node *)(group->entry),old_varno, new_varno,
|
|
|
|
sublevels_up);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_Expr:
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Expr *expr = (Expr *) node;
|
|
|
|
|
1998-01-21 05:24:46 +01:00
|
|
|
ChangeVarNodes((Node *) expr->args, old_varno, new_varno, sublevels_up);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
|
|
|
case T_Var:
|
|
|
|
{
|
|
|
|
Var *var = (Var *) node;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-01-21 05:24:46 +01:00
|
|
|
if (var->varno == old_varno &&
|
|
|
|
var->varlevelsup == sublevels_up)
|
1997-09-08 04:41:22 +02:00
|
|
|
{
|
|
|
|
var->varno = new_varno;
|
|
|
|
var->varnoold = new_varno;
|
|
|
|
}
|
1998-07-19 07:49:26 +02:00
|
|
|
if (var->varlevelsup > 0) OffsetVarNodes((Node *)var,3);
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_List:
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
List *l;
|
|
|
|
|
|
|
|
foreach(l, (List *) node)
|
1998-01-21 05:24:46 +01:00
|
|
|
ChangeVarNodes(lfirst(l), old_varno, new_varno, sublevels_up);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_SubLink:
|
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
SubLink *sublink = (SubLink *) node;
|
|
|
|
Query *query = (Query *) sublink->subselect;
|
1998-01-21 05:24:46 +01:00
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
ChangeVarNodes((Node *) query->qual, old_varno, new_varno,
|
|
|
|
sublevels_up + 1);
|
1998-07-19 07:49:26 +02:00
|
|
|
|
|
|
|
/* We also have to adapt the variables used in sublink->lefthand
|
|
|
|
* and sublink->oper */
|
|
|
|
ChangeVarNodes((Node *) (sublink->lefthand), old_varno, new_varno,
|
|
|
|
sublevels_up);
|
|
|
|
|
|
|
|
/* Make sure the first argument of sublink->oper points to the
|
|
|
|
* same var as sublink->lefthand does otherwise we will
|
|
|
|
* run into troubles using aggregates (aggno will not be
|
|
|
|
* set correctly */
|
|
|
|
/* lfirst(((Expr *) lfirst(sublink->oper))->args) =
|
|
|
|
lfirst(sublink->lefthand); */
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* ignore the others */
|
|
|
|
break;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
AddQual(Query *parsetree, Node *qual)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Node *copy,
|
|
|
|
*old;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
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));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1998-07-19 07:49:26 +02:00
|
|
|
/* Adds 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)
|
|
|
|
{
|
|
|
|
Node *copy, *old;
|
|
|
|
|
|
|
|
if (havingQual == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
copy = copyObject(havingQual);
|
|
|
|
old = parsetree->havingQual;
|
|
|
|
if (old == NULL)
|
|
|
|
parsetree->havingQual = copy;
|
|
|
|
else
|
|
|
|
parsetree->havingQual =
|
|
|
|
(Node *) make_andclause(makeList(parsetree->havingQual, copy, -1));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
AddNotQual(Query *parsetree, Node *qual)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Node *copy;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (qual == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
copy = (Node *) make_notclause(copyObject(qual));
|
|
|
|
|
|
|
|
AddQual(parsetree, copy);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static Node *
|
1996-07-09 08:22:35 +02:00
|
|
|
make_null(Oid type)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Const *c = makeNode(Const);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
c->consttype = type;
|
|
|
|
c->constlen = get_typlen(type);
|
|
|
|
c->constvalue = PointerGetDatum(NULL);
|
|
|
|
c->constisnull = true;
|
|
|
|
c->constbyval = get_typbyval(type);
|
|
|
|
return (Node *) c;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
FixResdomTypes(List *tlist)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
List *i;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
foreach(i, tlist)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
TargetEntry *tle = lfirst(i);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (nodeTag(tle->expr) == T_Var)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Var *var = (Var *) tle->expr;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
tle->resdom->restype = var->vartype;
|
1998-02-10 05:02:59 +01:00
|
|
|
tle->resdom->restypmod = var->vartypmod;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static Node *
|
1997-09-08 23:56:23 +02:00
|
|
|
FindMatchingNew(List *tlist, int attno)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
List *i;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
foreach(i, tlist)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
TargetEntry *tle = lfirst(i);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (tle->resdom->resno == attno)
|
1998-09-01 05:29:17 +02:00
|
|
|
return tle->expr;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
return NULL;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static Node *
|
1997-09-08 23:56:23 +02:00
|
|
|
FindMatchingTLEntry(List *tlist, char *e_attname)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
List *i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
foreach(i, tlist)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
TargetEntry *tle = lfirst(i);
|
|
|
|
char *resname;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
resname = tle->resdom->resname;
|
|
|
|
if (!strcmp(e_attname, resname))
|
1998-09-01 05:29:17 +02:00
|
|
|
return tle->expr;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
return NULL;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1998-01-21 05:24:46 +01:00
|
|
|
ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr,
|
1998-02-26 05:46:47 +01:00
|
|
|
int sublevels_up)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Node *node = *nodePtr;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (node == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (nodeTag(node))
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_TargetEntry:
|
1998-01-21 05:24:46 +01:00
|
|
|
ResolveNew(info, targetlist, &((TargetEntry *) node)->expr,
|
1998-02-26 05:46:47 +01:00
|
|
|
sublevels_up);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
1998-01-04 05:31:43 +01:00
|
|
|
case T_Aggreg:
|
1998-01-21 05:24:46 +01:00
|
|
|
ResolveNew(info, targetlist, &((Aggreg *) node)->target,
|
1998-02-26 05:46:47 +01:00
|
|
|
sublevels_up);
|
1998-01-04 05:31:43 +01:00
|
|
|
break;
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_Expr:
|
1998-01-21 05:24:46 +01:00
|
|
|
ResolveNew(info, targetlist, (Node **) (&(((Expr *) node)->args)),
|
1998-02-26 05:46:47 +01:00
|
|
|
sublevels_up);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
|
|
|
case T_Var:
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
int this_varno = (int) ((Var *) node)->varno;
|
|
|
|
int this_varlevelsup = (int) ((Var *) node)->varlevelsup;
|
|
|
|
Node *n;
|
1997-09-08 04:41:22 +02:00
|
|
|
|
1998-01-21 05:24:46 +01:00
|
|
|
if (this_varno == info->new_varno &&
|
|
|
|
this_varlevelsup == sublevels_up)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
n = FindMatchingNew(targetlist,
|
|
|
|
((Var *) node)->varattno);
|
|
|
|
if (n == NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
if (info->event == CMD_UPDATE)
|
|
|
|
{
|
|
|
|
((Var *) node)->varno = info->current_varno;
|
|
|
|
((Var *) node)->varnoold = info->current_varno;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*nodePtr = make_null(((Var *) node)->vartype);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
1997-09-08 04:41:22 +02:00
|
|
|
*nodePtr = n;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_List:
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
List *l;
|
|
|
|
|
|
|
|
foreach(l, (List *) node)
|
1998-01-21 05:24:46 +01:00
|
|
|
ResolveNew(info, targetlist, (Node **) &(lfirst(l)),
|
1998-02-26 05:46:47 +01:00
|
|
|
sublevels_up);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1998-01-21 05:24:46 +01:00
|
|
|
case T_SubLink:
|
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
SubLink *sublink = (SubLink *) node;
|
|
|
|
Query *query = (Query *) sublink->subselect;
|
1998-01-21 05:24:46 +01:00
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
ResolveNew(info, targetlist, (Node **) &(query->qual), sublevels_up + 1);
|
1998-01-21 05:24:46 +01:00
|
|
|
}
|
|
|
|
break;
|
1997-09-08 04:41:22 +02:00
|
|
|
default:
|
|
|
|
/* ignore the others */
|
1997-09-07 07:04:48 +02:00
|
|
|
break;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
FixNew(RewriteInfo *info, Query *parsetree)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
ResolveNew(info, parsetree->targetList,
|
1998-01-21 05:24:46 +01:00
|
|
|
(Node **) &(info->rule_action->targetList), 0);
|
|
|
|
ResolveNew(info, parsetree->targetList, &info->rule_action->qual, 0);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1997-09-08 23:56:23 +02:00
|
|
|
nodeHandleRIRAttributeRule(Node **nodePtr,
|
|
|
|
List *rtable,
|
|
|
|
List *targetlist,
|
1997-09-07 07:04:48 +02:00
|
|
|
int rt_index,
|
|
|
|
int attr_num,
|
|
|
|
int *modified,
|
1998-01-21 05:24:46 +01:00
|
|
|
int *badsql,
|
|
|
|
int sublevels_up)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Node *node = *nodePtr;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (node == NULL)
|
|
|
|
return;
|
|
|
|
switch (nodeTag(node))
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_TargetEntry:
|
|
|
|
{
|
|
|
|
TargetEntry *tle = (TargetEntry *) node;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
nodeHandleRIRAttributeRule(&tle->expr, rtable, targetlist,
|
1998-02-26 05:46:47 +01:00
|
|
|
rt_index, attr_num, modified, badsql,
|
|
|
|
sublevels_up);
|
1997-09-08 04:41:22 +02:00
|
|
|
}
|
|
|
|
break;
|
1998-01-04 05:31:43 +01:00
|
|
|
case T_Aggreg:
|
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
Aggreg *agg = (Aggreg *) node;
|
1998-01-04 05:31:43 +01:00
|
|
|
|
|
|
|
nodeHandleRIRAttributeRule(&agg->target, rtable, targetlist,
|
1998-02-26 05:46:47 +01:00
|
|
|
rt_index, attr_num, modified, badsql,
|
|
|
|
sublevels_up);
|
1998-01-04 05:31:43 +01:00
|
|
|
}
|
|
|
|
break;
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_Expr:
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Expr *expr = (Expr *) node;
|
|
|
|
|
|
|
|
nodeHandleRIRAttributeRule((Node **) (&(expr->args)), rtable,
|
|
|
|
targetlist, rt_index, attr_num,
|
1998-01-21 05:24:46 +01:00
|
|
|
modified, badsql,
|
|
|
|
sublevels_up);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
|
|
|
case T_Var:
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-01-21 05:24:46 +01:00
|
|
|
int this_varno = ((Var *) node)->varno;
|
|
|
|
int this_varattno = ((Var *) node)->varattno;
|
|
|
|
int this_varlevelsup = ((Var *) node)->varlevelsup;
|
1997-09-08 04:41:22 +02:00
|
|
|
|
|
|
|
if (this_varno == rt_index &&
|
1998-01-21 05:24:46 +01:00
|
|
|
this_varattno == attr_num &&
|
|
|
|
this_varlevelsup == sublevels_up)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
if (((Var *) node)->vartype == 32)
|
|
|
|
{ /* HACK */
|
|
|
|
*nodePtr = make_null(((Var *) node)->vartype);
|
|
|
|
*modified = TRUE;
|
|
|
|
*badsql = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1998-01-21 05:24:46 +01:00
|
|
|
NameData name_to_look_for;
|
|
|
|
|
|
|
|
name_to_look_for.data[0] = '\0';
|
1997-09-08 04:41:22 +02:00
|
|
|
namestrcpy(&name_to_look_for,
|
|
|
|
(char *) get_attname(getrelid(this_varno,
|
|
|
|
rtable),
|
|
|
|
attr_num));
|
1998-01-21 05:24:46 +01:00
|
|
|
if (name_to_look_for.data[0])
|
|
|
|
{
|
|
|
|
Node *n;
|
1998-02-26 05:46:47 +01:00
|
|
|
|
1998-01-21 05:24:46 +01:00
|
|
|
n = FindMatchingTLEntry(targetlist, (char *) &name_to_look_for);
|
|
|
|
if (n == NULL)
|
|
|
|
*nodePtr = make_null(((Var *) node)->vartype);
|
|
|
|
else
|
|
|
|
*nodePtr = n;
|
|
|
|
*modified = TRUE;
|
|
|
|
}
|
1997-09-08 04:41:22 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1998-01-21 05:24:46 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_List:
|
|
|
|
{
|
|
|
|
List *i;
|
1997-09-08 04:41:22 +02:00
|
|
|
|
1998-01-21 05:24:46 +01:00
|
|
|
foreach(i, (List *) node)
|
|
|
|
{
|
|
|
|
nodeHandleRIRAttributeRule((Node **) (&(lfirst(i))), rtable,
|
|
|
|
targetlist, rt_index, attr_num,
|
1998-02-26 05:46:47 +01:00
|
|
|
modified, badsql, sublevels_up);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
}
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
1998-01-21 05:24:46 +01:00
|
|
|
case T_SubLink:
|
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
SubLink *sublink = (SubLink *) node;
|
|
|
|
Query *query = (Query *) sublink->subselect;
|
1998-01-21 05:24:46 +01:00
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
nodeHandleRIRAttributeRule((Node **) &(query->qual), rtable, targetlist,
|
|
|
|
rt_index, attr_num, modified, badsql,
|
|
|
|
sublevels_up + 1);
|
1998-01-21 05:24:46 +01:00
|
|
|
}
|
|
|
|
break;
|
1997-09-08 04:41:22 +02:00
|
|
|
default:
|
|
|
|
/* ignore the others */
|
|
|
|
break;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
1996-07-09 08:22:35 +02:00
|
|
|
* Handles 'on retrieve to relation.attribute
|
1997-09-07 07:04:48 +02:00
|
|
|
* do instead retrieve (attribute = expression) w/qual'
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
HandleRIRAttributeRule(Query *parsetree,
|
|
|
|
List *rtable,
|
|
|
|
List *targetlist,
|
1997-09-07 07:04:48 +02:00
|
|
|
int rt_index,
|
|
|
|
int attr_num,
|
|
|
|
int *modified,
|
|
|
|
int *badsql)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
nodeHandleRIRAttributeRule((Node **) (&(parsetree->targetList)), rtable,
|
|
|
|
targetlist, rt_index, attr_num,
|
1998-01-21 05:24:46 +01:00
|
|
|
modified, badsql, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
nodeHandleRIRAttributeRule(&parsetree->qual, rtable, targetlist,
|
1998-01-21 05:24:46 +01:00
|
|
|
rt_index, attr_num, modified, badsql, 0);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
1997-09-08 23:56:23 +02:00
|
|
|
nodeHandleViewRule(Node **nodePtr,
|
|
|
|
List *rtable,
|
|
|
|
List *targetlist,
|
1997-09-07 07:04:48 +02:00
|
|
|
int rt_index,
|
1998-01-21 05:24:46 +01:00
|
|
|
int *modified,
|
1998-02-26 05:46:47 +01:00
|
|
|
int sublevels_up)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Node *node = *nodePtr;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (node == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (nodeTag(node))
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_TargetEntry:
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
TargetEntry *tle = (TargetEntry *) node;
|
|
|
|
|
|
|
|
nodeHandleViewRule(&(tle->expr), rtable, targetlist,
|
1998-01-21 05:24:46 +01:00
|
|
|
rt_index, modified, sublevels_up);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
1998-01-04 05:31:43 +01:00
|
|
|
case T_Aggreg:
|
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
Aggreg *agg = (Aggreg *) node;
|
1998-01-04 05:31:43 +01:00
|
|
|
|
|
|
|
nodeHandleViewRule(&(agg->target), rtable, targetlist,
|
1998-07-19 07:49:26 +02:00
|
|
|
rt_index, modified, sublevels_up);
|
1998-01-04 05:31:43 +01:00
|
|
|
}
|
|
|
|
break;
|
1998-07-19 07:49:26 +02:00
|
|
|
/* 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;
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_Expr:
|
|
|
|
{
|
|
|
|
Expr *expr = (Expr *) node;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
nodeHandleViewRule((Node **) (&(expr->args)),
|
|
|
|
rtable, targetlist,
|
1998-01-21 05:24:46 +01:00
|
|
|
rt_index, modified, sublevels_up);
|
1997-09-08 04:41:22 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_Var:
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Var *var = (Var *) node;
|
|
|
|
int this_varno = var->varno;
|
1998-01-21 05:24:46 +01:00
|
|
|
int this_varlevelsup = var->varlevelsup;
|
1997-09-08 04:41:22 +02:00
|
|
|
Node *n;
|
1998-07-19 07:49:26 +02:00
|
|
|
|
1998-01-21 05:24:46 +01:00
|
|
|
if (this_varno == rt_index &&
|
1998-07-19 07:49:26 +02:00
|
|
|
this_varlevelsup == sublevels_up)
|
|
|
|
{
|
|
|
|
n = FindMatchingTLEntry(targetlist,
|
|
|
|
get_attname(getrelid(this_varno,
|
|
|
|
rtable),
|
|
|
|
var->varattno));
|
|
|
|
if (n == NULL)
|
|
|
|
{
|
|
|
|
*nodePtr = make_null(((Var *) node)->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;
|
|
|
|
}
|
|
|
|
((Var *)*nodePtr)->varlevelsup = this_varlevelsup;
|
|
|
|
}
|
|
|
|
*modified = TRUE;
|
|
|
|
}
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1998-01-21 05:24:46 +01:00
|
|
|
case T_List:
|
|
|
|
{
|
|
|
|
List *l;
|
|
|
|
|
|
|
|
foreach(l, (List *) node)
|
|
|
|
{
|
|
|
|
nodeHandleViewRule((Node **) (&(lfirst(l))),
|
|
|
|
rtable, targetlist,
|
|
|
|
rt_index, modified, sublevels_up);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_SubLink:
|
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
SubLink *sublink = (SubLink *) node;
|
|
|
|
Query *query = (Query *) sublink->subselect;
|
1998-01-21 05:24:46 +01:00
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
nodeHandleViewRule((Node **) &(query->qual), rtable, targetlist,
|
1998-07-19 07:49:26 +02:00
|
|
|
rt_index, modified, sublevels_up + 1);
|
|
|
|
|
|
|
|
/* We also have to adapt the variables used in sublink->lefthand
|
|
|
|
* and sublink->oper */
|
|
|
|
nodeHandleViewRule((Node **) &(sublink->lefthand), rtable,
|
|
|
|
targetlist, rt_index, modified, sublevels_up);
|
|
|
|
|
|
|
|
/* Make sure the first argument of sublink->oper points to the
|
|
|
|
* same var as sublink->lefthand does otherwise we will
|
|
|
|
* run into troubles using aggregates (aggno will not be
|
|
|
|
* set correctly */
|
|
|
|
pfree(lfirst(((Expr *) lfirst(sublink->oper))->args));
|
|
|
|
lfirst(((Expr *) lfirst(sublink->oper))->args) =
|
|
|
|
lfirst(sublink->lefthand);
|
1998-01-21 05:24:46 +01:00
|
|
|
}
|
|
|
|
break;
|
1997-09-08 04:41:22 +02:00
|
|
|
default:
|
|
|
|
/* ignore the others */
|
1997-09-07 07:04:48 +02:00
|
|
|
break;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
HandleViewRule(Query *parsetree,
|
|
|
|
List *rtable,
|
|
|
|
List *targetlist,
|
1997-09-07 07:04:48 +02:00
|
|
|
int rt_index,
|
|
|
|
int *modified)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
nodeHandleViewRule(&parsetree->qual, rtable, targetlist, rt_index,
|
1998-01-21 05:24:46 +01:00
|
|
|
modified, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
nodeHandleViewRule((Node **) (&(parsetree->targetList)), rtable, targetlist,
|
1998-01-21 05:24:46 +01:00
|
|
|
rt_index, modified, 0);
|
1998-07-19 07:49:26 +02:00
|
|
|
/* 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);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1998-07-19 07:49:26 +02:00
|
|
|
|