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.c435
1 files changed, 435 insertions, 0 deletions
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
new file mode 100644
index 00000000000..d5b6934649d
--- /dev/null
+++ b/src/backend/rewrite/rewriteManip.c
@@ -0,0 +1,435 @@
+/*-------------------------------------------------------------------------
+ *
+ * rewriteManip.c--
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.1.1.1 1996/07/09 06:21:52 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, &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);
+}
+