]> granicus.if.org Git - postgresql/commitdiff
Here's a combination of all the patches I'm currently waiting
authorBruce Momjian <bruce@momjian.us>
Fri, 2 Oct 1998 16:28:04 +0000 (16:28 +0000)
committerBruce Momjian <bruce@momjian.us>
Fri, 2 Oct 1998 16:28:04 +0000 (16:28 +0000)
    for against a just updated CVS tree. It contains

        Partial new rewrite system that handles subselects,  view
        aggregate  columns, insert into select from view, updates
        with set col = view-value and select rules restriction to
        view definition.

        Updates  for  rule/view  backparsing utility functions to
        handle subselects correct.

        New system views pg_tables and pg_indexes (where you  can
        see the complete index definition in the latter one).

        Enabling array references on query parameters.

        Bugfix for functional index.

        Little changes to system views pg_rules and pg_views.

    The rule system isn't a release-stopper any longer.

    But  another  stopper  is  that  I  don't  know if the latest
    changes to PL/pgSQL (not already in CVS) made it  compile  on
    AIX. Still wait for some response from Dave.

Jan

src/backend/access/index/indexam.c
src/backend/rewrite/locks.c
src/backend/rewrite/rewriteDefine.c
src/backend/rewrite/rewriteHandler.c
src/backend/rewrite/rewriteManip.c
src/backend/utils/adt/ruleutils.c
src/bin/initdb/initdb.sh
src/include/catalog/pg_proc.h
src/include/rewrite/locks.h
src/test/regress/expected/rules.out
src/test/regress/sql/rules.sql

index f695d71107e3b8061af60dbd7b7b26c069a986b1..aa2d9446504ba74ec6e118c75f7175144e546708 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.27 1998/09/07 05:35:30 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.28 1998/10/02 16:27:43 momjian Exp $
  *
  * INTERFACE ROUTINES
  *             index_open              - open an index relation by relationId
@@ -362,7 +362,7 @@ GetIndexValue(HeapTuple tuple,
                          bool *attNull)
 {
        Datum           returnVal;
-       bool            isNull;
+       bool            isNull = FALSE;
 
        if (PointerIsValid(fInfo) && FIgetProcOid(fInfo) != InvalidOid)
        {
@@ -375,13 +375,15 @@ GetIndexValue(HeapTuple tuple,
                                                                          attrNums[i],
                                                                          hTupDesc,
                                                                          attNull);
+                       if (*attNull)
+                               isNull = TRUE;
                }
                returnVal = (Datum) fmgr_array_args(FIgetProcOid(fInfo),
                                                                                        FIgetnArgs(fInfo),
                                                                                        (char **) attData,
                                                                                        &isNull);
                pfree(attData);
-               *attNull = FALSE;
+               *attNull = isNull;
        }
        else
                returnVal = heap_getattr(tuple, attrNums[attOff], hTupDesc, attNull);
index f57a436420757b6feb213e76bb19bf58a25f8ccb..5c9b0887a1a5e9fea4f20ac335a4f8dd3a822ad7 100644 (file)
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.13 1998/09/01 04:31:30 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.14 1998/10/02 16:27:45 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,7 +24,6 @@
 #include "utils/builtins.h"
 #include "catalog/pg_shadow.h"
 
-static void checkLockPerms(List *locks, Query *parsetree, int rt_index);
 
 /*
  * ThisLockWasTriggered
@@ -170,7 +169,7 @@ matchLocks(CmdType event,
 }
 
 
-static void
+void
 checkLockPerms(List *locks, Query *parsetree, int rt_index)
 {
        Relation        ev_rel;
index 20eff2fbb03c002901824cd7d5a6cafb181d2b73..64d46efa408dc0ac960ec3d0ddf12d9c56094b04 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.21 1998/09/01 04:31:32 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.22 1998/10/02 16:27:46 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -199,11 +199,8 @@ DefineQueryRewrite(RuleStmt *stmt)
        /* ----------
         * The current rewrite handler is known to work on relation level
         * rules only. And for SELECT events, it expects one non-nothing
-        * action that is instead. Since we now hand out views and rules
-        * to regular users, we must deny anything else.
-        *
-        * I know that I must write a new rewrite handler from scratch
-        * for 6.5 so we can remove these checks and allow all the rules.
+        * action that is instead and returns exactly a tuple of the
+        * rewritten relation. This restricts SELECT rules to views.
         *
         *         Jan
         * ----------
@@ -217,6 +214,9 @@ DefineQueryRewrite(RuleStmt *stmt)
        else
                eslot_string = NULL;
 
+       /*
+        * No rule actions that modify OLD or NEW
+        */
        if (action != NIL)
                foreach(l, action)
        {
@@ -233,23 +233,86 @@ DefineQueryRewrite(RuleStmt *stmt)
                }
        }
 
+       /*
+        * Rules ON SELECT are restricted to view definitions
+        */
        if (event_type == CMD_SELECT)
        {
+               TargetEntry             *tle;
+               Resdom                  *resdom;
+               Form_pg_attribute       attr;
+               char                    *attname;
+               int                     i;
+
+               /*
+                * So there cannot be INSTEAD NOTHING, ...
+                */
                if (length(action) == 0)
                {
                        elog(NOTICE, "instead nothing rules on select currently not supported");
                        elog(ERROR, " use views instead");
                }
+
+               /*
+                * ... there cannot be multiple actions, ...
+                */
                if (length(action) > 1)
                        elog(ERROR, "multiple action rules on select currently not supported");
+               /*
+                * ... the one action must be a SELECT, ...
+                */
                query = (Query *) lfirst(action);
                if (!is_instead || query->commandType != CMD_SELECT)
                        elog(ERROR, "only instead-select rules currently supported on select");
+               if (event_qual != NULL)
+                       elog(ERROR, "event qualifications not supported for rules on select");
+
+               /*
+                * ... the targetlist of the SELECT action must
+                * exactly match the event relation ...
+                */
+               event_relation = heap_openr(event_obj->relname);
+               if (event_relation == NULL)
+                       elog(ERROR, "virtual relations not supported yet");
+
+               if (event_relation->rd_att->natts != length(query->targetList))
+                       elog(ERROR, "select rules target list must match event relations structure");
+
+               for (i = 1; i <= event_relation->rd_att->natts; i++) {
+                       tle = (TargetEntry *)nth(i - 1, query->targetList);
+                       resdom = tle->resdom;
+                       attr = event_relation->rd_att->attrs[i - 1];
+                       attname = nameout(&(attr->attname));
+
+                       if (strcmp(resdom->resname, attname) != 0)
+                               elog(ERROR, "select rules target entry %d has different column name from %s", i, attname);
+
+                       if (attr->atttypid != resdom->restype)
+                               elog(ERROR, "select rules target entry %d has different type from attribute %s", i,  attname);
+
+                       if (attr->atttypmod != resdom->restypmod)
+                               elog(ERROR, "select rules target entry %d has different size from attribute %s", i,  attname);
+               }
+
+               /*
+                * ... and final there must not be another ON SELECT
+                * rule already.
+                */
+               if (event_relation->rd_rules != NULL) {
+                       for (i = 0; i < event_relation->rd_rules->numLocks; i++) {
+                               RewriteRule     *rule;
+
+                               rule = event_relation->rd_rules->rules[i];
+                               if (rule->event == CMD_SELECT)
+                                       elog(ERROR, "%s is already a view", nameout(&(event_relation->rd_rel->relname)));
+                       }
+               }
+
+               heap_close(event_relation);
        }
 
        /*
-        * This rule is currently allowed - too restricted I know - but women
-        * and children first Jan
+        * This rule is allowed - install it.
         */
 
        event_relation = heap_openr(event_obj->relname);
index 7a4637e91e502ffd7d7986c33ab60d8a2ae9f878..0bbeeb0c51b2334eea7cbe1be79443b69402a2f7 100644 (file)
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.21 1998/09/01 04:31:33 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.22 1998/10/02 16:27:47 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include "utils/rel.h"
 #include "nodes/pg_list.h"
 #include "nodes/primnodes.h"
+#include "nodes/relation.h"
 
 #include "parser/parsetree.h"  /* for parsetree manipulation */
 #include "parser/parse_relation.h"
 #include "commands/creatinh.h"
 #include "access/heapam.h"
 
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 #include "utils/acl.h"
 #include "catalog/pg_shadow.h"
+#include "catalog/pg_type.h"
+
+
+
+static RewriteInfo *gatherRewriteMeta(Query *parsetree,
+                                 Query *rule_action,
+                                 Node *rule_qual,
+                                 int rt_index,
+                                 CmdType event,
+                                 bool *instead_flag);
+static bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up);
+static bool attribute_used(Node *node, int rt_index, int attno, int sublevels_up);
+static void offset_varnodes(Node *node, int offset, int sublevels_up);
+static void change_varnodes(Node *node, int rt_index, int new_index, int sublevels_up);
+static void modifyAggregUplevel(Node *node);
+static void modifyAggregChangeVarnodes(Node **nodePtr, int rt_index, int new_index, int sublevels_up);
+static void modifyAggregDropQual(Node **nodePtr, Node *orignode, Expr *expr);
+static SubLink *modifyAggregMakeSublink(Expr *origexp, Query *parsetree);
+static void modifyAggregQual(Node **nodePtr, Query *parsetree);
+
+
+
+
+
+
+
+
+
+
+
+
+
+static Query *fireRIRrules(Query *parsetree);
 
-static void ApplyRetrieveRule(Query *parsetree, RewriteRule *rule,
-                                 int rt_index, int relation_level,
-                                 Relation relation, int *modified);
-static List *fireRules(Query *parsetree, int rt_index, CmdType event,
-                 bool *instead_flag, List *locks, List **qual_products);
-static void QueryRewriteSubLink(Node *node);
-static List *QueryRewriteOne(Query *parsetree);
-static List *deepRewriteQuery(Query *parsetree);
-static void RewritePreprocessQuery(Query *parsetree);
-static Query *RewritePostprocessNonSelect(Query *parsetree);
 
 /*
  * gatherRewriteMeta -
@@ -118,316 +143,2083 @@ gatherRewriteMeta(Query *parsetree,
        return info;
 }
 
-static List *
-OptimizeRIRRules(List *locks)
-{
-       List       *attr_level = NIL,
-                          *i;
-       List       *relation_level = NIL;
-
-       foreach(i, locks)
-       {
-               RewriteRule *rule_lock = lfirst(i);
-
-               if (rule_lock->attrno == -1)
-                       relation_level = lappend(relation_level, rule_lock);
-               else
-                       attr_level = lappend(attr_level, rule_lock);
-       }
-       return nconc(relation_level, attr_level);
-}
 
 /*
- * idea is to fire regular rules first, then qualified instead
- * rules and unqualified instead rules last. Any lemming is counted for.
+ * rangeTableEntry_used -
+ *     we need to process a RTE for RIR rules only if it is
+ *     referenced somewhere in var nodes of the query.
  */
-static List *
-orderRules(List *locks)
+static bool
+rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
 {
-       List       *regular = NIL;
-       List       *instead_rules = NIL;
-       List       *instead_qualified = NIL;
-       List       *i;
+       if (node == NULL)
+               return FALSE;
 
-       foreach(i, locks)
-       {
-               RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
+       switch(nodeTag(node)) {
+               case T_TargetEntry:
+                       {
+                               TargetEntry     *tle = (TargetEntry *)node;
 
-               if (rule_lock->isInstead)
-               {
-                       if (rule_lock->qual == NULL)
-                               instead_rules = lappend(instead_rules, rule_lock);
-                       else
-                               instead_qualified = lappend(instead_qualified, rule_lock);
-               }
-               else
-                       regular = lappend(regular, rule_lock);
-       }
-       regular = nconc(regular, instead_qualified);
-       return nconc(regular, instead_rules);
-}
+                               return rangeTableEntry_used(
+                                               (Node *)(tle->expr),
+                                               rt_index,
+                                               sublevels_up);
+                       }
+                       break;
 
-static int
-AllRetrieve(List *actions)
-{
-       List       *n;
+               case T_Aggreg:
+                       {
+                               Aggreg  *agg = (Aggreg *)node;
 
-       foreach(n, actions)
-       {
-               Query      *pt = lfirst(n);
+                               return rangeTableEntry_used(
+                                               (Node *)(agg->target),
+                                               rt_index,
+                                               sublevels_up);
+                       }
+                       break;
 
-               /*
-                * in the old postgres code, we check whether command_type is a
-                * consp of '('*'.commandType). but we've never supported
-                * transitive closures. Hence removed    - ay 10/94.
-                */
-               if (pt->commandType != CMD_SELECT)
-                       return false;
-       }
-       return true;
-}
+               case T_GroupClause:
+                       {
+                               GroupClause     *grp = (GroupClause *)node;
 
-static List *
-FireRetrieveRulesAtQuery(Query *parsetree,
-                                                int rt_index,
-                                                Relation relation,
-                                                bool *instead_flag,
-                                                int rule_flag)
-{
-       List       *i,
-                          *locks;
-       RuleLock   *rt_entry_locks = NULL;
-       List       *work = NIL;
+                               return rangeTableEntry_used(
+                                               (Node *)(grp->entry),
+                                               rt_index,
+                                               sublevels_up);
+                       }
+                       break;
 
-       if ((rt_entry_locks = relation->rd_rules) == NULL)
-               return NIL;
+               case T_Expr:
+                       {
+                               Expr    *exp = (Expr *)node;
+
+                               return rangeTableEntry_used(
+                                               (Node *)(exp->args),
+                                               rt_index,
+                                               sublevels_up);
+                       }
+                       break;
 
-       locks = matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree);
+               case T_Iter:
+                       {
+                               Iter    *iter = (Iter *)node;
 
-       /* find all retrieve instead */
-       foreach(i, locks)
-       {
-               RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
+                               return rangeTableEntry_used(
+                                               (Node *)(iter->iterexpr),
+                                               rt_index,
+                                               sublevels_up);
+                       }
+                       break;
 
-               if (!rule_lock->isInstead)
-                       continue;
-               work = lappend(work, rule_lock);
-       }
-       if (work != NIL)
-       {
-               work = OptimizeRIRRules(locks);
-               foreach(i, work)
-               {
-                       RewriteRule *rule_lock = lfirst(i);
-                       int                     relation_level;
-                       int                     modified = FALSE;
+               case T_ArrayRef:
+                       {
+                               ArrayRef        *ref = (ArrayRef *)node;
+
+                               if (rangeTableEntry_used(
+                                               (Node *)(ref->refupperindexpr),
+                                               rt_index,
+                                               sublevels_up))
+                                       return TRUE;
+                               
+                               if (rangeTableEntry_used(
+                                               (Node *)(ref->reflowerindexpr),
+                                               rt_index,
+                                               sublevels_up))
+                                       return TRUE;
+                               
+                               if (rangeTableEntry_used(
+                                               (Node *)(ref->refexpr),
+                                               rt_index,
+                                               sublevels_up))
+                                       return TRUE;
+                               
+                               if (rangeTableEntry_used(
+                                               (Node *)(ref->refassgnexpr),
+                                               rt_index,
+                                               sublevels_up))
+                                       return TRUE;
+                               
+                               return FALSE;
+                       }
+                       break;
+
+               case T_Var:
+                       {
+                               Var     *var = (Var *)node;
+
+                               if (var->varlevelsup == sublevels_up)
+                                       return var->varno == rt_index;
+                               else
+                                       return FALSE;
+                       }
+                       break;
+
+               case T_Param:
+                       return FALSE;
 
-                       relation_level = (rule_lock->attrno == -1);
-                       if (rule_lock->actions == NIL)
+               case T_Const:
+                       return FALSE;
+
+               case T_List:
                        {
-                               *instead_flag = TRUE;
-                               return NIL;
+                               List    *l;
+
+                               foreach (l, (List *)node) {
+                                       if (rangeTableEntry_used(
+                                                       (Node *)lfirst(l),
+                                                       rt_index,
+                                                       sublevels_up))
+                                               return TRUE;
+                               }
+                               return FALSE;
                        }
-                       if (!rule_flag &&
-                               length(rule_lock->actions) >= 2 &&
-                               AllRetrieve(rule_lock->actions))
+                       break;
+
+               case T_SubLink:
                        {
-                               *instead_flag = TRUE;
-                               return rule_lock->actions;
+                               SubLink *sub = (SubLink *)node;
+
+                               if (rangeTableEntry_used(
+                                               (Node *)(sub->lefthand),
+                                               rt_index,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               if (rangeTableEntry_used(
+                                               (Node *)(sub->subselect),
+                                               rt_index,
+                                               sublevels_up + 1))
+                                       return TRUE;
+
+                               return FALSE;
                        }
-                       ApplyRetrieveRule(parsetree, rule_lock, rt_index, relation_level, relation,
-                                                         &modified);
-                       if (modified)
+                       break;
+
+               case T_Query:
                        {
-                               *instead_flag = TRUE;
-                               FixResdomTypes(parsetree->targetList);
-                               return lcons(parsetree, NIL);
+                               Query   *qry = (Query *)node;
+
+                               if (rangeTableEntry_used(
+                                               (Node *)(qry->targetList),
+                                               rt_index,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               if (rangeTableEntry_used(
+                                               (Node *)(qry->qual),
+                                               rt_index,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               if (rangeTableEntry_used(
+                                               (Node *)(qry->havingQual),
+                                               rt_index,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               if (rangeTableEntry_used(
+                                               (Node *)(qry->groupClause),
+                                               rt_index,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               return FALSE;
                        }
-               }
+                       break;
+
+               default:
+                       elog(NOTICE, "unknown node tag %d in rangeTableEntry_used()", nodeTag(node));
+                       elog(NOTICE, "Node is: %s", nodeToString(node));
+                       break;
+
+
        }
-       return NIL;
+
+       return FALSE;
 }
 
 
-/* Idea is like this:
- *
- * retrieve-instead-retrieve rules have different semantics than update nodes
- * Separate RIR rules from others.     Pass others to FireRules.
- * Order RIR rules and process.
- *
- * side effect: parsetree's rtable field might be changed
+/*
+ * attribute_used -
+ *     Check if a specific attribute number of a RTE is used
+ *     somewhere in the query
  */
-static void
-ApplyRetrieveRule(Query *parsetree,
-                                 RewriteRule *rule,
-                                 int rt_index,
-                                 int relation_level,
-                                 Relation relation,
-                                 int *modified)
+static bool
+attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
 {
-       Query      *rule_action = NULL;
-       Node       *rule_qual;
-       List       *rtable,
-                          *rt;
-       int                     nothing,
-                               rt_length;
-       int                     badsql = FALSE;
+       if (node == NULL)
+               return FALSE;
 
-       rule_qual = rule->qual;
-       if (rule->actions)
-       {
-               if (length(rule->actions) > 1)  /* ??? because we don't handle
-                                                                                * rules with more than one
-                                                                                * action? -ay */
+       switch(nodeTag(node)) {
+               case T_TargetEntry:
+                       {
+                               TargetEntry     *tle = (TargetEntry *)node;
 
-                       /*
-                        * WARNING!!! If we sometimes handle rules with more than one
-                        * action, the view acl checks might get broken.
-                        * viewAclOverride should only become true (below) if this is
-                        * a relation_level, instead, select query - Jan
-                        */
-                       return;
-               rule_action = copyObject(lfirst(rule->actions));
-               nothing = FALSE;
-       }
-       else
-               nothing = TRUE;
+                               return attribute_used(
+                                               (Node *)(tle->expr),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up);
+                       }
+                       break;
 
-       rtable = copyObject(parsetree->rtable);
-       foreach(rt, rtable)
-       {
-               RangeTblEntry *rte = lfirst(rt);
+               case T_Aggreg:
+                       {
+                               Aggreg  *agg = (Aggreg *)node;
 
-               /*
-                * this is to prevent add_missing_vars_to_base_rels() from adding
-                * a bogus entry to the new target list.
-                */
-               rte->inFromCl = false;
-       }
-       rt_length = length(rtable);
+                               return attribute_used(
+                                               (Node *)(agg->target),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up);
+                       }
+                       break;
 
-       rtable = nconc(rtable, copyObject(rule_action->rtable));
-       parsetree->rtable = rtable;
+               case T_GroupClause:
+                       {
+                               GroupClause     *grp = (GroupClause *)node;
 
-       rule_action->rtable = rtable;
-       OffsetVarNodes(rule_action->qual, rt_length);
-       OffsetVarNodes((Node *) rule_action->targetList, rt_length);
-       OffsetVarNodes(rule_qual, rt_length);
+                               return attribute_used(
+                                               (Node *)(grp->entry),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up);
+                       }
+                       break;
 
-       OffsetVarNodes((Node *) rule_action->groupClause, rt_length);
-       OffsetVarNodes((Node *) rule_action->havingQual, rt_length);
+               case T_Expr:
+                       {
+                               Expr    *exp = (Expr *)node;
 
-       ChangeVarNodes(rule_action->qual,
-                                  PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
-       ChangeVarNodes((Node *) rule_action->targetList,
-                                  PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
-       ChangeVarNodes(rule_qual, PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
+                               return attribute_used(
+                                               (Node *)(exp->args),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up);
+                       }
+                       break;
 
-       ChangeVarNodes((Node *) rule_action->groupClause,
-                                  PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
-       ChangeVarNodes((Node *) rule_action->havingQual,
-                                  PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
+               case T_Iter:
+                       {
+                               Iter    *iter = (Iter *)node;
 
-       if (relation_level)
-       {
-               HandleViewRule(parsetree, rtable, rule_action->targetList, rt_index,
-                                          modified);
-       }
-       else
-       {
-               HandleRIRAttributeRule(parsetree, rtable, rule_action->targetList,
-                                                          rt_index, rule->attrno, modified, &badsql);
-       }
-       if (*modified && !badsql)
-       {
-               AddQual(parsetree, rule_action->qual);
+                               return attribute_used(
+                                               (Node *)(iter->iterexpr),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up);
+                       }
+                       break;
 
-               /*
-                * This will only work if the query made to the view defined by
-                * the following groupClause groups by the same attributes or does
-                * not use group at all!
-                */
-               if (parsetree->groupClause == NULL)
-                       parsetree->groupClause = rule_action->groupClause;
-               AddHavingQual(parsetree, rule_action->havingQual);
-               parsetree->hasAggs = (rule_action->hasAggs || parsetree->hasAggs);
-               parsetree->hasSubLinks = (rule_action->hasSubLinks || parsetree->hasSubLinks);
-       }
-}
+               case T_ArrayRef:
+                       {
+                               ArrayRef        *ref = (ArrayRef *)node;
+
+                               if (attribute_used(
+                                               (Node *)(ref->refupperindexpr),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               if (attribute_used(
+                                               (Node *)(ref->reflowerindexpr),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               if (attribute_used(
+                                               (Node *)(ref->refexpr),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               if (attribute_used(
+                                               (Node *)(ref->refassgnexpr),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               return FALSE;
+                       }
+                       break;
 
-static List *
-ProcessRetrieveQuery(Query *parsetree,
-                                        List *rtable,
-                                        bool *instead_flag,
-                                        bool rule)
-{
-       List       *rt;
-       List       *product_queries = NIL;
-       int                     rt_index = 0;
+               case T_Var:
+                       {
+                               Var     *var = (Var *)node;
 
+                               if (var->varlevelsup == sublevels_up)
+                                       return var->varno == rt_index;
+                               else
+                                       return FALSE;
+                       }
+                       break;
 
-       foreach(rt, rtable)
-       {
-               RangeTblEntry *rt_entry = lfirst(rt);
-               Relation        rt_entry_relation = NULL;
-               List       *result = NIL;
+               case T_Param:
+                       return FALSE;
 
-               rt_index++;
-               rt_entry_relation = heap_openr(rt_entry->relname);
+               case T_Const:
+                       return FALSE;
 
+               case T_List:
+                       {
+                               List    *l;
+
+                               foreach (l, (List *)node) {
+                                       if (attribute_used(
+                                                       (Node *)lfirst(l),
+                                                       rt_index,
+                                                       attno,
+                                                       sublevels_up))
+                                               return TRUE;
+                               }
+                               return FALSE;
+                       }
+                       break;
+
+               case T_SubLink:
+                       {
+                               SubLink *sub = (SubLink *)node;
+
+                               if (attribute_used(
+                                               (Node *)(sub->lefthand),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               if (attribute_used(
+                                               (Node *)(sub->subselect),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up + 1))
+                                       return TRUE;
+
+                               return FALSE;
+                       }
+                       break;
+
+               case T_Query:
+                       {
+                               Query   *qry = (Query *)node;
+
+                               if (attribute_used(
+                                               (Node *)(qry->targetList),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               if (attribute_used(
+                                               (Node *)(qry->qual),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               if (attribute_used(
+                                               (Node *)(qry->havingQual),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               if (attribute_used(
+                                               (Node *)(qry->groupClause),
+                                               rt_index,
+                                               attno,
+                                               sublevels_up))
+                                       return TRUE;
+
+                               return FALSE;
+                       }
+                       break;
+
+               default:
+                       elog(NOTICE, "unknown node tag %d in attribute_used()", nodeTag(node));
+                       elog(NOTICE, "Node is: %s", nodeToString(node));
+                       break;
 
 
-               if (rt_entry_relation->rd_rules != NULL)
-               {
-                       result =
-                               FireRetrieveRulesAtQuery(parsetree,
-                                                                                rt_index,
-                                                                                rt_entry_relation,
-                                                                                instead_flag,
-                                                                                rule);
-               }
-               heap_close(rt_entry_relation);
-               if (*instead_flag)
-                       return result;
        }
-       if (rule)
-               return NIL;
 
-       rt_index = 0;
+       return FALSE;
+}
 
-       foreach(rt, rtable)
-       {
-               RangeTblEntry *rt_entry = lfirst(rt);
-               Relation        rt_entry_relation = NULL;
-               RuleLock   *rt_entry_locks = NULL;
-               List       *result = NIL;
-               List       *locks = NIL;
-               List       *dummy_products;
 
-               rt_index++;
-               rt_entry_relation = heap_openr(rt_entry->relname);
-               rt_entry_locks = rt_entry_relation->rd_rules;
-               heap_close(rt_entry_relation);
+/*
+ * offset_varnodes -
+ *     We need another version of OffsetVarNodes() when processing
+ *     RIR rules
+ */
+static void
+offset_varnodes(Node *node, int offset, int sublevels_up)
+{
+       if (node == NULL)
+               return;
+
+       switch(nodeTag(node)) {
+               case T_TargetEntry:
+                       {
+                               TargetEntry     *tle = (TargetEntry *)node;
 
+                               offset_varnodes(
+                                               (Node *)(tle->expr),
+                                               offset,
+                                               sublevels_up);
+                       }
+                       break;
 
-               if (rt_entry_locks)
-               {
-                       locks =
-                               matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree);
-               }
-               if (locks != NIL)
-               {
-                       result = fireRules(parsetree, rt_index, CMD_SELECT,
-                                                          instead_flag, locks, &dummy_products);
-                       if (*instead_flag)
-                               return lappend(NIL, result);
-                       if (result != NIL)
-                               product_queries = nconc(product_queries, result);
+               case T_Aggreg:
+                       {
+                               Aggreg  *agg = (Aggreg *)node;
+
+                               offset_varnodes(
+                                               (Node *)(agg->target),
+                                               offset,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_GroupClause:
+                       {
+                               GroupClause     *grp = (GroupClause *)node;
+
+                               offset_varnodes(
+                                               (Node *)(grp->entry),
+                                               offset,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Expr:
+                       {
+                               Expr    *exp = (Expr *)node;
+
+                               offset_varnodes(
+                                               (Node *)(exp->args),
+                                               offset,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Iter:
+                       {
+                               Iter    *iter = (Iter *)node;
+
+                               offset_varnodes(
+                                               (Node *)(iter->iterexpr),
+                                               offset,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_ArrayRef:
+                       {
+                               ArrayRef        *ref = (ArrayRef *)node;
+
+                               offset_varnodes(
+                                               (Node *)(ref->refupperindexpr),
+                                               offset,
+                                               sublevels_up);
+                               offset_varnodes(
+                                               (Node *)(ref->reflowerindexpr),
+                                               offset,
+                                               sublevels_up);
+                               offset_varnodes(
+                                               (Node *)(ref->refexpr),
+                                               offset,
+                                               sublevels_up);
+                               offset_varnodes(
+                                               (Node *)(ref->refassgnexpr),
+                                               offset,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Var:
+                       {
+                               Var     *var = (Var *)node;
+
+                               if (var->varlevelsup == sublevels_up) {
+                                       var->varno += offset;
+                                       var->varnoold += offset;
+                               }
+                       }
+                       break;
+
+               case T_Param:
+                       break;
+
+               case T_Const:
+                       break;
+
+               case T_List:
+                       {
+                               List    *l;
+
+                               foreach (l, (List *)node)
+                                       offset_varnodes(
+                                                       (Node *)lfirst(l),
+                                                       offset,
+                                                       sublevels_up);
+                       }
+                       break;
+
+               case T_SubLink:
+                       {
+                               SubLink *sub = (SubLink *)node;
+
+                               offset_varnodes(
+                                               (Node *)(sub->lefthand),
+                                               offset,
+                                               sublevels_up);
+
+                               offset_varnodes(
+                                               (Node *)(sub->subselect),
+                                               offset,
+                                               sublevels_up + 1);
+                       }
+                       break;
+
+               case T_Query:
+                       {
+                               Query   *qry = (Query *)node;
+
+                               offset_varnodes(
+                                               (Node *)(qry->targetList),
+                                               offset,
+                                               sublevels_up);
+
+                               offset_varnodes(
+                                               (Node *)(qry->qual),
+                                               offset,
+                                               sublevels_up);
+
+                               offset_varnodes(
+                                               (Node *)(qry->havingQual),
+                                               offset,
+                                               sublevels_up);
+
+                               offset_varnodes(
+                                               (Node *)(qry->groupClause),
+                                               offset,
+                                               sublevels_up);
+                       }
+                       break;
+
+               default:
+                       elog(NOTICE, "unknown node tag %d in offset_varnodes()", nodeTag(node));
+                       elog(NOTICE, "Node is: %s", nodeToString(node));
+                       break;
+
+
+       }
+}
+
+
+/*
+ * change_varnodes -
+ *     and another ChangeVarNodes() too
+ */
+static void
+change_varnodes(Node *node, int rt_index, int new_index, int sublevels_up)
+{
+       if (node == NULL)
+               return;
+
+       switch(nodeTag(node)) {
+               case T_TargetEntry:
+                       {
+                               TargetEntry     *tle = (TargetEntry *)node;
+
+                               change_varnodes(
+                                               (Node *)(tle->expr),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Aggreg:
+                       {
+                               Aggreg  *agg = (Aggreg *)node;
+
+                               change_varnodes(
+                                               (Node *)(agg->target),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_GroupClause:
+                       {
+                               GroupClause     *grp = (GroupClause *)node;
+
+                               change_varnodes(
+                                               (Node *)(grp->entry),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Expr:
+                       {
+                               Expr    *exp = (Expr *)node;
+
+                               change_varnodes(
+                                               (Node *)(exp->args),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Iter:
+                       {
+                               Iter    *iter = (Iter *)node;
+
+                               change_varnodes(
+                                               (Node *)(iter->iterexpr),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_ArrayRef:
+                       {
+                               ArrayRef        *ref = (ArrayRef *)node;
+
+                               change_varnodes(
+                                               (Node *)(ref->refupperindexpr),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                               change_varnodes(
+                                               (Node *)(ref->reflowerindexpr),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                               change_varnodes(
+                                               (Node *)(ref->refexpr),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                               change_varnodes(
+                                               (Node *)(ref->refassgnexpr),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Var:
+                       {
+                               Var     *var = (Var *)node;
+
+                               if (var->varlevelsup == sublevels_up &&
+                                               var->varno == rt_index) {
+                                       var->varno = new_index;
+                                       var->varnoold = new_index;
+                               }
+                       }
+                       break;
+
+               case T_Param:
+                       break;
+
+               case T_Const:
+                       break;
+
+               case T_List:
+                       {
+                               List    *l;
+
+                               foreach (l, (List *)node)
+                                       change_varnodes(
+                                                       (Node *)lfirst(l),
+                                                       rt_index,
+                                                       new_index,
+                                                       sublevels_up);
+                       }
+                       break;
+
+               case T_SubLink:
+                       {
+                               SubLink *sub = (SubLink *)node;
+
+                               change_varnodes(
+                                               (Node *)(sub->lefthand),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+
+                               change_varnodes(
+                                               (Node *)(sub->subselect),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up + 1);
+                       }
+                       break;
+
+               case T_Query:
+                       {
+                               Query   *qry = (Query *)node;
+
+                               change_varnodes(
+                                               (Node *)(qry->targetList),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+
+                               change_varnodes(
+                                               (Node *)(qry->qual),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+
+                               change_varnodes(
+                                               (Node *)(qry->havingQual),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+
+                               change_varnodes(
+                                               (Node *)(qry->groupClause),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               default:
+                       elog(NOTICE, "unknown node tag %d in change_varnodes()", nodeTag(node));
+                       elog(NOTICE, "Node is: %s", nodeToString(node));
+                       break;
+
+
+       }
+}
+
+
+/*
+ * modifyAggregUplevel -
+ *     In the newly created sublink for an aggregate column used in
+ *     the qualification, we must adjust the varlevelsup in all the
+ *     var nodes.
+ */
+static void
+modifyAggregUplevel(Node *node)
+{
+       if (node == NULL)
+               return;
+
+       switch(nodeTag(node)) {
+               case T_TargetEntry:
+                       {
+                               TargetEntry     *tle = (TargetEntry *)node;
+
+                               modifyAggregUplevel(
+                                               (Node *)(tle->expr));
+                       }
+                       break;
+
+               case T_Aggreg:
+                       {
+                               Aggreg  *agg = (Aggreg *)node;
+
+                               modifyAggregUplevel(
+                                               (Node *)(agg->target));
+                       }
+                       break;
+
+               case T_Expr:
+                       {
+                               Expr    *exp = (Expr *)node;
+
+                               modifyAggregUplevel(
+                                               (Node *)(exp->args));
+                       }
+                       break;
+
+               case T_Iter:
+                       {
+                               Iter    *iter = (Iter *)node;
+
+                               modifyAggregUplevel(
+                                               (Node *)(iter->iterexpr));
+                       }
+                       break;
+
+               case T_ArrayRef:
+                       {
+                               ArrayRef        *ref = (ArrayRef *)node;
+
+                               modifyAggregUplevel(
+                                               (Node *)(ref->refupperindexpr));
+                               modifyAggregUplevel(
+                                               (Node *)(ref->reflowerindexpr));
+                               modifyAggregUplevel(
+                                               (Node *)(ref->refexpr));
+                               modifyAggregUplevel(
+                                               (Node *)(ref->refassgnexpr));
+                       }
+                       break;
+
+               case T_Var:
+                       {
+                               Var     *var = (Var *)node;
+
+                               var->varlevelsup++;
+                       }
+                       break;
+
+               case T_Param:
+                       break;
+
+               case T_Const:
+                       break;
+
+               case T_List:
+                       {
+                               List    *l;
+
+                               foreach (l, (List *)node)
+                                       modifyAggregUplevel(
+                                                       (Node *)lfirst(l));
+                       }
+                       break;
+
+               case T_SubLink:
+                       {
+                               SubLink *sub = (SubLink *)node;
+
+                               modifyAggregUplevel(
+                                               (Node *)(sub->lefthand));
+
+                               modifyAggregUplevel(
+                                               (Node *)(sub->oper));
+
+                               modifyAggregUplevel(
+                                               (Node *)(sub->subselect));
+                       }
+                       break;
+
+               case T_Query:
+                       {
+                               Query   *qry = (Query *)node;
+
+                               modifyAggregUplevel(
+                                               (Node *)(qry->targetList));
+
+                               modifyAggregUplevel(
+                                               (Node *)(qry->qual));
+
+                               modifyAggregUplevel(
+                                               (Node *)(qry->havingQual));
+
+                               modifyAggregUplevel(
+                                               (Node *)(qry->groupClause));
+                       }
+                       break;
+
+               default:
+                       elog(NOTICE, "unknown node tag %d in modifyAggregUplevel()", nodeTag(node));
+                       elog(NOTICE, "Node is: %s", nodeToString(node));
+                       break;
+
+
+       }
+}
+
+
+/*
+ * modifyAggregChangeVarnodes -
+ *     Change the var nodes in a sublink created for an aggregate column
+ *     used in the qualification that is subject of the aggregate
+ *     function to point to the correct local RTE.
+ */
+static void
+modifyAggregChangeVarnodes(Node **nodePtr, int rt_index, int new_index, int sublevels_up)
+{
+       Node    *node = *nodePtr;
+
+       if (node == NULL)
+               return;
+
+       switch(nodeTag(node)) {
+               case T_TargetEntry:
+                       {
+                               TargetEntry     *tle = (TargetEntry *)node;
+
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(tle->expr)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Aggreg:
+                       {
+                               Aggreg  *agg = (Aggreg *)node;
+
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(agg->target)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_GroupClause:
+                       {
+                               GroupClause     *grp = (GroupClause *)node;
+
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(grp->entry)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Expr:
+                       {
+                               Expr    *exp = (Expr *)node;
+
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(exp->args)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Iter:
+                       {
+                               Iter    *iter = (Iter *)node;
+
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(iter->iterexpr)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_ArrayRef:
+                       {
+                               ArrayRef        *ref = (ArrayRef *)node;
+
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(ref->refupperindexpr)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(ref->reflowerindexpr)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(ref->refexpr)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(ref->refassgnexpr)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Var:
+                       {
+                               Var     *var = (Var *)node;
+
+                               if (var->varlevelsup == sublevels_up &&
+                                               var->varno == rt_index) {
+                                       var = copyObject(var);
+                                       var->varno = new_index;
+                                       var->varnoold = new_index;
+                                       var->varlevelsup = 0;
+
+                                       *nodePtr = (Node *)var;
+                               }
+                       }
+                       break;
+
+               case T_Param:
+                       break;
+
+               case T_Const:
+                       break;
+
+               case T_List:
+                       {
+                               List    *l;
+
+                               foreach (l, (List *)node)
+                                       modifyAggregChangeVarnodes(
+                                                       (Node **)(&lfirst(l)),
+                                                       rt_index,
+                                                       new_index,
+                                                       sublevels_up);
+                       }
+                       break;
+
+               case T_SubLink:
+                       {
+                               SubLink *sub = (SubLink *)node;
+
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(sub->lefthand)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(sub->oper)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(sub->subselect)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up + 1);
+                       }
+                       break;
+
+               case T_Query:
+                       {
+                               Query   *qry = (Query *)node;
+
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(qry->targetList)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(qry->qual)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(qry->havingQual)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+
+                               modifyAggregChangeVarnodes(
+                                               (Node **)(&(qry->groupClause)),
+                                               rt_index,
+                                               new_index,
+                                               sublevels_up);
+                       }
+                       break;
+
+               default:
+                       elog(NOTICE, "unknown node tag %d in modifyAggregChangeVarnodes()", nodeTag(node));
+                       elog(NOTICE, "Node is: %s", nodeToString(node));
+                       break;
+
+
+       }
+}
+
+
+/*
+ * modifyAggregDropQual -
+ *     remove the pure aggreg clase from a qualification
+ */
+static void
+modifyAggregDropQual(Node **nodePtr, Node *orignode, Expr *expr)
+{
+       Node    *node = *nodePtr;
+
+       if (node == NULL)
+               return;
+
+       switch(nodeTag(node)) {
+               case T_Var:
+                       break;
+
+               case T_Aggreg:
+                       {
+                               Aggreg  *agg = (Aggreg *)node;
+                               Aggreg  *oagg = (Aggreg *)orignode;
+
+                               modifyAggregDropQual(
+                                               (Node **)(&(agg->target)),
+                                               (Node *)(oagg->target),
+                                               expr);
+                       }
+                       break;
+
+               case T_Param:
+                       break;
+
+               case T_Const:
+                       break;
+
+               case T_GroupClause:
+                       break;
+
+               case T_Expr:
+                       {
+                               Expr    *this_expr = (Expr *)node;
+                               Expr    *orig_expr = (Expr *)orignode;
+
+                               if (orig_expr == expr) {
+                                       Const   *ctrue;
+
+                                       if (expr->typeOid != BOOLOID)
+                                               elog(ERROR,
+                                                       "aggregate expression in qualification isn't of type bool");
+                                       ctrue = makeNode(Const);
+                                       ctrue->consttype = BOOLOID;
+                                       ctrue->constlen = 1;
+                                       ctrue->constisnull = FALSE;
+                                       ctrue->constvalue = (Datum)TRUE;
+                                       ctrue->constbyval = TRUE;
+
+                                       *nodePtr = (Node *)ctrue;
+                               }
+                               else
+                                       modifyAggregDropQual(
+                                               (Node **)(&(this_expr->args)),
+                                               (Node *)(orig_expr->args),
+                                               expr);
+                       }
+                       break;
+
+               case T_Iter:
+                       {
+                               Iter    *iter = (Iter *)node;
+                               Iter    *oiter = (Iter *)orignode;
+
+                               modifyAggregDropQual(
+                                               (Node **)(&(iter->iterexpr)),
+                                               (Node *)(oiter->iterexpr),
+                                               expr);
+                       }
+                       break;
+
+               case T_ArrayRef:
+                       {
+                               ArrayRef        *ref = (ArrayRef *)node;
+                               ArrayRef        *oref = (ArrayRef *)orignode;
+
+                               modifyAggregDropQual(
+                                               (Node **)(&(ref->refupperindexpr)),
+                                               (Node *)(oref->refupperindexpr),
+                                               expr);
+                               modifyAggregDropQual(
+                                               (Node **)(&(ref->reflowerindexpr)),
+                                               (Node *)(oref->reflowerindexpr),
+                                               expr);
+                               modifyAggregDropQual(
+                                               (Node **)(&(ref->refexpr)),
+                                               (Node *)(oref->refexpr),
+                                               expr);
+                               modifyAggregDropQual(
+                                               (Node **)(&(ref->refassgnexpr)),
+                                               (Node *)(oref->refassgnexpr),
+                                               expr);
+                       }
+                       break;
+
+               case T_List:
+                       {
+                               List    *l;
+                               List    *ol = (List *)orignode;
+                               int     li = 0;
+
+                               foreach (l, (List *)node) {
+                                       modifyAggregDropQual(
+                                                       (Node **)(&(lfirst(l))),
+                                                       (Node *)nth(li, ol),
+                                                       expr);
+                                       li++;
+                               }
+                       }
+                       break;
+
+               case T_SubLink:
+                       {
+                               SubLink *sub = (SubLink *)node;
+                               SubLink *osub = (SubLink *)orignode;
+
+                               modifyAggregDropQual(
+                                               (Node **)(&(sub->subselect)),
+                                               (Node *)(osub->subselect),
+                                               expr);
+                       }
+                       break;
+
+               case T_Query:
+                       {
+                               Query   *qry = (Query *)node;
+                               Query   *oqry = (Query *)orignode;
+
+                               modifyAggregDropQual(
+                                               (Node **)(&(qry->qual)),
+                                               (Node *)(oqry->qual),
+                                               expr);
+
+                               modifyAggregDropQual(
+                                               (Node **)(&(qry->havingQual)),
+                                               (Node *)(oqry->havingQual),
+                                               expr);
+                       }
+                       break;
+
+               default:
+                       elog(NOTICE, "unknown node tag %d in modifyAggregDropQual()", nodeTag(node));
+                       elog(NOTICE, "Node is: %s", nodeToString(node));
+                       break;
+
+
+       }
+}
+
+
+/*
+ * modifyAggregMakeSublink -
+ *     Create a sublink node for a qualification expression that
+ *     uses an aggregate column of a view
+ */
+static SubLink *
+modifyAggregMakeSublink(Expr *origexp, Query *parsetree)
+{
+       SubLink         *sublink;
+       Query           *subquery;
+       Node            *subqual;
+       RangeTblEntry   *rte;
+       Aggreg          *aggreg;
+       Var             *target;
+       TargetEntry     *tle;
+       Resdom          *resdom;
+       Expr            *exp = copyObject(origexp);
+
+       if (nodeTag(nth(0, exp->args)) == T_Aggreg)
+               if (nodeTag(nth(1, exp->args)) == T_Aggreg)
+                       elog(ERROR, "rewrite: comparision of 2 aggregate columns not supported");
+               else
+                       elog(ERROR, "rewrite: aggregate column of view must be at rigth side in qual");
+
+       aggreg = (Aggreg *)nth(1, exp->args);
+       target  = (Var *)(aggreg->target);
+       rte     = (RangeTblEntry *)nth(target->varno - 1, parsetree->rtable);
+       tle     = makeNode(TargetEntry);
+       resdom  = makeNode(Resdom);
+
+       aggreg->usenulls = TRUE;
+
+       resdom->resno   = 1;
+       resdom->restype = ((Oper *)(exp->oper))->opresulttype;
+       resdom->restypmod = -1;
+       resdom->resname = pstrdup("<noname>");
+       resdom->reskey  = 0;
+       resdom->reskeyop = 0;
+       resdom->resjunk = 0;
+
+       tle->resdom     = resdom;
+       tle->expr       = (Node *)aggreg;
+
+       subqual = copyObject(parsetree->qual);
+       modifyAggregDropQual((Node **)&subqual, (Node *)parsetree->qual, origexp);
+
+       sublink = makeNode(SubLink);
+       sublink->subLinkType    = EXPR_SUBLINK;
+       sublink->useor          = FALSE;
+       sublink->lefthand       = lappend(NIL, copyObject(lfirst(exp->args)));
+       sublink->oper           = lappend(NIL, copyObject(exp));
+       sublink->subselect      = NULL;
+
+       subquery                = makeNode(Query);
+       sublink->subselect      = (Node *)subquery;
+
+       subquery->commandType           = CMD_SELECT;
+       subquery->utilityStmt           = NULL;
+       subquery->resultRelation        = 0;
+       subquery->into                  = NULL;
+       subquery->isPortal              = FALSE;
+       subquery->isBinary              = FALSE;
+       subquery->unionall              = FALSE;
+       subquery->uniqueFlag            = NULL;
+       subquery->sortClause            = NULL;
+       subquery->rtable                = lappend(NIL, rte);
+       subquery->targetList            = lappend(NIL, tle);
+       subquery->qual                  = subqual;
+       subquery->groupClause           = NIL;
+       subquery->havingQual            = NULL;
+       subquery->hasAggs               = TRUE;
+       subquery->hasSubLinks           = FALSE;
+       subquery->unionClause           = NULL;
+
+
+       modifyAggregUplevel((Node *)sublink);
+
+       modifyAggregChangeVarnodes((Node **)&(sublink->lefthand), target->varno,
+                       1, target->varlevelsup);
+       modifyAggregChangeVarnodes((Node **)&(sublink->oper), target->varno,
+                       1, target->varlevelsup);
+       modifyAggregChangeVarnodes((Node **)&(sublink->subselect), target->varno,
+                       1, target->varlevelsup);
+
+       return sublink;
+}
+
+
+/*
+ * modifyAggregQual -
+ *     Search for qualification expressions that contain aggregate
+ *     functions and substiture them by sublinks. These expressions
+ *     originally come from qualifications that use aggregate columns
+ *     of a view.
+ */
+static void
+modifyAggregQual(Node **nodePtr, Query *parsetree)
+{
+       Node    *node = *nodePtr;
+
+       if (node == NULL)
+               return;
+
+       switch(nodeTag(node)) {
+               case T_Var:
+                       break;
+
+               case T_Param:
+                       break;
+
+               case T_Const:
+                       break;
+
+               case T_GroupClause:
+                       {
+                               GroupClause     *grp = (GroupClause *)node;
+
+                               modifyAggregQual(
+                                               (Node **)(&(grp->entry)),
+                                               parsetree);
+                       }
+                       break;
+
+               case T_Expr:
+                       {
+                               Expr    *exp = (Expr *)node;
+                               SubLink *sub;
+
+
+                               if (length(exp->args) != 2) {
+                                       modifyAggregQual(
+                                               (Node **)(&(exp->args)),
+                                               parsetree);
+                                       break;
+                               }
+
+                               if (nodeTag(nth(0, exp->args)) != T_Aggreg &&
+                                       nodeTag(nth(1, exp->args)) != T_Aggreg) {
+
+                                       modifyAggregQual(
+                                               (Node **)(&(exp->args)),
+                                               parsetree);
+                                       break;
+                               }
+
+                               sub = modifyAggregMakeSublink(exp,
+                                               parsetree);
+
+                               *nodePtr = (Node *)sub;
+                               parsetree->hasSubLinks = TRUE;
+                       }
+                       break;
+
+               case T_Iter:
+                       {
+                               Iter    *iter = (Iter *)node;
+
+                               modifyAggregQual(
+                                               (Node **)(&(iter->iterexpr)),
+                                               parsetree);
+                       }
+                       break;
+
+               case T_ArrayRef:
+                       {
+                               ArrayRef        *ref = (ArrayRef *)node;
+
+                               modifyAggregQual(
+                                               (Node **)(&(ref->refupperindexpr)),
+                                               parsetree);
+                               modifyAggregQual(
+                                               (Node **)(&(ref->reflowerindexpr)),
+                                               parsetree);
+                               modifyAggregQual(
+                                               (Node **)(&(ref->refexpr)),
+                                               parsetree);
+                               modifyAggregQual(
+                                               (Node **)(&(ref->refassgnexpr)),
+                                               parsetree);
+                       }
+                       break;
+
+               case T_List:
+                       {
+                               List    *l;
+
+                               foreach (l, (List *)node)
+                                       modifyAggregQual(
+                                                       (Node **)(&(lfirst(l))),
+                                                       parsetree);
+                       }
+                       break;
+
+               case T_SubLink:
+                       {
+                               SubLink *sub = (SubLink *)node;
+
+                               modifyAggregQual(
+                                               (Node **)(&(sub->subselect)),
+                                               (Query *)(sub->subselect));
+                       }
+                       break;
+
+               case T_Query:
+                       {
+                               Query   *qry = (Query *)node;
+
+                               modifyAggregQual(
+                                               (Node **)(&(qry->qual)),
+                                               parsetree);
+
+                               modifyAggregQual(
+                                               (Node **)(&(qry->havingQual)),
+                                               parsetree);
+                       }
+                       break;
+
+               default:
+                       elog(NOTICE, "unknown node tag %d in modifyAggregQual()", nodeTag(node));
+                       elog(NOTICE, "Node is: %s", nodeToString(node));
+                       break;
+
+
+       }
+}
+
+
+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 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;
+}
+
+
+static void
+apply_RIR_view(Node **nodePtr, int rt_index, RangeTblEntry *rte, List *tlist, int *modified, int sublevels_up)
+{
+       Node    *node = *nodePtr;
+
+       if (node == NULL)
+               return;
+
+       switch(nodeTag(node)) {
+               case T_TargetEntry:
+                       {
+                               TargetEntry     *tle = (TargetEntry *)node;
+
+                               apply_RIR_view(
+                                               (Node **)(&(tle->expr)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Aggreg:
+                       {
+                               Aggreg  *agg = (Aggreg *)node;
+
+                               apply_RIR_view(
+                                               (Node **)(&(agg->target)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_GroupClause:
+                       {
+                               GroupClause     *grp = (GroupClause *)node;
+
+                               apply_RIR_view(
+                                               (Node **)(&(grp->entry)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Expr:
+                       {
+                               Expr    *exp = (Expr *)node;
+
+                               apply_RIR_view(
+                                               (Node **)(&(exp->args)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Iter:
+                       {
+                               Iter    *iter = (Iter *)node;
+
+                               apply_RIR_view(
+                                               (Node **)(&(iter->iterexpr)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_ArrayRef:
+                       {
+                               ArrayRef        *ref = (ArrayRef *)node;
+
+                               apply_RIR_view(
+                                               (Node **)(&(ref->refupperindexpr)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+                               apply_RIR_view(
+                                               (Node **)(&(ref->reflowerindexpr)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+                               apply_RIR_view(
+                                               (Node **)(&(ref->refexpr)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+                               apply_RIR_view(
+                                               (Node **)(&(ref->refassgnexpr)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+                       }
+                       break;
+
+               case T_Var:
+                       {
+                               Var     *var = (Var *)node;
+
+                               if (var->varlevelsup == sublevels_up &&
+                                               var->varno == rt_index) {
+                                       Node            *exp;
+
+                                       exp = FindMatchingTLEntry(
+                                                       tlist,
+                                                       get_attname(rte->relid,
+                                                               var->varattno));
+
+                                       if (exp == NULL) {
+                                               *nodePtr = make_null(var->vartype);
+                                               return;
+                                       }
+
+                                       if (var->varlevelsup > 0 &&
+                                                       nodeTag(exp) == T_Var) {
+                                               exp = copyObject(exp);
+                                               ((Var *)exp)->varlevelsup = var->varlevelsup;
+                                       }
+                                       *nodePtr = exp;
+                                       *modified = TRUE;
+                               }
+                       }
+                       break;
+
+               case T_Param:
+                       break;
+
+               case T_Const:
+                       break;
+
+               case T_List:
+                       {
+                               List    *l;
+
+                               foreach (l, (List *)node)
+                                       apply_RIR_view(
+                                                       (Node **)(&(lfirst(l))),
+                                                       rt_index,
+                                                       rte,
+                                                       tlist,
+                                                       modified,
+                                                       sublevels_up);
+                       }
+                       break;
+
+               case T_SubLink:
+                       {
+                               SubLink *sub = (SubLink *)node;
+
+                               apply_RIR_view(
+                                               (Node **)(&(sub->lefthand)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+
+                               apply_RIR_view(
+                                               (Node **)(&(sub->subselect)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up + 1);
+                       }
+                       break;
+
+               case T_Query:
+                       {
+                               Query   *qry = (Query *)node;
+
+                               apply_RIR_view(
+                                               (Node **)(&(qry->targetList)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+
+                               apply_RIR_view(
+                                               (Node **)(&(qry->qual)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+
+                               apply_RIR_view(
+                                               (Node **)(&(qry->havingQual)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+
+                               apply_RIR_view(
+                                               (Node **)(&(qry->groupClause)),
+                                               rt_index,
+                                               rte,
+                                               tlist,
+                                               modified,
+                                               sublevels_up);
+                       }
+                       break;
+
+               default:
+                       elog(NOTICE, "unknown node tag %d in apply_RIR_view()", nodeTag(node));
+                       elog(NOTICE, "Node is: %s", nodeToString(node));
+                       break;
+
+
+       }
+}
+
+
+static void
+ApplyRetrieveRule(Query *parsetree,
+                                 RewriteRule *rule,
+                                 int rt_index,
+                                 int relation_level,
+                                 Relation relation,
+                                 int *modified)
+{
+       Query      *rule_action = NULL;
+       Node       *rule_qual;
+       List       *rtable,
+                          *rt;
+       int                     nothing,
+                               rt_length;
+       int                     badsql = FALSE;
+
+       rule_qual = rule->qual;
+       if (rule->actions)
+       {
+               if (length(rule->actions) > 1)  /* ??? because we don't handle
+                                                                                * rules with more than one
+                                                                                * action? -ay */
+
+                       return;
+               rule_action = copyObject(lfirst(rule->actions));
+               nothing = FALSE;
+       }
+       else
+               nothing = TRUE;
+
+       rtable = copyObject(parsetree->rtable);
+       foreach(rt, rtable)
+       {
+               RangeTblEntry *rte = lfirst(rt);
+
+               /*
+                * this is to prevent add_missing_vars_to_base_rels() from adding
+                * a bogus entry to the new target list.
+                */
+               rte->inFromCl = false;
+       }
+       rt_length = length(rtable);
+
+       rtable = nconc(rtable, copyObject(rule_action->rtable));
+       parsetree->rtable = rtable;
+
+       rule_action->rtable = rtable;
+       offset_varnodes((Node *) rule_qual,   rt_length, 0);
+       offset_varnodes((Node *) rule_action, rt_length, 0);
+
+       change_varnodes((Node *) rule_qual, 
+                                  PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
+       change_varnodes((Node *) rule_action,
+                                  PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
+
+       if (relation_level)
+       {
+         apply_RIR_view((Node **) &parsetree, rt_index, 
+                       (RangeTblEntry *)nth(rt_index - 1, rtable),
+                       rule_action->targetList, modified, 0);
+         apply_RIR_view((Node **) &rule_action, rt_index, 
+                       (RangeTblEntry *)nth(rt_index - 1, rtable),
+                       rule_action->targetList, modified, 0);
+       }
+       else
+       {
+         HandleRIRAttributeRule(parsetree, rtable, rule_action->targetList,
+                                rt_index, rule->attrno, modified, &badsql);
+       }
+       if (*modified && !badsql) {
+         AddQual(parsetree, rule_action->qual);
+         /* This will only work if the query made to the view defined by the following
+          * groupClause groups by the same attributes or does not use group at all! */
+         if (parsetree->groupClause == NULL)
+           parsetree->groupClause=rule_action->groupClause;
+         AddHavingQual(parsetree, rule_action->havingQual);
+         parsetree->hasAggs = (rule_action->hasAggs || parsetree->hasAggs);
+         parsetree->hasSubLinks = (rule_action->hasSubLinks ||  parsetree->hasSubLinks);
+       }       
+}
+
+
+static void
+fireRIRonSubselect(Node *node)
+{
+       if (node == NULL)
+               return;
+
+       switch(nodeTag(node)) {
+               case T_TargetEntry:
+                       {
+                               TargetEntry     *tle = (TargetEntry *)node;
+
+                               fireRIRonSubselect(
+                                               (Node *)(tle->expr));
+                       }
+                       break;
+
+               case T_Aggreg:
+                       {
+                               Aggreg  *agg = (Aggreg *)node;
+
+                               fireRIRonSubselect(
+                                               (Node *)(agg->target));
+                       }
+                       break;
+
+               case T_GroupClause:
+                       {
+                               GroupClause     *grp = (GroupClause *)node;
+
+                               fireRIRonSubselect(
+                                               (Node *)(grp->entry));
+                       }
+                       break;
+
+               case T_Expr:
+                       {
+                               Expr    *exp = (Expr *)node;
+
+                               fireRIRonSubselect(
+                                               (Node *)(exp->args));
+                       }
+                       break;
+
+               case T_Iter:
+                       {
+                               Iter    *iter = (Iter *)node;
+
+                               fireRIRonSubselect(
+                                               (Node *)(iter->iterexpr));
+                       }
+                       break;
+
+               case T_ArrayRef:
+                       {
+                               ArrayRef        *ref = (ArrayRef *)node;
+
+                               fireRIRonSubselect(
+                                               (Node *)(ref->refupperindexpr));
+                               fireRIRonSubselect(
+                                               (Node *)(ref->reflowerindexpr));
+                               fireRIRonSubselect(
+                                               (Node *)(ref->refexpr));
+                               fireRIRonSubselect(
+                                               (Node *)(ref->refassgnexpr));
+                       }
+                       break;
+
+               case T_Var:
+                       break;
+
+               case T_Param:
+                       break;
+
+               case T_Const:
+                       break;
+
+               case T_List:
+                       {
+                               List    *l;
+
+                               foreach (l, (List *)node)
+                                       fireRIRonSubselect(
+                                                       (Node *)(lfirst(l)));
+                       }
+                       break;
+
+               case T_SubLink:
+                       {
+                               SubLink *sub = (SubLink *)node;
+                               Query   *qry;
+
+                               fireRIRonSubselect(
+                                               (Node *)(sub->lefthand));
+
+                               qry = fireRIRrules((Query *)(sub->subselect));
+
+                               fireRIRonSubselect(
+                                               (Node *)qry);
+
+                               sub->subselect = (Node *) qry;
+                       }
+                       break;
+
+               case T_Query:
+                       {
+                               Query   *qry = (Query *)node;
+
+                               fireRIRonSubselect(
+                                               (Node *)(qry->targetList));
+
+                               fireRIRonSubselect(
+                                               (Node *)(qry->qual));
+
+                               fireRIRonSubselect(
+                                               (Node *)(qry->havingQual));
+
+                               fireRIRonSubselect(
+                                               (Node *)(qry->groupClause));
+                       }
+                       break;
+
+               default:
+                       elog(NOTICE, "unknown node tag %d in fireRIRonSubselect()", nodeTag(node));
+                       elog(NOTICE, "Node is: %s", nodeToString(node));
+                       break;
+
+
+       }
+}
+
+
+/*
+ * fireRIRrules -
+ *     Apply all RIR rules on each rangetable entry in a query
+ */
+static Query *
+fireRIRrules(Query *parsetree)
+{
+       int             rt_index;
+       RangeTblEntry   *rte;
+       Relation        rel;
+       List            *locks;
+       RuleLock        *rules;
+       RewriteRule     *rule;
+       RewriteRule     RIRonly;
+       int             modified;
+       int             i;
+       List            *l;
+
+       rt_index = 0;
+       while(rt_index < length(parsetree->rtable)) {
+               ++rt_index;
+
+               if (!rangeTableEntry_used((Node *)parsetree, rt_index, 0))
+                       continue;
+               
+               rte = nth(rt_index - 1, parsetree->rtable);
+               rel = heap_openr(rte->relname);
+               if (rel->rd_rules == NULL) {
+                       heap_close(rel);
+                       continue;
+               }
+
+               rules = rel->rd_rules;
+               locks = NIL;
+
+               /*
+                * Collect the RIR rules that we must apply
+                */
+               for (i = 0; i < rules->numLocks; i++) {
+                       rule = rules->rules[i];
+                       if (rule->event != CMD_SELECT)
+                               continue;
+                       
+                       if (rule->attrno > 0 &&
+                                       !attribute_used((Node *)parsetree,
+                                                       rt_index,
+                                                       rule->attrno, 0))
+                               continue;
+
+                       locks = lappend(locks, rule);
+               }
+
+               /*
+                * Check permissions
+                */
+               checkLockPerms(locks, parsetree, rt_index);
+
+               /*
+                * Now apply them
+                */
+               foreach (l, locks) {
+                       rule = lfirst(l);
+
+                       RIRonly.event   = rule->event;
+                       RIRonly.attrno  = rule->attrno;
+                       RIRonly.qual    = rule->qual;
+                       RIRonly.actions = rule->actions;
+
+                       ApplyRetrieveRule(parsetree,
+                                       &RIRonly,
+                                       rt_index,
+                                       RIRonly.attrno == -1,
+                                       rel,
+                                       &modified);
+               }
+
+               heap_close(rel);
+       }
+
+       fireRIRonSubselect((Node *) parsetree);
+       modifyAggregQual((Node **) &(parsetree->qual), parsetree);
+
+       return parsetree;
+}
+
+
+/*
+ * idea is to fire regular rules first, then qualified instead
+ * rules and unqualified instead rules last. Any lemming is counted for.
+ */
+static List *
+orderRules(List *locks)
+{
+       List       *regular = NIL;
+       List       *instead_rules = NIL;
+       List       *instead_qualified = NIL;
+       List       *i;
+
+       foreach(i, locks)
+       {
+               RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
+
+               if (rule_lock->isInstead)
+               {
+                       if (rule_lock->qual == NULL)
+                               instead_rules = lappend(instead_rules, rule_lock);
+                       else
+                               instead_qualified = lappend(instead_qualified, rule_lock);
                }
+               else
+                       regular = lappend(regular, rule_lock);
        }
-       return product_queries;
+       regular = nconc(regular, instead_qualified);
+       return nconc(regular, instead_rules);
 }
 
+
+
 static Query *
 CopyAndAddQual(Query *parsetree,
                           List *actions,
@@ -462,6 +2254,7 @@ CopyAndAddQual(Query *parsetree,
 }
 
 
+
 /*
  *     fireRules -
  *        Iterate through rule locks applying rules.
@@ -488,13 +2281,7 @@ fireRules(Query *parsetree,
        /* choose rule to fire from list of rules */
        if (locks == NIL)
        {
-               ProcessRetrieveQuery(parsetree,
-                                                        parsetree->rtable,
-                                                        instead_flag, TRUE);
-               if (*instead_flag)
-                       return lappend(NIL, parsetree);
-               else
-                       return NIL;
+               return NIL;
        }
 
        locks = orderRules(locks);      /* real instead rules last */
@@ -505,7 +2292,6 @@ fireRules(Query *parsetree,
                                   *event_qual;
                List       *actions;
                List       *r;
-               bool            orig_instead_flag = *instead_flag;
 
                /*
                 * Instead rules change the resultRelation of the query. So the
@@ -645,8 +2431,10 @@ fireRules(Query *parsetree,
                         *--------------------------------------------------
                         */
                        info->rule_action->rtable = info->rt;
+                       /*
                        ProcessRetrieveQuery(info->rule_action, info->rt,
                                                                 &orig_instead_flag, TRUE);
+                       */
 
                        /*--------------------------------------------------
                         * Step 4
@@ -670,128 +2458,32 @@ fireRules(Query *parsetree,
        return results;
 }
 
-/* ----------
- * RewritePreprocessQuery -
- *     adjust details in the parsetree, the rule system
- *     depends on
- * ----------
- */
-static void
-RewritePreprocessQuery(Query *parsetree)
-{
-       /* ----------
-        * if the query has a resultRelation, reassign the
-        * result domain numbers to the attribute numbers in the
-        * target relation. FixNew() depends on it when replacing
-        * *new* references in a rule action by the expressions
-        * from the rewritten query.
-        * ----------
-        */
-       if (parsetree->resultRelation > 0)
-       {
-               RangeTblEntry *rte;
-               Relation        rd;
-               List       *tl;
-               TargetEntry *tle;
-               int                     resdomno;
-
-               rte = (RangeTblEntry *) nth(parsetree->resultRelation - 1,
-                                                                       parsetree->rtable);
-               rd = heap_openr(rte->relname);
-
-               foreach(tl, parsetree->targetList)
-               {
-                       tle = (TargetEntry *) lfirst(tl);
-                       resdomno = attnameAttNum(rd, tle->resdom->resname);
-                       tle->resdom->resno = resdomno;
-               }
-
-               heap_close(rd);
-       }
-}
-
-
-/* ----------
- * RewritePostprocessNonSelect -
- *     apply instead select rules on a query fired in by
- *     the rewrite system
- * ----------
- */
-static Query *
-RewritePostprocessNonSelect(Query *parsetree)
-{
-       List       *rt;
-       int                     rt_index = 0;
-       Query      *newtree = copyObject(parsetree);
-
-       foreach(rt, parsetree->rtable)
-       {
-               RangeTblEntry *rt_entry = lfirst(rt);
-               Relation        rt_entry_relation = NULL;
-               RuleLock   *rt_entry_locks = NULL;
-               List       *locks = NIL;
-               List       *instead_locks = NIL;
-               List       *lock;
-               RewriteRule *rule;
-
-               rt_index++;
-               rt_entry_relation = heap_openr(rt_entry->relname);
-               rt_entry_locks = rt_entry_relation->rd_rules;
-
-               if (rt_entry_locks)
-               {
-                       int                     origcmdtype = newtree->commandType;
-
-                       newtree->commandType = CMD_SELECT;
-                       locks =
-                               matchLocks(CMD_SELECT, rt_entry_locks, rt_index, newtree);
-                       newtree->commandType = origcmdtype;
-               }
-               if (locks != NIL)
-               {
-                       foreach(lock, locks)
-                       {
-                               rule = (RewriteRule *) lfirst(lock);
-                               if (rule->isInstead)
-                                       instead_locks = nconc(instead_locks, lock);
-                       }
-               }
-               if (instead_locks != NIL)
-               {
-                       foreach(lock, instead_locks)
-                       {
-                               int                     relation_level;
-                               int                     modified = 0;
-
-                               rule = (RewriteRule *) lfirst(lock);
-                               relation_level = (rule->attrno == -1);
-
-                               ApplyRetrieveRule(newtree,
-                                                                 rule,
-                                                                 rt_index,
-                                                                 relation_level,
-                                                                 rt_entry_relation,
-                                                                 &modified);
-                       }
-               }
-
-               heap_close(rt_entry_relation);
-       }
 
-       return newtree;
-}
 
 static List *
 RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
 {
        CmdType         event;
-       List       *product_queries = NIL;
-       int                     result_relation = 0;
+       List            *product_queries = NIL;
+       int             result_relation = 0;
+       RangeTblEntry   *rt_entry;
+       Relation        rt_entry_relation = NULL;
+       RuleLock        *rt_entry_locks = NULL;
 
        Assert(parsetree != NULL);
 
        event = parsetree->commandType;
 
+       /*
+        * SELECT rules are handled later when we have all the
+        * queries that should get executed
+        */
+       if (event == CMD_SELECT)
+               return NIL;
+
+       /*
+        * Utilities aren't rewritten at all - why is this here?
+        */
        if (event == CMD_UTILITY)
                return NIL;
 
@@ -803,79 +2495,34 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
 
        result_relation = parsetree->resultRelation;
 
-       if (event != CMD_SELECT)
-       {
-
-               /*
-                * the statement is an update, insert or delete
-                */
-               RangeTblEntry *rt_entry;
-               Relation        rt_entry_relation = NULL;
-               RuleLock   *rt_entry_locks = NULL;
-
-               rt_entry = rt_fetch(result_relation, parsetree->rtable);
-               rt_entry_relation = heap_openr(rt_entry->relname);
-               rt_entry_locks = rt_entry_relation->rd_rules;
-               heap_close(rt_entry_relation);
-
-               if (rt_entry_locks != NULL)
-               {
-                       List       *locks =
-                       matchLocks(event, rt_entry_locks, result_relation, parsetree);
-
-                       product_queries =
-                               fireRules(parsetree,
-                                                 result_relation,
-                                                 event,
-                                                 instead_flag,
-                                                 locks,
-                                                 qual_products);
-               }
-
-               /* ----------
-                * deepRewriteQuery does not handle the situation
-                * where a query fired by a rule uses relations that
-                * have instead select rules defined (views and the like).
-                * So we care for them here.
-                * ----------
-                */
-               if (product_queries != NIL)
-               {
-                       List       *pq;
-                       Query      *tmp;
-                       List       *new_products = NIL;
-
-                       foreach(pq, product_queries)
-                       {
-                               tmp = (Query *) lfirst(pq);
-                               tmp = RewritePostprocessNonSelect(tmp);
-                               new_products = lappend(new_products, tmp);
-                       }
-                       product_queries = new_products;
-               }
+       /*
+        * the statement is an update, insert or delete - fire rules
+        * on it.
+        */
+       rt_entry = rt_fetch(result_relation, parsetree->rtable);
+       rt_entry_relation = heap_openr(rt_entry->relname);
+       rt_entry_locks = rt_entry_relation->rd_rules;
+       heap_close(rt_entry_relation);
 
-               return product_queries;
-       }
-       else
+       if (rt_entry_locks != NULL)
        {
+               List       *locks =
+               matchLocks(event, rt_entry_locks, result_relation, parsetree);
+
+               product_queries =
+                       fireRules(parsetree,
+                                         result_relation,
+                                         event,
+                                         instead_flag,
+                                         locks,
+                                         qual_products);
+       }
 
-               /*
-                * the statement is a select
-                */
-               Query      *other;
-
-               /*
-                * ApplyRetrieveRule changes the range table XXX Unions are copied
-                * again.
-                */
-               other = copyObject(parsetree);
+       return product_queries;
 
-               return
-                       ProcessRetrieveQuery(other, parsetree->rtable,
-                                                                instead_flag, FALSE);
-       }
 }
 
+
 /*
  * to avoid infinite recursion, we restrict the number of times a query
  * can be rewritten. Detecting cycles is left for the reader as an excercise.
@@ -886,103 +2533,6 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
 
 static int     numQueryRewriteInvoked = 0;
 
-/*
- * QueryRewrite -
- *       rewrite one query via QueryRewrite system, possibly returning 0, or many
- *       queries
- */
-List *
-QueryRewrite(Query *parsetree)
-{
-       RewritePreprocessQuery(parsetree);
-
-       QueryRewriteSubLink(parsetree->qual);
-       QueryRewriteSubLink(parsetree->havingQual);
-
-       return QueryRewriteOne(parsetree);
-}
-
-/*
- *     QueryRewriteSubLink
- *
- *     This rewrites the SubLink subqueries first, doing the lowest ones first.
- *     We already have code in the main rewrite loops to process correlated
- *     variables from upper queries that exist in subqueries.
- */
-static void
-QueryRewriteSubLink(Node *node)
-{
-       if (node == NULL)
-               return;
-
-       switch (nodeTag(node))
-       {
-               case T_TargetEntry:
-                       break;
-               case T_Aggreg:
-                       break;
-               case T_Expr:
-                       {
-                               Expr       *expr = (Expr *) node;
-
-                               QueryRewriteSubLink((Node *) expr->args);
-                       }
-                       break;
-               case T_Var:
-                       break;
-               case T_List:
-                       {
-                               List       *l;
-
-                               foreach(l, (List *) node)
-                                       QueryRewriteSubLink(lfirst(l));
-                       }
-                       break;
-               case T_SubLink:
-                       {
-                               SubLink    *sublink = (SubLink *) node;
-                               Query      *query = (Query *) sublink->subselect;
-                               List       *ret;
-
-                               /*
-                                * Nest down first.  We do this so if a rewrite adds a
-                                * SubLink we don't process it as part of this loop.
-                                */
-                               QueryRewriteSubLink((Node *) query->qual);
-
-                               QueryRewriteSubLink((Node *) query->havingQual);
-
-                               ret = QueryRewriteOne(query);
-                               if (!ret)
-                                       sublink->subselect = NULL;
-                               else if (lnext(ret) == NIL)
-                                       sublink->subselect = lfirst(ret);
-                               else
-                                       elog(ERROR, "Don't know how to process subquery that rewrites to multiple queries.");
-                       }
-                       break;
-               default:
-                       /* ignore the others */
-                       break;
-       }
-       return;
-}
-
-/*
- * QueryOneRewrite -
- *       rewrite one query
- */
-static List *
-QueryRewriteOne(Query *parsetree)
-{
-       numQueryRewriteInvoked = 0;
-
-       /*
-        * take a deep breath and apply all the rewrite rules - ay
-        */
-       return deepRewriteQuery(parsetree);
-}
-
 /*
  * deepRewriteQuery -
  *       rewrites the query and apply the rules again on the queries rewritten
@@ -1040,3 +2590,104 @@ deepRewriteQuery(Query *parsetree)
 
        return rewritten;
 }
+
+
+/*
+ * QueryOneRewrite -
+ *       rewrite one query
+ */
+static List *
+QueryRewriteOne(Query *parsetree)
+{
+       numQueryRewriteInvoked = 0;
+
+       /*
+        * take a deep breath and apply all the rewrite rules - ay
+        */
+       return deepRewriteQuery(parsetree);
+}
+
+
+/* ----------
+ * RewritePreprocessQuery -
+ *     adjust details in the parsetree, the rule system
+ *     depends on
+ * ----------
+ */
+static void
+RewritePreprocessQuery(Query *parsetree)
+{
+       /* ----------
+        * if the query has a resultRelation, reassign the
+        * result domain numbers to the attribute numbers in the
+        * target relation. FixNew() depends on it when replacing
+        * *new* references in a rule action by the expressions
+        * from the rewritten query.
+        * ----------
+        */
+       if (parsetree->resultRelation > 0)
+       {
+               RangeTblEntry *rte;
+               Relation        rd;
+               List       *tl;
+               TargetEntry *tle;
+               int                     resdomno;
+
+               rte = (RangeTblEntry *) nth(parsetree->resultRelation - 1,
+                                                                       parsetree->rtable);
+               rd = heap_openr(rte->relname);
+
+               foreach(tl, parsetree->targetList)
+               {
+                       tle = (TargetEntry *) lfirst(tl);
+                       resdomno = attnameAttNum(rd, tle->resdom->resname);
+                       tle->resdom->resno = resdomno;
+               }
+
+               heap_close(rd);
+       }
+}
+
+
+/*
+ * QueryRewrite -
+ *       rewrite one query via query rewrite system, possibly returning 0
+ *       or many queries
+ */
+List *
+QueryRewrite(Query *parsetree)
+{
+       List            *querylist;
+       List            *results = NIL;
+       List            *l;
+       Query           *query;
+
+       /*
+        * Step 1
+        *
+        * There still seems something broken with the resdom numbers
+        * so we reassign them first.
+        */
+       RewritePreprocessQuery(parsetree);
+
+       /*
+        * Step 2
+        *
+        * Apply all non-SELECT rules possibly getting 0 or many queries
+        */
+       querylist = QueryRewriteOne(parsetree);
+
+       /*
+        * Step 3
+        *
+        * Apply all the RIR rules on each query
+        */
+       foreach (l, querylist) {
+               query = (Query *)lfirst(l);
+               results = lappend(results, fireRIRrules(query));
+       }
+
+       return results;
+}
+
+
index 15c68064a6a4c2d44ea3368dd658647f061b42c3..87786d9cdd078c654a455e58f996c867890dbb00 100644 (file)
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.18 1998/09/11 16:39:59 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.19 1998/10/02 16:27:49 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,6 +73,23 @@ OffsetVarNodes(Node *node, int offset)
                                OffsetVarNodes((Node *) expr->args, offset);
                        }
                        break;
+               case T_Iter:
+                       {
+                               Iter       *iter = (Iter *) node;
+
+                               OffsetVarNodes((Node *) iter->iterexpr, offset);
+                       }
+                       break;
+               case T_ArrayRef:
+                       {
+                               ArrayRef           *ref = (ArrayRef *) node;
+
+                               OffsetVarNodes((Node *) ref->refupperindexpr, offset);
+                               OffsetVarNodes((Node *) ref->reflowerindexpr, offset);
+                               OffsetVarNodes((Node *) ref->refexpr, offset);
+                               OffsetVarNodes((Node *) ref->refassgnexpr, offset);
+                       }
+                       break;
                case T_Var:
                        {
                                Var                *var = (Var *) node;
@@ -157,6 +174,23 @@ ChangeVarNodes(Node *node, int old_varno, int new_varno, int sublevels_up)
                                ChangeVarNodes((Node *) expr->args, old_varno, new_varno, sublevels_up);
                        }
                        break;
+               case T_Iter:
+                       {
+                               Iter       *iter = (Iter *) node;
+
+                               ChangeVarNodes((Node *) iter->iterexpr, old_varno, new_varno, sublevels_up);
+                       }
+                       break;
+               case T_ArrayRef:
+                       {
+                               ArrayRef           *ref = (ArrayRef *) node;
+
+                               ChangeVarNodes((Node *) ref->refupperindexpr, old_varno, new_varno, sublevels_up);
+                               ChangeVarNodes((Node *) ref->reflowerindexpr, old_varno, new_varno, sublevels_up);
+                               ChangeVarNodes((Node *) ref->refexpr, old_varno, new_varno, sublevels_up);
+                               ChangeVarNodes((Node *) ref->refassgnexpr, old_varno, new_varno, sublevels_up);
+                       }
+                       break;
                case T_Var:
                        {
                                Var                *var = (Var *) node;
@@ -353,6 +387,20 @@ ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr,
                        ResolveNew(info, targetlist, (Node **) (&(((Expr *) node)->args)),
                                           sublevels_up);
                        break;
+               case T_Iter:
+                       ResolveNew(info, targetlist, (Node **) (&(((Iter *) node)->iterexpr)),
+                                          sublevels_up);
+                       break;
+               case T_ArrayRef:
+                       ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refupperindexpr)),
+                                          sublevels_up);
+                       ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->reflowerindexpr)),
+                                          sublevels_up);
+                       ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refexpr)),
+                                          sublevels_up);
+                       ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refassgnexpr)),
+                                          sublevels_up);
+                       break;
                case T_Var:
                        {
                                int                     this_varno = (int) ((Var *) node)->varno;
@@ -454,6 +502,38 @@ nodeHandleRIRAttributeRule(Node **nodePtr,
                                                                                   sublevels_up);
                        }
                        break;
+               case T_Iter:
+                       {
+                               Iter       *iter = (Iter *) node;
+
+                               nodeHandleRIRAttributeRule((Node **) (&(iter->iterexpr)), rtable,
+                                                                                  targetlist, rt_index, attr_num,
+                                                                                  modified, badsql,
+                                                                                  sublevels_up);
+                       }
+                       break;
+               case T_ArrayRef:
+                       {
+                               ArrayRef           *ref = (ArrayRef *) node;
+
+                               nodeHandleRIRAttributeRule((Node **) (&(ref->refupperindexpr)), rtable,
+                                                                                  targetlist, rt_index, attr_num,
+                                                                                  modified, badsql,
+                                                                                  sublevels_up);
+                               nodeHandleRIRAttributeRule((Node **) (&(ref->reflowerindexpr)), rtable,
+                                                                                  targetlist, rt_index, attr_num,
+                                                                                  modified, badsql,
+                                                                                  sublevels_up);
+                               nodeHandleRIRAttributeRule((Node **) (&(ref->refexpr)), rtable,
+                                                                                  targetlist, rt_index, attr_num,
+                                                                                  modified, badsql,
+                                                                                  sublevels_up);
+                               nodeHandleRIRAttributeRule((Node **) (&(ref->refassgnexpr)), rtable,
+                                                                                  targetlist, rt_index, attr_num,
+                                                                                  modified, badsql,
+                                                                                  sublevels_up);
+                       }
+                       break;
                case T_Var:
                        {
                                int                     this_varno = ((Var *) node)->varno;
@@ -598,6 +678,33 @@ nodeHandleViewRule(Node **nodePtr,
                                                                   rt_index, modified, sublevels_up);
                        }
                        break;
+               case T_Iter:
+                       {
+                               Iter       *iter = (Iter *) node;
+
+                               nodeHandleViewRule((Node **) (&(iter->iterexpr)),
+                                                                  rtable, targetlist,
+                                                                  rt_index, modified, sublevels_up);
+                       }
+                       break;
+               case T_ArrayRef:
+                       {
+                               ArrayRef           *ref = (ArrayRef *) node;
+
+                               nodeHandleViewRule((Node **) (&(ref->refupperindexpr)),
+                                                                  rtable, targetlist,
+                                                                  rt_index, modified, sublevels_up);
+                               nodeHandleViewRule((Node **) (&(ref->reflowerindexpr)),
+                                                                  rtable, targetlist,
+                                                                  rt_index, modified, sublevels_up);
+                               nodeHandleViewRule((Node **) (&(ref->refexpr)),
+                                                                  rtable, targetlist,
+                                                                  rt_index, modified, sublevels_up);
+                               nodeHandleViewRule((Node **) (&(ref->refassgnexpr)),
+                                                                  rtable, targetlist,
+                                                                  rt_index, modified, sublevels_up);
+                       }
+                       break;
                case T_Var:
                        {
                                Var                *var = (Var *) node;
index f9774bf62f545c5f90f3c8e1ed19fe60cf2acebf..b3a1db8c069010f503755033b5ddafe2d651d708 100644 (file)
@@ -3,7 +3,7 @@
  *                       out of it's tuple
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.3 1998/09/01 04:32:49 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.4 1998/10/02 16:27:51 momjian Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
 #include "utils/lsyscache.h"
 #include "catalog/pg_class.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_shadow.h"
+#include "catalog/pg_index.h"
+#include "catalog/pg_opclass.h"
 #include "fmgr.h"
 
 
+/* ----------
+ * Local data types
+ * ----------
+ */
+typedef struct QryHier {
+       struct QryHier          *parent;
+       Query                   *query;
+} QryHier;
+
+
 /* ----------
  * Global data
  * ----------
@@ -64,6 +77,10 @@ static void *plan_getrule = NULL;
 static char *query_getrule = "SELECT * FROM pg_rewrite WHERE rulename = $1";
 static void *plan_getview = NULL;
 static char *query_getview = "SELECT * FROM pg_rewrite WHERE rulename = $1 or rulename = $2";
+static void *plan_getam = NULL;
+static char *query_getam = "SELECT * FROM pg_am WHERE oid = $1";
+static void *plan_getopclass = NULL;
+static char *query_getopclass = "SELECT * FROM pg_opclass WHERE oid = $1";
 
 
 /* ----------
@@ -72,6 +89,8 @@ static char *query_getview = "SELECT * FROM pg_rewrite WHERE rulename = $1 or ru
  */
 text      *pg_get_ruledef(NameData *rname);
 text      *pg_get_viewdef(NameData *rname);
+text       *pg_get_indexdef(Oid indexrelid);
+NameData   *pg_get_userbyid(int4 uid);
 
 
 /* ----------
@@ -80,15 +99,16 @@ text           *pg_get_viewdef(NameData *rname);
  */
 static char *make_ruledef(HeapTuple ruletup, TupleDesc rulettc);
 static char *make_viewdef(HeapTuple ruletup, TupleDesc rulettc);
-static char *get_query_def(Query *query);
-static char *get_select_query_def(Query *query);
-static char *get_insert_query_def(Query *query);
-static char *get_update_query_def(Query *query);
-static char *get_delete_query_def(Query *query);
-static char *get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix);
-static char *get_func_expr(List *rtable, int rt_index, Expr *expr, bool varprefix);
-static char *get_tle_expr(List *rtable, int rt_index, TargetEntry *tle, bool varprefix);
+static char *get_query_def(Query *query, QryHier *parentqh);
+static char *get_select_query_def(Query *query, QryHier *qh);
+static char *get_insert_query_def(Query *query, QryHier *qh);
+static char *get_update_query_def(Query *query, QryHier *qh);
+static char *get_delete_query_def(Query *query, QryHier *qh);
+static char *get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix);
+static char *get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix);
+static char *get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix);
 static char *get_const_expr(Const *constval);
+static char *get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix);
 static char *get_relation_name(Oid relid);
 static char *get_attribute_name(Oid relid, int2 attnum);
 static bool check_if_rte_used(int rt_index, Node *node, int sup);
@@ -288,6 +308,272 @@ pg_get_viewdef(NameData *rname)
 }
 
 
+/* ----------
+ * get_viewdef                 - Mainly the same thing, but we
+ *                               only return the SELECT part of a view
+ * ----------
+ */
+text       *
+pg_get_indexdef(Oid indexrelid)
+{
+       text            *indexdef;
+       HeapTuple       ht_idx;
+       HeapTuple       ht_idxrel;
+       HeapTuple       ht_indrel;
+       HeapTuple       spi_tup;
+       TupleDesc       spi_ttc;
+       int             spi_fno;
+       Form_pg_index   idxrec;
+       Form_pg_class   idxrelrec;
+       Form_pg_class   indrelrec;
+       Datum           spi_args[1];
+       char            spi_nulls[2];
+       int             spirc;
+       int             len;
+       int             keyno;
+       char            buf[8192];
+       char            keybuf[8192];
+       char            *sep;
+
+       /* ----------
+        * Connect to SPI manager
+        * ----------
+        */
+       if (SPI_connect() != SPI_OK_CONNECT)
+               elog(ERROR, "get_indexdef: cannot connect to SPI manager");
+
+       /* ----------
+        * On the first call prepare the plans to lookup pg_am
+        * and pg_opclass.
+        * ----------
+        */
+       if (plan_getam == NULL)
+       {
+               Oid                     argtypes[1];
+               void       *plan;
+
+               argtypes[0] = OIDOID;
+               plan = SPI_prepare(query_getam, 1, argtypes);
+               if (plan == NULL)
+                       elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getam);
+               plan_getam = SPI_saveplan(plan);
+
+               argtypes[0] = OIDOID;
+               plan = SPI_prepare(query_getopclass, 1, argtypes);
+               if (plan == NULL)
+                       elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getopclass);
+               plan_getopclass = SPI_saveplan(plan);
+       }
+
+       /* ----------
+        * Fetch the pg_index tuple by the Oid of the index
+        * ----------
+        */
+       ht_idx = SearchSysCacheTuple(INDEXRELID,
+                       ObjectIdGetDatum(indexrelid), 0, 0, 0);
+       if (!HeapTupleIsValid(ht_idx))
+               elog(ERROR, "syscache lookup for index %d failed", indexrelid);
+       idxrec = (Form_pg_index)GETSTRUCT(ht_idx);
+
+       /* ----------
+        * Fetch the pg_class tuple of the index relation
+        * ----------
+        */
+       ht_idxrel = SearchSysCacheTuple(RELOID,
+                       ObjectIdGetDatum(idxrec->indexrelid), 0, 0, 0);
+       if (!HeapTupleIsValid(ht_idxrel))
+               elog(ERROR, "syscache lookup for relid %d failed", idxrec->indexrelid);
+       idxrelrec = (Form_pg_class)GETSTRUCT(ht_idxrel);
+
+       /* ----------
+        * Fetch the pg_class tuple of the indexed relation
+        * ----------
+        */
+       ht_indrel = SearchSysCacheTuple(RELOID,
+                       ObjectIdGetDatum(idxrec->indrelid), 0, 0, 0);
+       if (!HeapTupleIsValid(ht_indrel))
+               elog(ERROR, "syscache lookup for relid %d failed", idxrec->indrelid);
+       indrelrec = (Form_pg_class)GETSTRUCT(ht_indrel);
+
+       /* ----------
+        * Get the am name for the index relation
+        * ----------
+        */
+       spi_args[0] = ObjectIdGetDatum(idxrelrec->relam);
+       spi_nulls[0] = ' ';
+       spi_nulls[1] = '\0';
+       spirc = SPI_execp(plan_getam, spi_args, spi_nulls, 1);
+       if (spirc != SPI_OK_SELECT)
+               elog(ERROR, "failed to get pg_am tuple for index %s", nameout(&(idxrelrec->relname)));
+       if (SPI_processed != 1)
+               elog(ERROR, "failed to get pg_am tuple for index %s", nameout(&(idxrelrec->relname)));
+       spi_tup = SPI_tuptable->vals[0];
+       spi_ttc = SPI_tuptable->tupdesc;
+       spi_fno = SPI_fnumber(spi_ttc, "amname");
+
+       /* ----------
+        * Start the index definition
+        * ----------
+        */
+       sprintf(buf, "CREATE %sINDEX %s ON %s USING %s (",
+               idxrec->indisunique ? "UNIQUE " : "",
+               nameout(&(idxrelrec->relname)),
+               nameout(&(indrelrec->relname)),
+               SPI_getvalue(spi_tup, spi_ttc, spi_fno));
+                       
+       /* ----------
+        * Collect the indexed attributes
+        * ----------
+        */
+       sep = "";
+       keybuf[0] = '\0';
+       for (keyno = 0; keyno < INDEX_MAX_KEYS; keyno++)
+       {
+               if (idxrec->indkey[keyno] == InvalidAttrNumber)
+                       break;
+
+               strcat(keybuf, sep);
+               sep = ", ";
+
+               /* ----------
+                * Add the indexed field name
+                * ----------
+                */
+               if (idxrec->indkey[keyno] == ObjectIdAttributeNumber - 1)
+                       strcat(keybuf, "oid");
+               else
+                       strcat(keybuf, get_attribute_name(idxrec->indrelid,
+                                               idxrec->indkey[keyno]));
+
+               /* ----------
+                * If not a functional index, add the operator class name
+                * ----------
+                */
+               if (idxrec->indproc == InvalidOid)
+               {
+                       spi_args[0] = ObjectIdGetDatum(idxrec->indclass[keyno]);
+                       spi_nulls[0] = ' ';
+                       spi_nulls[1] = '\0';
+                       spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
+                       if (spirc != SPI_OK_SELECT)
+                               elog(ERROR, "failed to get pg_opclass tuple %d", idxrec->indclass[keyno]);
+                       if (SPI_processed != 1)
+                               elog(ERROR, "failed to get pg_opclass tuple %d", idxrec->indclass[keyno]);
+                       spi_tup = SPI_tuptable->vals[0];
+                       spi_ttc = SPI_tuptable->tupdesc;
+                       spi_fno = SPI_fnumber(spi_ttc, "opcname");
+                       strcat(keybuf, " ");
+                       strcat(keybuf, SPI_getvalue(spi_tup, spi_ttc, spi_fno));
+               }
+       }
+
+       /* ----------
+        * For functional index say 'func (attrs) opclass'
+        * ----------
+        */
+       if (idxrec->indproc != InvalidOid)
+       {
+               HeapTuple       proctup;
+               Form_pg_proc    procStruct;
+
+               proctup = SearchSysCacheTuple(PROOID,
+                                                               ObjectIdGetDatum(idxrec->indproc), 0, 0, 0);
+               if (!HeapTupleIsValid(proctup))
+                       elog(ERROR, "cache lookup for proc %d failed", idxrec->indproc);
+
+               procStruct = (Form_pg_proc) GETSTRUCT(proctup);
+               strcat(buf, nameout(&(procStruct->proname)));
+               strcat(buf, " (");
+               strcat(buf, keybuf);
+               strcat(buf, ") ");
+
+               spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]);
+               spi_nulls[0] = ' ';
+               spi_nulls[1] = '\0';
+               spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
+               if (spirc != SPI_OK_SELECT)
+                       elog(ERROR, "failed to get pg_opclass tuple %d", idxrec->indclass[0]);
+               if (SPI_processed != 1)
+                       elog(ERROR, "failed to get pg_opclass tuple %d", idxrec->indclass[0]);
+               spi_tup = SPI_tuptable->vals[0];
+               spi_ttc = SPI_tuptable->tupdesc;
+               spi_fno = SPI_fnumber(spi_ttc, "opcname");
+               strcat(buf, SPI_getvalue(spi_tup, spi_ttc, spi_fno));
+       }
+       else
+       /* ----------
+        * For the others say 'attr opclass [, ...]'
+        * ----------
+        */
+       {
+               strcat(buf, keybuf);
+       }
+
+       /* ----------
+        * Finish
+        * ----------
+        */
+       strcat(buf, ")");
+
+       /* ----------
+        * Create the result in upper executor memory
+        * ----------
+        */
+       len = strlen(buf) + VARHDRSZ;
+       indexdef = SPI_palloc(len);
+       VARSIZE(indexdef) = len;
+       memcpy(VARDATA(indexdef), buf, len - VARHDRSZ);
+
+       /* ----------
+        * Disconnect from SPI manager
+        * ----------
+        */
+       if (SPI_finish() != SPI_OK_FINISH)
+               elog(ERROR, "get_viewdef: SPI_finish() failed");
+
+       return indexdef;
+}
+
+
+/* ----------
+ * get_userbyid                        - Get a user name by usesysid and
+ *                               fallback to 'unknown (UID=n)'
+ * ----------
+ */
+NameData   *
+pg_get_userbyid(int4 uid)
+{
+       HeapTuple       usertup;
+       Form_pg_shadow  user_rec;
+       NameData        *result;
+
+       /* ----------
+        * Allocate space for the result
+        * ----------
+        */
+       result = (NameData *) palloc(NAMEDATALEN);
+       memset(result->data, 0, NAMEDATALEN);
+
+       /* ----------
+        * Get the pg_shadow entry and print the result
+        * ----------
+        */
+       usertup = SearchSysCacheTuple(USESYSID,
+                       ObjectIdGetDatum(uid), 0, 0, 0);
+       if (HeapTupleIsValid(usertup))
+       {
+               user_rec = (Form_pg_shadow)GETSTRUCT(usertup);
+               StrNCpy(result->data, (&(user_rec->usename))->data, NAMEDATALEN);
+       }
+       else
+       {
+               sprintf((char *)result, "unknown (UID=%d)", uid);
+       }
+
+       return result;
+}
+
+
 /* ----------
  * make_ruledef                        - reconstruct the CREATE RULE command
  *                               for a given pg_rewrite tuple
@@ -331,16 +617,13 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
 
        fno = SPI_fnumber(rulettc, "ev_qual");
        ev_qual = SPI_getvalue(ruletup, rulettc, fno);
-       if (isnull)
-               ev_qual = NULL;
 
        fno = SPI_fnumber(rulettc, "ev_action");
        ev_action = SPI_getvalue(ruletup, rulettc, fno);
-       if (isnull)
-               ev_action = NULL;
        if (ev_action != NULL)
                actions = (List *) stringToNode(ev_action);
 
+
        /* ----------
         * Build the rules definition text
         * ----------
@@ -391,12 +674,15 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
        {
                Node       *qual;
                Query      *query;
+               QryHier    qh;
 
                qual = stringToNode(ev_qual);
                query = (Query *) lfirst(actions);
+               qh.parent = NULL;
+               qh.query  = query;
 
                strcat(buf, " WHERE ");
-               strcat(buf, get_rule_expr(query->rtable, 0, qual, TRUE));
+               strcat(buf, get_rule_expr(&qh, 0, qual, TRUE));
        }
 
        strcat(buf, " DO ");
@@ -415,7 +701,7 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
                foreach(action, actions)
                {
                        query = (Query *) lfirst(action);
-                       strcat(buf, get_query_def(query));
+                       strcat(buf, get_query_def(query, NULL));
                        strcat(buf, "; ");
                }
                strcat(buf, ");");
@@ -431,7 +717,7 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
                        Query      *query;
 
                        query = (Query *) lfirst(actions);
-                       strcat(buf, get_query_def(query));
+                       strcat(buf, get_query_def(query, NULL));
                        strcat(buf, ";");
                }
        }
@@ -482,13 +768,9 @@ make_viewdef(HeapTuple ruletup, TupleDesc rulettc)
 
        fno = SPI_fnumber(rulettc, "ev_qual");
        ev_qual = SPI_getvalue(ruletup, rulettc, fno);
-       if (isnull)
-               ev_qual = "";
 
        fno = SPI_fnumber(rulettc, "ev_action");
        ev_action = SPI_getvalue(ruletup, rulettc, fno);
-       if (isnull)
-               ev_action = NULL;
        if (ev_action != NULL)
                actions = (List *) stringToNode(ev_action);
 
@@ -500,7 +782,7 @@ make_viewdef(HeapTuple ruletup, TupleDesc rulettc)
        if (ev_type != '1' || ev_attr >= 0 || !is_instead || strcmp(ev_qual, ""))
                return "Not a view";
 
-       strcpy(buf, get_select_query_def(query));
+       strcpy(buf, get_query_def(query, NULL));
        strcat(buf, ";");
 
        /* ----------
@@ -518,24 +800,29 @@ make_viewdef(HeapTuple ruletup, TupleDesc rulettc)
  * ----------
  */
 static char *
-get_query_def(Query *query)
+get_query_def(Query *query, QryHier *parentqh)
 {
+       QryHier         qh;
+
+       qh.parent = parentqh;
+       qh.query  = query;
+
        switch (query->commandType)
        {
                        case CMD_SELECT:
-                       return get_select_query_def(query);
+                       return get_select_query_def(query, &qh);
                        break;
 
                case CMD_UPDATE:
-                       return get_update_query_def(query);
+                       return get_update_query_def(query, &qh);
                        break;
 
                case CMD_INSERT:
-                       return get_insert_query_def(query);
+                       return get_insert_query_def(query, &qh);
                        break;
 
                case CMD_DELETE:
-                       return get_delete_query_def(query);
+                       return get_delete_query_def(query, &qh);
                        break;
 
                case CMD_NOTHING:
@@ -557,7 +844,7 @@ get_query_def(Query *query)
  * ----------
  */
 static char *
-get_select_query_def(Query *query)
+get_select_query_def(Query *query, QryHier *qh)
 {
        char            buf[8192];
        char       *sep;
@@ -635,7 +922,7 @@ get_select_query_def(Query *query)
                strcat(buf, sep);
                sep = ", ";
 
-               strcat(buf, get_tle_expr(query->rtable, 0, tle, (rt_numused > 1)));
+               strcat(buf, get_tle_expr(qh, 0, tle, (rt_numused > 1)));
 
                /* Check if we must say AS ... */
                if (nodeTag(tle->expr) != T_Var)
@@ -681,7 +968,7 @@ get_select_query_def(Query *query)
                                strcat(buf, sep);
                                sep = ", ";
                                strcat(buf, rte->relname);
-                               if (rt_numused > 1)
+                               if (strcmp(rte->relname, rte->refname) != 0)
                                {
                                        strcat(buf, " ");
                                        strcat(buf, rte->refname);
@@ -694,7 +981,7 @@ get_select_query_def(Query *query)
        if (query->qual != NULL)
        {
                strcat(buf, " WHERE ");
-               strcat(buf, get_rule_expr(query->rtable, 0, query->qual, (rt_numused > 1)));
+               strcat(buf, get_rule_expr(qh, 0, query->qual, (rt_numused > 1)));
        }
 
        /* Add the GROUP BY CLAUSE */
@@ -706,7 +993,7 @@ get_select_query_def(Query *query)
                {
                        strcat(buf, sep);
                        sep = ", ";
-                       strcat(buf, get_rule_expr(query->rtable, 0, lfirst(l), (rt_numused > 1)));
+                       strcat(buf, get_rule_expr(qh, 0, lfirst(l), (rt_numused > 1)));
                }
        }
 
@@ -723,7 +1010,7 @@ get_select_query_def(Query *query)
  * ----------
  */
 static char *
-get_insert_query_def(Query *query)
+get_insert_query_def(Query *query, QryHier *qh)
 {
        char            buf[8192];
        char       *sep;
@@ -810,12 +1097,12 @@ get_insert_query_def(Query *query)
 
                        strcat(buf, sep);
                        sep = ", ";
-                       strcat(buf, get_tle_expr(query->rtable, 0, tle, (rt_numused > 1)));
+                       strcat(buf, get_tle_expr(qh, 0, tle, (rt_numused > 1)));
                }
                strcat(buf, ")");
        }
        else
-               strcat(buf, get_select_query_def(query));
+               strcat(buf, get_query_def(query, qh));
 
        /* ----------
         * Copy the query string into allocated space and return it
@@ -830,7 +1117,7 @@ get_insert_query_def(Query *query)
  * ----------
  */
 static char *
-get_update_query_def(Query *query)
+get_update_query_def(Query *query, QryHier *qh)
 {
        char            buf[8192];
        char       *sep;
@@ -857,7 +1144,7 @@ get_update_query_def(Query *query)
                sep = ", ";
                strcat(buf, tle->resdom->resname);
                strcat(buf, " = ");
-               strcat(buf, get_tle_expr(query->rtable, query->resultRelation,
+               strcat(buf, get_tle_expr(qh, query->resultRelation,
                                                                 tle, TRUE));
        }
 
@@ -865,7 +1152,7 @@ get_update_query_def(Query *query)
        if (query->qual != NULL)
        {
                strcat(buf, " WHERE ");
-               strcat(buf, get_rule_expr(query->rtable, query->resultRelation,
+               strcat(buf, get_rule_expr(qh, query->resultRelation,
                                                                  query->qual, TRUE));
        }
 
@@ -882,7 +1169,7 @@ get_update_query_def(Query *query)
  * ----------
  */
 static char *
-get_delete_query_def(Query *query)
+get_delete_query_def(Query *query, QryHier *qh)
 {
        char            buf[8192];
        RangeTblEntry *rte;
@@ -899,7 +1186,7 @@ get_delete_query_def(Query *query)
        if (query->qual != NULL)
        {
                strcat(buf, " WHERE ");
-               strcat(buf, get_rule_expr(query->rtable, 0, query->qual, FALSE));
+               strcat(buf, get_rule_expr(qh, 0, query->qual, FALSE));
        }
 
        /* ----------
@@ -915,7 +1202,7 @@ get_delete_query_def(Query *query)
  * ----------
  */
 static char *
-get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
+get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
 {
        char            buf[8192];
 
@@ -936,7 +1223,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
                        {
                                TargetEntry *tle = (TargetEntry *) node;
 
-                               return get_rule_expr(rtable, rt_index,
+                               return get_rule_expr(qh, rt_index,
                                                                         (Node *) (tle->expr), varprefix);
                        }
                        break;
@@ -947,7 +1234,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
 
                                strcat(buf, agg->aggname);
                                strcat(buf, "(");
-                               strcat(buf, get_rule_expr(rtable, rt_index,
+                               strcat(buf, get_rule_expr(qh, rt_index,
                                                                         (Node *) (agg->target), varprefix));
                                strcat(buf, ")");
                                return pstrdup(buf);
@@ -958,7 +1245,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
                        {
                                GroupClause *grp = (GroupClause *) node;
 
-                               return get_rule_expr(rtable, rt_index,
+                               return get_rule_expr(qh, rt_index,
                                                                         (Node *) (grp->entry), varprefix);
                        }
                        break;
@@ -974,13 +1261,13 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
                                switch (expr->opType)
                                {
                                        case OP_EXPR:
-                                               strcat(buf, get_rule_expr(rtable, rt_index,
+                                               strcat(buf, get_rule_expr(qh, rt_index,
                                                                                           (Node *) get_leftop(expr),
                                                                                                  varprefix));
                                                strcat(buf, " ");
                                                strcat(buf, get_opname(((Oper *) expr->oper)->opno));
                                                strcat(buf, " ");
-                                               strcat(buf, get_rule_expr(rtable, rt_index,
+                                               strcat(buf, get_rule_expr(qh, rt_index,
                                                                                          (Node *) get_rightop(expr),
                                                                                                  varprefix));
                                                return pstrdup(buf);
@@ -988,11 +1275,11 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
 
                                        case OR_EXPR:
                                                strcat(buf, "(");
-                                               strcat(buf, get_rule_expr(rtable, rt_index,
+                                               strcat(buf, get_rule_expr(qh, rt_index,
                                                                                           (Node *) get_leftop(expr),
                                                                                                  varprefix));
                                                strcat(buf, ") OR (");
-                                               strcat(buf, get_rule_expr(rtable, rt_index,
+                                               strcat(buf, get_rule_expr(qh, rt_index,
                                                                                          (Node *) get_rightop(expr),
                                                                                                  varprefix));
                                                strcat(buf, ")");
@@ -1001,11 +1288,11 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
 
                                        case AND_EXPR:
                                                strcat(buf, "(");
-                                               strcat(buf, get_rule_expr(rtable, rt_index,
+                                               strcat(buf, get_rule_expr(qh, rt_index,
                                                                                           (Node *) get_leftop(expr),
                                                                                                  varprefix));
                                                strcat(buf, ") AND (");
-                                               strcat(buf, get_rule_expr(rtable, rt_index,
+                                               strcat(buf, get_rule_expr(qh, rt_index,
                                                                                          (Node *) get_rightop(expr),
                                                                                                  varprefix));
                                                strcat(buf, ")");
@@ -1014,7 +1301,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
 
                                        case NOT_EXPR:
                                                strcat(buf, "NOT (");
-                                               strcat(buf, get_rule_expr(rtable, rt_index,
+                                               strcat(buf, get_rule_expr(qh, rt_index,
                                                                                           (Node *) get_leftop(expr),
                                                                                                  varprefix));
                                                strcat(buf, ")");
@@ -1022,7 +1309,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
                                                break;
 
                                        case FUNC_EXPR:
-                                               return get_func_expr(rtable, rt_index,
+                                               return get_func_expr(qh, rt_index,
                                                                                         (Expr *) node,
                                                                                         varprefix);
                                                break;
@@ -1037,7 +1324,14 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
                case T_Var:
                        {
                                Var                *var = (Var *) node;
-                               RangeTblEntry *rte = (RangeTblEntry *) nth(var->varno - 1, rtable);
+                               RangeTblEntry *rte;
+                               int sup = var->varlevelsup;
+
+                               while(sup-- > 0) qh = qh->parent;
+                               rte = (RangeTblEntry *) nth(var->varno - 1, qh->query->rtable);
+
+                               if (qh->parent == NULL && var->varlevelsup > 0)
+                                       rte = (RangeTblEntry *) nth(var->varno + 1, qh->query->rtable);
 
                                if (!strcmp(rte->refname, "*NEW*"))
                                        strcat(buf, "new.");
@@ -1047,7 +1341,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
                                                strcat(buf, "current.");
                                        else
                                        {
-                                               if (varprefix && var->varno != rt_index)
+                                               if (strcmp(rte->relname, rte->refname) != 0)
                                                {
                                                        strcat(buf, rte->refname);
                                                        strcat(buf, ".");
@@ -1069,30 +1363,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
 
                case T_SubLink:
                        {
-                               SubLink    *sublink = (SubLink *) node;
-                               Query      *query = (Query *) (sublink->subselect);
-                               List       *l;
-                               char       *sep;
-
-                               if (sublink->lefthand != NULL)
-                               {
-                                       strcat(buf, "(");
-                                       sep = "";
-                                       foreach(l, sublink->lefthand)
-                                       {
-                                               strcat(buf, sep);
-                                               sep = ", ";
-                                               strcat(buf, get_rule_expr(rtable, rt_index,
-                                                                                                 lfirst(l), varprefix));
-                                       }
-                                       strcat(buf, ") IN ");
-                               }
-
-                               strcat(buf, "(");
-                               strcat(buf, get_query_def(query));
-                               strcat(buf, ")");
-
-                               return pstrdup(buf);
+                               return get_sublink_expr(qh, rt_index, node, varprefix);
                        }
                        break;
 
@@ -1116,7 +1387,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
  * ----------
  */
 static char *
-get_func_expr(List *rtable, int rt_index, Expr *expr, bool varprefix)
+get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix)
 {
        char            buf[8192];
        HeapTuple       proctup;
@@ -1143,7 +1414,7 @@ get_func_expr(List *rtable, int rt_index, Expr *expr, bool varprefix)
                if (!strcmp(proname, "nullvalue"))
                {
                        strcpy(buf, "(");
-                       strcat(buf, get_rule_expr(rtable, rt_index, lfirst(expr->args),
+                       strcat(buf, get_rule_expr(qh, rt_index, lfirst(expr->args),
                                                                          varprefix));
                        strcat(buf, ") ISNULL");
                        return pstrdup(buf);
@@ -1151,7 +1422,7 @@ get_func_expr(List *rtable, int rt_index, Expr *expr, bool varprefix)
                if (!strcmp(proname, "nonnullvalue"))
                {
                        strcpy(buf, "(");
-                       strcat(buf, get_rule_expr(rtable, rt_index, lfirst(expr->args),
+                       strcat(buf, get_rule_expr(qh, rt_index, lfirst(expr->args),
                                                                          varprefix));
                        strcat(buf, ") NOTNULL");
                        return pstrdup(buf);
@@ -1169,7 +1440,7 @@ get_func_expr(List *rtable, int rt_index, Expr *expr, bool varprefix)
        {
                strcat(buf, sep);
                sep = ", ";
-               strcat(buf, get_rule_expr(rtable, rt_index, lfirst(l), varprefix));
+               strcat(buf, get_rule_expr(qh, rt_index, lfirst(l), varprefix));
        }
        strcat(buf, ")");
 
@@ -1194,7 +1465,7 @@ get_func_expr(List *rtable, int rt_index, Expr *expr, bool varprefix)
  * ----------
  */
 static char *
-get_tle_expr(List *rtable, int rt_index, TargetEntry *tle, bool varprefix)
+get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix)
 {
        HeapTuple       proctup;
        Form_pg_proc procStruct;
@@ -1208,12 +1479,12 @@ get_tle_expr(List *rtable, int rt_index, TargetEntry *tle, bool varprefix)
         * ----------
         */
        if (tle->resdom->restypmod < 0)
-               return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
+               return get_rule_expr(qh, rt_index, tle->expr, varprefix);
        if (nodeTag(tle->expr) != T_Expr)
-               return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
+               return get_rule_expr(qh, rt_index, tle->expr, varprefix);
        expr = (Expr *) (tle->expr);
        if (expr->opType != FUNC_EXPR)
-               return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
+               return get_rule_expr(qh, rt_index, tle->expr, varprefix);
 
        func = (Func *) (expr->oper);
 
@@ -1235,11 +1506,11 @@ get_tle_expr(List *rtable, int rt_index, TargetEntry *tle, bool varprefix)
         * ----------
         */
        if (procStruct->pronargs != 2)
-               return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
+               return get_rule_expr(qh, rt_index, tle->expr, varprefix);
        if (procStruct->prorettype != procStruct->proargtypes[0])
-               return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
+               return get_rule_expr(qh, rt_index, tle->expr, varprefix);
        if (procStruct->proargtypes[1] != INT4OID)
-               return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
+               return get_rule_expr(qh, rt_index, tle->expr, varprefix);
 
        /* ----------
         * Finally (to be totally safe) the second argument must be a
@@ -1248,15 +1519,15 @@ get_tle_expr(List *rtable, int rt_index, TargetEntry *tle, bool varprefix)
         */
        second_arg = (Const *) nth(1, expr->args);
        if (nodeTag((Node *) second_arg) != T_Const)
-               return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
+               return get_rule_expr(qh, rt_index, tle->expr, varprefix);
        if ((int4) (second_arg->constvalue) != tle->resdom->restypmod)
-               return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
+               return get_rule_expr(qh, rt_index, tle->expr, varprefix);
 
        /* ----------
         * Whow - got it. Now get rid of the padding function
         * ----------
         */
-       return get_rule_expr(rtable, rt_index, lfirst(expr->args), varprefix);
+       return get_rule_expr(qh, rt_index, lfirst(expr->args), varprefix);
 }
 
 
@@ -1274,6 +1545,7 @@ get_const_expr(Const *constval)
        char       *extval;
        bool            isnull = FALSE;
        char            buf[8192];
+       char            namebuf[64];
 
        if (constval->constisnull)
                return "NULL";
@@ -1289,7 +1561,83 @@ get_const_expr(Const *constval)
        extval = (char *) (*fmgr_faddr(&finfo_output)) (constval->constvalue,
                                                                                                        &isnull, -1);
 
-       sprintf(buf, "'%s'::%s", extval, nameout(&(typeStruct->typname)));
+       sprintf(namebuf, "::%s", nameout(&(typeStruct->typname)));
+       if (strcmp(namebuf, "::unknown") == 0)
+               namebuf[0] = '\0';
+       sprintf(buf, "'%s'%s", extval, namebuf);
+       return pstrdup(buf);
+}
+
+
+/* ----------
+ * get_sublink_expr                    - Parse back a sublink
+ * ----------
+ */
+static char *
+get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
+{
+       SubLink    *sublink = (SubLink *) node;
+       Query      *query = (Query *) (sublink->subselect);
+       Expr       *expr;
+       List       *l;
+       char       *sep;
+       char       buf[8192];
+
+       buf[0] = '\0';
+
+       if (sublink->lefthand != NULL)
+       {
+               if (length(sublink->lefthand) > 1)
+                       strcat(buf, "(");
+
+               sep = "";
+               foreach(l, sublink->lefthand)
+               {
+                       strcat(buf, sep);
+                       sep = ", ";
+                       strcat(buf, get_rule_expr(qh, rt_index,
+                                                                         lfirst(l), varprefix));
+               }
+
+               if (length(sublink->lefthand) > 1)
+                       strcat(buf, ") ");
+               else
+                       strcat(buf, " ");
+       }
+
+       switch (sublink->subLinkType) {
+               case EXISTS_SUBLINK:
+                       strcat(buf, "EXISTS ");
+                       break;
+
+               case ANY_SUBLINK:
+                       expr = (Expr *)lfirst(sublink->oper);
+                       strcat(buf, get_opname(((Oper *) (expr->oper))->opno));
+                       strcat(buf, " ANY ");
+                       break;
+
+               case ALL_SUBLINK:
+                       expr = (Expr *)lfirst(sublink->oper);
+                       strcat(buf, get_opname(((Oper *) (expr->oper))->opno));
+                       strcat(buf, " ALL ");
+                       break;
+
+               case EXPR_SUBLINK:
+                       expr = (Expr *)lfirst(sublink->oper);
+                       strcat(buf, get_opname(((Oper *) (expr->oper))->opno));
+                       strcat(buf, " ");
+                       break;
+
+               default:
+                       elog(ERROR, "unupported sublink type %d",
+                                       sublink->subLinkType);
+                       break;
+       }
+
+       strcat(buf, "(");
+       strcat(buf, get_query_def(query, qh));
+       strcat(buf, ")");
+
        return pstrdup(buf);
 }
 
index 0117885d251dc1e51dced59edab6436e013d339e..1ca47f40e2f899ce485c276ff824e4c155b89102 100644 (file)
@@ -26,7 +26,7 @@
 #
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.55 1998/09/09 18:16:36 momjian Exp $
+#    $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.56 1998/10/02 16:27:53 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -435,6 +435,7 @@ echo "REVOKE ALL on pg_shadow FROM public" | \
 
 echo "Creating view pg_rules"
 echo "CREATE TABLE xpg_rules (         \
+           tablename   name,           \
            rulename    name,           \
            definition  text);" | postgres $PGSQL_OPT template1 > /dev/null
 #move it into pg_rules
@@ -445,12 +446,18 @@ echo "UPDATE pg_type SET typname = 'pg_rules' WHERE typname = 'xpg_rules';" |\
 mv $PGDATA/base/template1/xpg_rules $PGDATA/base/template1/pg_rules
 
 echo "CREATE RULE \"_RETpg_rules\" AS ON SELECT TO pg_rules DO INSTEAD \
-           SELECT rulename, pg_get_ruledef(rulename) AS definition     \
-             FROM pg_rewrite;" | postgres $PGSQL_OPT template1 > /dev/null
+           SELECT C.relname AS tablename,                              \
+                  R.rulename AS rulename,                              \
+                  pg_get_ruledef(R.rulename) AS definition             \
+             FROM pg_rewrite R, pg_class C                             \
+                  WHERE R.rulename !~ '^_RET'                          \
+                  AND C.oid = R.ev_class;" | \
+       postgres $PGSQL_OPT template1 > /dev/null
 
 echo "Creating view pg_views"
 echo "CREATE TABLE xpg_views (         \
            viewname    name,           \
+           viewowner   name,           \
            definition  text);" | postgres $PGSQL_OPT template1 > /dev/null
 #move it into pg_views
 echo "UPDATE pg_class SET relname = 'pg_views' WHERE relname = 'xpg_views';" |\
@@ -461,11 +468,57 @@ mv $PGDATA/base/template1/xpg_views $PGDATA/base/template1/pg_views
 
 echo "CREATE RULE \"_RETpg_views\" AS ON SELECT TO pg_views DO INSTEAD \
            SELECT relname AS viewname,                                 \
+                  pg_get_userbyid(relowner) AS viewowner,              \
                   pg_get_viewdef(relname) AS definition                \
              FROM pg_class WHERE relhasrules AND                       \
                   pg_get_viewdef(relname) != 'Not a view';" | \
        postgres $PGSQL_OPT template1 > /dev/null
 
+echo "Creating view pg_tables"
+echo "CREATE TABLE xpg_tables (                \
+           tablename   name,           \
+           tableowner  name,           \
+           hasindexes  bool,           \
+           hasrules    bool,           \
+           hastriggers bool);" | postgres $PGSQL_OPT template1 > /dev/null
+#move it into pg_tables
+echo "UPDATE pg_class SET relname = 'pg_tables' WHERE relname = 'xpg_tables';" |\
+       postgres $PGSQL_OPT template1 > /dev/null
+echo "UPDATE pg_type SET typname = 'pg_tables' WHERE typname = 'xpg_tables';" |\
+       postgres $PGSQL_OPT template1 > /dev/null
+mv $PGDATA/base/template1/xpg_tables $PGDATA/base/template1/pg_tables
+
+echo "CREATE RULE \"_RETpg_tables\" AS ON SELECT TO pg_tables DO INSTEAD       \
+           SELECT relname AS tablename,                                \
+                  pg_get_userbyid(relowner) AS tableowner,             \
+                  relhasindex AS hasindexes,                           \
+                  relhasrules AS hasrules,                             \
+                  (reltriggers > 0) AS hastriggers                     \
+             FROM pg_class WHERE relkind IN ('r', 's')                 \
+                  AND pg_get_viewdef(relname) = 'Not a view';" | \
+       postgres $PGSQL_OPT template1 > /dev/null
+
+echo "Creating view pg_indexes"
+echo "CREATE TABLE xpg_indexes (       \
+           tablename   name,           \
+           indexname   name,           \
+           indexdef    text);" | postgres $PGSQL_OPT template1 > /dev/null
+#move it into pg_indexes
+echo "UPDATE pg_class SET relname = 'pg_indexes' WHERE relname = 'xpg_indexes';" |\
+       postgres $PGSQL_OPT template1 > /dev/null
+echo "UPDATE pg_type SET typname = 'pg_indexes' WHERE typname = 'xpg_indexes';" |\
+       postgres $PGSQL_OPT template1 > /dev/null
+mv $PGDATA/base/template1/xpg_indexes $PGDATA/base/template1/pg_indexes
+
+echo "CREATE RULE \"_RETpg_indexes\" AS ON SELECT TO pg_indexes DO INSTEAD     \
+           SELECT C.relname AS tablename,                              \
+                  I.relname AS indexname,                              \
+                  pg_get_indexdef(X.indexrelid) AS indexdef            \
+             FROM pg_index X, pg_class C, pg_class I                   \
+                  WHERE C.oid = X.indrelid                             \
+                  AND I.oid = X.indexrelid;" | \
+       postgres $PGSQL_OPT template1 > /dev/null
+
 echo "Loading pg_description"
 echo "copy pg_description from '$TEMPLATE_DESCR'" | \
        postgres $PGSQL_OPT template1 > /dev/null
index 06cb99d0c15d9e7d21a6f930b40a129d4bd78e7c..1f8ca515837227b5444a887f7f165ec2bba085f1 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.69 1998/09/01 04:35:10 momjian Exp $
+ * $Id: pg_proc.h,v 1.70 1998/10/02 16:27:55 momjian Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -2040,6 +2040,10 @@ DATA(insert OID = 1640 (  pg_get_ruledef    PGUID 11 f t f 1 f 25 "19" 100 0 0 1
 DESCR("source text of a rule");
 DATA(insert OID = 1641 (  pg_get_viewdef          PGUID 11 f t f 1 f 25 "19" 100 0 0 100  foo bar ));
 DESCR("select statement of a view");
+DATA(insert OID = 1642 (  pg_get_userbyid         PGUID 11 f t f 1 f 19 "23" 100 0 0 100  foo bar ));
+DESCR("user name by UID (with fallback)");
+DATA(insert OID = 1643 (  pg_get_indexdef         PGUID 11 f t f 1 f 25 "26" 100 0 0 100  foo bar ));
+DESCR("index description");
 
 /*
  * prototypes for functions pg_proc.c
index b51b02463edb90953dde5325f38455532c19f45a..ad258d9063e214b2c2c886df881b96cf63c3bbc1 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: locks.h,v 1.9 1998/09/01 04:37:57 momjian Exp $
+ * $Id: locks.h,v 1.10 1998/10/02 16:27:58 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,5 +19,6 @@
 
 extern List *matchLocks(CmdType event, RuleLock *rulelocks, int varno,
                   Query *parsetree);
+extern void checkLockPerms(List *locks, Query *parsetree, int rt_index);
 
 #endif  /* LOCKS_H */
index 447b1499fafee74a68629785891c355a064ce345..f77a532d6e2e7f4762a8e98468cea71051185395 100644 (file)
@@ -671,3 +671,181 @@ QUERY: select * from rtest_nothn3;
 200|OK
 (2 rows)
 
+QUERY: create table rtest_view1 (a int4, b text, v bool);
+QUERY: create table rtest_view2 (a int4);
+QUERY: create table rtest_view3 (a int4, b text);
+QUERY: create table rtest_view4 (a int4, b text, c int4);
+QUERY: create view rtest_vview1 as select a, b from rtest_view1 X
+       where 0 < (select count(*) from rtest_view2 Y where Y.a = X.a);
+QUERY: create view rtest_vview2 as select a, b from rtest_view1 where v;
+QUERY: create view rtest_vview3 as select a, b from rtest_vview2 X
+       where 0 < (select count(*) from rtest_view2 Y where Y.a = X.a);
+QUERY: create view rtest_vview4 as select X.a, X.b, count(Y.a) as refcount
+       from rtest_view1 X, rtest_view2 Y
+       where X.a = Y.a
+       group by X.a, X.b;
+QUERY: create function rtest_viewfunc1(int4) returns int4 as
+       'select count(*) from rtest_view2 where a = $1'
+       language 'sql';
+QUERY: create view rtest_vview5 as select a, b, rtest_viewfunc1(a) as refcount
+       from rtest_view1;
+QUERY: insert into rtest_view1 values (1, 'item 1', 't');
+QUERY: insert into rtest_view1 values (2, 'item 2', 't');
+QUERY: insert into rtest_view1 values (3, 'item 3', 't');
+QUERY: insert into rtest_view1 values (4, 'item 4', 'f');
+QUERY: insert into rtest_view1 values (5, 'item 5', 't');
+QUERY: insert into rtest_view1 values (6, 'item 6', 'f');
+QUERY: insert into rtest_view1 values (7, 'item 7', 't');
+QUERY: insert into rtest_view1 values (8, 'item 8', 't');
+QUERY: insert into rtest_view2 values (2);
+QUERY: insert into rtest_view2 values (2);
+QUERY: insert into rtest_view2 values (4);
+QUERY: insert into rtest_view2 values (5);
+QUERY: insert into rtest_view2 values (7);
+QUERY: insert into rtest_view2 values (7);
+QUERY: insert into rtest_view2 values (7);
+QUERY: insert into rtest_view2 values (7);
+QUERY: select * from rtest_vview1;
+a|b     
+-+------
+2|item 2
+4|item 4
+5|item 5
+7|item 7
+(4 rows)
+
+QUERY: select * from rtest_vview2;
+a|b     
+-+------
+1|item 1
+2|item 2
+3|item 3
+5|item 5
+7|item 7
+8|item 8
+(6 rows)
+
+QUERY: select * from rtest_vview3;
+a|b     
+-+------
+2|item 2
+5|item 5
+7|item 7
+(3 rows)
+
+QUERY: select * from rtest_vview4;
+a|b     |refcount
+-+------+--------
+2|item 2|       2
+4|item 4|       1
+5|item 5|       1
+7|item 7|       4
+(4 rows)
+
+QUERY: select * from rtest_vview5;
+a|b     |refcount
+-+------+--------
+1|item 1|       0
+2|item 2|       2
+3|item 3|       0
+4|item 4|       1
+5|item 5|       1
+6|item 6|       0
+7|item 7|       4
+8|item 8|       0
+(8 rows)
+
+QUERY: insert into rtest_view3 select * from rtest_vview1 where a < 7;
+QUERY: select * from rtest_view3;
+a|b     
+-+------
+2|item 2
+4|item 4
+5|item 5
+(3 rows)
+
+QUERY: delete from rtest_view3;
+QUERY: insert into rtest_view3 select * from rtest_vview2 where a != 5 and b !~ '2';
+QUERY: select * from rtest_view3;
+a|b     
+-+------
+1|item 1
+3|item 3
+7|item 7
+8|item 8
+(4 rows)
+
+QUERY: delete from rtest_view3;
+QUERY: insert into rtest_view3 select * from rtest_vview3;
+QUERY: select * from rtest_view3;
+a|b     
+-+------
+2|item 2
+5|item 5
+7|item 7
+(3 rows)
+
+QUERY: delete from rtest_view3;
+QUERY: insert into rtest_view4 select * from rtest_vview4 where 3 > refcount;
+QUERY: select * from rtest_view4;
+a|b     |c
+-+------+-
+2|item 2|2
+4|item 4|1
+5|item 5|1
+(3 rows)
+
+QUERY: delete from rtest_view4;
+QUERY: insert into rtest_view4 select * from rtest_vview5 where a > 2 and refcount = 0;
+QUERY: select * from rtest_view4;
+a|b     |c
+-+------+-
+3|item 3|0
+6|item 6|0
+8|item 8|0
+(3 rows)
+
+QUERY: delete from rtest_view4;
+QUERY: create table rtest_comp (
+       part    text,
+       unit    char(4),
+       size    float
+);
+QUERY: create table rtest_unitfact (
+       unit    char(4),
+       factor  float
+);
+QUERY: create view rtest_vcomp as
+       select X.part, (X.size * Y.factor) as size_in_cm
+                       from rtest_comp X, rtest_unitfact Y
+                       where X.unit = Y.unit;
+QUERY: insert into rtest_unitfact values ('m', 100.0);
+QUERY: insert into rtest_unitfact values ('cm', 1.0);
+QUERY: insert into rtest_unitfact values ('inch', 2.54);
+QUERY: insert into rtest_comp values ('p1', 'm', 5.0);
+QUERY: insert into rtest_comp values ('p2', 'm', 3.0);
+QUERY: insert into rtest_comp values ('p3', 'cm', 5.0);
+QUERY: insert into rtest_comp values ('p4', 'cm', 15.0);
+QUERY: insert into rtest_comp values ('p5', 'inch', 7.0);
+QUERY: insert into rtest_comp values ('p6', 'inch', 4.4);
+QUERY: select * from rtest_vcomp order by part;
+part|size_in_cm
+----+----------
+p1  |       500
+p2  |       300
+p3  |         5
+p4  |        15
+p5  |     17.78
+p6  |    11.176
+(6 rows)
+
+QUERY: select * from rtest_vcomp where size_in_cm > 10.0 order by size_in_cm using >;
+part|size_in_cm
+----+----------
+p1  |       500
+p2  |       300
+p5  |     17.78
+p4  |        15
+p6  |    11.176
+(5 rows)
+
index 6ca18775863183f15dc396d86196a033290f61bf..8ffefd5be00fa8b22b70f6831c4a87300a209b18 100644 (file)
@@ -404,3 +404,100 @@ insert into rtest_nothn2 select * from rtest_nothn4;
 select * from rtest_nothn2;
 select * from rtest_nothn3;
 
+create table rtest_view1 (a int4, b text, v bool);
+create table rtest_view2 (a int4);
+create table rtest_view3 (a int4, b text);
+create table rtest_view4 (a int4, b text, c int4);
+create view rtest_vview1 as select a, b from rtest_view1 X 
+       where 0 < (select count(*) from rtest_view2 Y where Y.a = X.a);
+create view rtest_vview2 as select a, b from rtest_view1 where v;
+create view rtest_vview3 as select a, b from rtest_vview2 X
+       where 0 < (select count(*) from rtest_view2 Y where Y.a = X.a);
+create view rtest_vview4 as select X.a, X.b, count(Y.a) as refcount
+       from rtest_view1 X, rtest_view2 Y
+       where X.a = Y.a
+       group by X.a, X.b;
+create function rtest_viewfunc1(int4) returns int4 as
+       'select count(*) from rtest_view2 where a = $1'
+       language 'sql';
+create view rtest_vview5 as select a, b, rtest_viewfunc1(a) as refcount
+       from rtest_view1;
+
+insert into rtest_view1 values (1, 'item 1', 't');
+insert into rtest_view1 values (2, 'item 2', 't');
+insert into rtest_view1 values (3, 'item 3', 't');
+insert into rtest_view1 values (4, 'item 4', 'f');
+insert into rtest_view1 values (5, 'item 5', 't');
+insert into rtest_view1 values (6, 'item 6', 'f');
+insert into rtest_view1 values (7, 'item 7', 't');
+insert into rtest_view1 values (8, 'item 8', 't');
+
+insert into rtest_view2 values (2);
+insert into rtest_view2 values (2);
+insert into rtest_view2 values (4);
+insert into rtest_view2 values (5);
+insert into rtest_view2 values (7);
+insert into rtest_view2 values (7);
+insert into rtest_view2 values (7);
+insert into rtest_view2 values (7);
+
+select * from rtest_vview1;
+select * from rtest_vview2;
+select * from rtest_vview3;
+select * from rtest_vview4;
+select * from rtest_vview5;
+
+insert into rtest_view3 select * from rtest_vview1 where a < 7;
+select * from rtest_view3;
+delete from rtest_view3;
+
+insert into rtest_view3 select * from rtest_vview2 where a != 5 and b !~ '2';
+select * from rtest_view3;
+delete from rtest_view3;
+
+insert into rtest_view3 select * from rtest_vview3;
+select * from rtest_view3;
+delete from rtest_view3;
+
+insert into rtest_view4 select * from rtest_vview4 where 3 > refcount;
+select * from rtest_view4;
+delete from rtest_view4;
+
+insert into rtest_view4 select * from rtest_vview5 where a > 2 and refcount = 0;
+select * from rtest_view4;
+delete from rtest_view4;
+--
+-- Test for computations in views
+--
+create table rtest_comp (
+       part    text,
+       unit    char(4),
+       size    float
+);
+
+
+create table rtest_unitfact (
+       unit    char(4),
+       factor  float
+);
+
+create view rtest_vcomp as 
+       select X.part, (X.size * Y.factor) as size_in_cm
+                       from rtest_comp X, rtest_unitfact Y
+                       where X.unit = Y.unit;
+
+
+insert into rtest_unitfact values ('m', 100.0);
+insert into rtest_unitfact values ('cm', 1.0);
+insert into rtest_unitfact values ('inch', 2.54);
+
+insert into rtest_comp values ('p1', 'm', 5.0);
+insert into rtest_comp values ('p2', 'm', 3.0);
+insert into rtest_comp values ('p3', 'cm', 5.0);
+insert into rtest_comp values ('p4', 'cm', 15.0);
+insert into rtest_comp values ('p5', 'inch', 7.0);
+insert into rtest_comp values ('p6', 'inch', 4.4);
+
+select * from rtest_vcomp order by part;
+
+select * from rtest_vcomp where size_in_cm > 10.0 order by size_in_cm using >;