Allow
authorHiroshi Inoue <inoue@tpf.co.jp>
Wed, 22 May 2002 07:46:58 +0000 (07:46 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Wed, 22 May 2002 07:46:58 +0000 (07:46 +0000)
  CREATE VIEW as SELECT CTID, ....
  SELECT currtid( a view, ..).

src/backend/catalog/heap.c
src/backend/utils/adt/tid.c

index c206196bfcc49082dade1667cae906580bbb1194..546acd243b472c5af4ebc27d1bdec75532ca870c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.201 2002/05/21 22:05:53 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.202 2002/05/22 07:46:58 inoue Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -353,7 +353,7 @@ heap_storage_create(Relation rel)
  * --------------------------------
  */
 static void
-CheckAttributeNames(TupleDesc tupdesc, bool relhasoids)
+CheckAttributeNames(TupleDesc tupdesc, bool relhasoids, int relkind)
 {
        int                     i;
        int                     j;
@@ -365,17 +365,18 @@ CheckAttributeNames(TupleDesc tupdesc, bool relhasoids)
         * also, warn user if attribute to be created has an unknown typid
         * (usually as a result of a 'retrieve into' - jolly
         */
-       for (i = 0; i < natts; i++)
-       {
-               if (SystemAttributeByName(NameStr(tupdesc->attrs[i]->attname),
+       if (relkind != RELKIND_VIEW)
+               for (i = 0; i < natts; i++)
+               {
+                       if (SystemAttributeByName(NameStr(tupdesc->attrs[i]->attname),
                                                                  relhasoids) != NULL)
-                       elog(ERROR, "name of column \"%s\" conflicts with an existing system column",
+                               elog(ERROR, "name of column \"%s\" conflicts with an existing system column",
                                 NameStr(tupdesc->attrs[i]->attname));
-               if (tupdesc->attrs[i]->atttypid == UNKNOWNOID)
-                       elog(WARNING, "Attribute '%s' has an unknown type"
+                       if (tupdesc->attrs[i]->atttypid == UNKNOWNOID)
+                               elog(WARNING, "Attribute '%s' has an unknown type"
                                 "\n\tProceeding with relation creation anyway",
                                 NameStr(tupdesc->attrs[i]->attname));
-       }
+               }
 
        /*
         * next check for repeated attribute names
@@ -402,7 +403,8 @@ CheckAttributeNames(TupleDesc tupdesc, bool relhasoids)
 static void
 AddNewAttributeTuples(Oid new_rel_oid,
                                          TupleDesc tupdesc,
-                                         bool relhasoids)
+                                         bool relhasoids,
+                                         int   relkind)
 {
        Form_pg_attribute *dpp;
        int                     i;
@@ -453,36 +455,36 @@ AddNewAttributeTuples(Oid new_rel_oid,
         * next we add the system attributes.  Skip OID if rel has no OIDs.
         */
        dpp = SysAtt;
-       for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++)
-       {
-               if (relhasoids || (*dpp)->attnum != ObjectIdAttributeNumber)
+       if (relkind != RELKIND_VIEW)
+               for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++)
                {
-                       Form_pg_attribute attStruct;
+                       if (relhasoids || (*dpp)->attnum != ObjectIdAttributeNumber)
+                       {
+                               Form_pg_attribute attStruct;
 
-                       tup = heap_addheader(Natts_pg_attribute,
+                               tup = heap_addheader(Natts_pg_attribute,
                                                                 ATTRIBUTE_TUPLE_SIZE,
                                                                 (void *) *dpp);
 
-                       /* Fill in the correct relation OID in the copied tuple */
-                       attStruct = (Form_pg_attribute) GETSTRUCT(tup);
-                       attStruct->attrelid = new_rel_oid;
+                               /* Fill in the correct relation OID in the copied tuple */
+                               attStruct = (Form_pg_attribute) GETSTRUCT(tup);
+                               attStruct->attrelid = new_rel_oid;
 
-                       /*
-                        * Unneeded since they should be OK in the constant data
-                        * anyway
-                        */
-                       /* attStruct->attstattarget = 0; */
-                       /* attStruct->attcacheoff = -1; */
+                               /*
+                                * Unneeded since they should be OK in the constant data
+                                * anyway
+                                */
+                               /* attStruct->attstattarget = 0; */
+                               /* attStruct->attcacheoff = -1; */
 
-                       simple_heap_insert(rel, tup);
+                               simple_heap_insert(rel, tup);
 
-                       if (hasindex)
-                               CatalogIndexInsert(idescs, Num_pg_attr_indices, rel, tup);
+                               if (hasindex)
+                                       CatalogIndexInsert(idescs, Num_pg_attr_indices, rel, tup);
 
-                       heap_freetuple(tup);
+                               heap_freetuple(tup);
+                       }
                }
-               dpp++;
-       }
 
        /*
         * close pg_attribute indices
@@ -664,7 +666,7 @@ heap_create_with_catalog(const char *relname,
                elog(ERROR, "Number of columns is out of range (1 to %d)",
                         MaxHeapAttributeNumber);
 
-       CheckAttributeNames(tupdesc, relhasoids);
+       CheckAttributeNames(tupdesc, relhasoids, relkind);
 
        if (get_relname_relid(relname, relnamespace))
                elog(ERROR, "Relation '%s' already exists", relname);
@@ -717,7 +719,7 @@ heap_create_with_catalog(const char *relname,
         * now add tuples to pg_attribute for the attributes in our new
         * relation.
         */
-       AddNewAttributeTuples(new_rel_oid, new_rel_desc->rd_att, relhasoids);
+       AddNewAttributeTuples(new_rel_oid, new_rel_desc->rd_att, relhasoids, relkind);
 
        /*
         * store constraints and defaults passed in the tupdesc, if any.
index 9f3dcf8fa1606cc2ba86b18e6ea48b94d05b2f77..5b111acf8f4554cbc4944bb3cb92352fd018d107 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.29 2002/03/30 01:02:41 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.30 2002/05/22 07:46:58 inoue Exp $
  *
  * NOTES
  *       input routine largely stolen from boxin().
@@ -21,6 +21,7 @@
 #include "access/heapam.h"
 #include "catalog/namespace.h"
 #include "utils/builtins.h"
+#include "catalog/pg_type.h"
 
 #define DatumGetItemPointer(X)  ((ItemPointer) DatumGetPointer(X))
 #define ItemPointerGetDatum(X)  PointerGetDatum(X)
@@ -133,6 +134,65 @@ setLastTid(const ItemPointer tid)
        Current_last_tid = *tid;
 }
 
+/*
+ *     Handle CTIDs of views.
+ *             CTID should be defined in the view and it must
+ *             correspond to the CTID of a base relation.
+ */
+static Datum
+currtid_for_view(Relation viewrel, ItemPointer tid) 
+{
+       TupleDesc       att = RelationGetDescr(viewrel);
+       RuleLock        *rulelock;
+       RewriteRule     *rewrite;
+       int     i, natts = att->natts, tididx = -1;
+
+       for (i = 0; i < natts ; i++)
+       {
+               if (strcasecmp(NameStr(att->attrs[i]->attname), "ctid") == 0)
+               {
+                       if (att->attrs[i]->atttypid != TIDOID)
+                               elog(ERROR, "ctid isn't of type TID");
+                       tididx = i;
+               }
+       }
+       if (tididx < 0)
+               elog(ERROR, "currtid can't handle views with no CTID");
+       if (rulelock = viewrel->rd_rules, !rulelock)
+               elog(ERROR, "the view has no rules");
+       for (i = 0; i < rulelock->numLocks; i++)
+       {
+               rewrite = rulelock->rules[i];
+               if (rewrite->event == CMD_SELECT)
+               {
+                       Query   *query;
+                       TargetEntry *tle;
+
+                       if (length(rewrite->actions) != 1)
+                               elog(ERROR, "only one select rule is allowed in views");
+                       query = (Query *) lfirst(rewrite->actions);
+                       tle = (TargetEntry *) nth(tididx, query->targetList);
+                       if (tle && tle->expr && nodeTag(tle->expr) == T_Var)
+                       {
+                               Var *var = (Var *) tle->expr;
+                               RangeTblEntry *rte;
+                               if (var->varno > 0 && var->varno < INNER && var->varattno == SelfItemPointerAttributeNumber)
+                               {
+                                       rte = (RangeTblEntry *) nth(var->varno - 1, query->rtable);
+                                       if (rte)
+                                       {
+                                               heap_close(viewrel, AccessShareLock);
+                                               return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
+                                       }
+                               }
+                       }
+                       break;
+               }
+       }
+       elog(ERROR, "currtid can't handle this view");
+       return (Datum) 0;
+}
+
 Datum
 currtid_byreloid(PG_FUNCTION_ARGS)
 {
@@ -149,6 +209,8 @@ currtid_byreloid(PG_FUNCTION_ARGS)
        }
 
        rel = heap_open(reloid, AccessShareLock);
+       if (rel->rd_rel->relkind == RELKIND_VIEW)
+               return currtid_for_view(rel, tid);
 
        ItemPointerCopy(tid, result);
        heap_get_latest_tid(rel, SnapshotNow, result);
@@ -170,6 +232,8 @@ currtid_byrelname(PG_FUNCTION_ARGS)
        relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname,
                                                                                                                "currtid_byrelname"));
        rel = heap_openrv(relrv, AccessShareLock);
+       if (rel->rd_rel->relkind == RELKIND_VIEW)
+               return currtid_for_view(rel, tid);
 
        result = (ItemPointer) palloc(sizeof(ItemPointerData));
        ItemPointerCopy(tid, result);