ADD/DROP INHERITS - Mailing list pgsql-patches

From Greg Stark
Subject ADD/DROP INHERITS
Date
Msg-id 878xo6geb4.fsf@stark.xeocode.com
Whole thread Raw
Responses Re: ADD/DROP INHERITS  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-patches
This is where I am with the ADD/DROP INHERITS patch now.

1) The syntax is:

   ALTER TABLE child INHERIT parent
   ALTER TABLE child NO INHERIT parent

   no new reserved words, no conflicts, no complicated grammar productions in
   gram.y to confuse people in the future.

2) Dependencies are being added and dropped by trawling directly through
   pg_depend rather than having dependencies on pg_depend lines.

3) Constraints are being compared by reverse-compiling the definition and
   comparing the result with strcmp.

   I also haven't checked the constraint name. To do so it would make sense to
   use a small hash table. I see something called dynahash in the source tree.
   Is it meant for these kind of quick small tasks?

   I'm ignoring unique, primary key, and foreign key constraints on the theory
   that these things don't really work on inherited tables yet anyways. Also
   NONE of these are copied when you create a new inherited table so it would
   mean that you wouldn't be able to re-add a freshly automatically generated
   child after removing it.

   Actually a foreign key constraint *from* a child table work fine. But like
   I said it currently isn't being copied when you create a child table. We
   could consider fixing that and adding a check here for matching foreign key
   constraints at the same time.




Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.184
diff -u -p -c -r1.184 tablecmds.c
cvs diff: conflicting specifications of output style
*** src/backend/commands/tablecmds.c    10 May 2006 23:18:39 -0000    1.184
--- src/backend/commands/tablecmds.c    9 Jun 2006 21:28:13 -0000
*************** typedef struct NewColumnValue
*** 159,166 ****
--- 159,168 ----
  static void truncate_check_rel(Relation rel);
  static List *MergeAttributes(List *schema, List *supers, bool istemp,
                  List **supOids, List **supconstr, int *supOidCount);
+ static void MergeAttributesIntoExisting(Relation rel, Relation relation);
  static bool change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);
  static void StoreCatalogInheritance(Oid relationId, List *supers);
+ static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, int16 seqNumber, Relation catalogRelation);
  static int    findAttrByName(const char *attributeName, List *schema);
  static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
  static bool needs_toast_table(Relation rel);
*************** static void ATPrepSetTableSpace(AlteredT
*** 246,251 ****
--- 248,255 ----
  static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace);
  static void ATExecEnableDisableTrigger(Relation rel, char *trigname,
                             bool enable, bool skip_system);
+ static void ATExecAddInherits(Relation rel, RangeVar *parent);
+ static void ATExecDropInherits(Relation rel, RangeVar *parent);
  static void copy_relation_data(Relation rel, SMgrRelation dst);
  static void update_ri_trigger_args(Oid relid,
                         const char *oldname,
*************** static void
*** 1156,1165 ****
  StoreCatalogInheritance(Oid relationId, List *supers)
  {
      Relation    relation;
-     TupleDesc    desc;
      int16        seqNumber;
      ListCell   *entry;
-     HeapTuple    tuple;

      /*
       * sanity checks
--- 1160,1167 ----
*************** StoreCatalogInheritance(Oid relationId,
*** 1179,1194 ****
       * anymore, there's no need to look for indirect ancestors.)
       */
      relation = heap_open(InheritsRelationId, RowExclusiveLock);
-     desc = RelationGetDescr(relation);

      seqNumber = 1;
      foreach(entry, supers)
      {
!         Oid            parentOid = lfirst_oid(entry);
          Datum        datum[Natts_pg_inherits];
          char        nullarr[Natts_pg_inherits];
          ObjectAddress childobject,
                      parentobject;

          datum[0] = ObjectIdGetDatum(relationId);        /* inhrel */
          datum[1] = ObjectIdGetDatum(parentOid); /* inhparent */
--- 1181,1206 ----
       * anymore, there's no need to look for indirect ancestors.)
       */
      relation = heap_open(InheritsRelationId, RowExclusiveLock);

      seqNumber = 1;
      foreach(entry, supers)
      {
!         StoreCatalogInheritance1(relationId, lfirst_oid(entry), seqNumber, relation);
!         seqNumber += 1;
!     }
!
!     heap_close(relation, RowExclusiveLock);
! }
!
! static void
! StoreCatalogInheritance1(Oid relationId, Oid parentOid, int16 seqNumber, Relation relation)
! {
          Datum        datum[Natts_pg_inherits];
          char        nullarr[Natts_pg_inherits];
          ObjectAddress childobject,
                      parentobject;
+         HeapTuple    tuple;
+         TupleDesc desc = RelationGetDescr(relation);

          datum[0] = ObjectIdGetDatum(relationId);        /* inhrel */
          datum[1] = ObjectIdGetDatum(parentOid); /* inhparent */
*************** StoreCatalogInheritance(Oid relationId,
*** 1223,1232 ****
           */
          setRelhassubclassInRelation(parentOid, true);

-         seqNumber += 1;
-     }
-
-     heap_close(relation, RowExclusiveLock);
  }

  /*
--- 1235,1240 ----
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2053,2058 ****
--- 2061,2068 ----
          case AT_DisableTrig:    /* DISABLE TRIGGER variants */
          case AT_DisableTrigAll:
          case AT_DisableTrigUser:
+         case AT_AddInherits:
+         case AT_DropInherits:
              ATSimplePermissions(rel, false);
              /* These commands never recurse */
              /* No command-specific prep needed */
*************** ATExecCmd(AlteredTableInfo *tab, Relatio
*** 2233,2238 ****
--- 2243,2254 ----
          case AT_DisableTrigUser:        /* DISABLE TRIGGER USER */
              ATExecEnableDisableTrigger(rel, NULL, false, true);
              break;
+         case AT_DropInherits:
+             ATExecDropInherits(rel, cmd->parent);
+             break;
+         case AT_AddInherits:
+             ATExecAddInherits(rel, cmd->parent);
+             break;
          default:                /* oops */
              elog(ERROR, "unrecognized alter table type: %d",
                   (int) cmd->subtype);
*************** ATExecEnableDisableTrigger(Relation rel,
*** 5880,5885 ****
--- 5896,6274 ----
      EnableDisableTrigger(rel, trigname, enable, skip_system);
  }

+ static bool
+ list_member_string(List *list, void *datum)
+ {
+     ListCell   *cell;
+
+     foreach(cell, list) {
+         if (!strcmp(lfirst(cell), datum))
+             return true;
+     }
+     return false;
+ }
+
+ static void
+ ATExecAddInherits(Relation rel, RangeVar *parent)
+ {
+     Relation     relation, catalogRelation;
+     SysScanDesc scan;
+     ScanKeyData key;
+     HeapTuple     inheritsTuple, constraintTuple;
+     int4         inhseqno;
+     ListCell       *child;
+     List         *children, *constraints;
+     TupleDesc       tupleDesc;
+
+     relation = heap_openrv(parent, AccessShareLock); /* XXX is this enough locking? */
+     if (relation->rd_rel->relkind != RELKIND_RELATION)
+         ereport(ERROR,
+                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                  errmsg("inherited relation \"%s\" is not a table",
+                         parent->relname)));
+
+
+     /* Permanent rels cannot inherit from temporary ones */
+     if (!rel->rd_istemp && isTempNamespace(RelationGetNamespace(relation)))
+         ereport(ERROR,
+                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                  errmsg("cannot inherit from temporary relation \"%s\"",
+                         parent->relname)));
+
+     if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
+         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+                        RelationGetRelationName(relation));
+
+     /* If parent has OIDs then all children must have OIDs */
+     if (relation->rd_rel->relhasoids && !rel->rd_rel->relhasoids)
+         ereport(ERROR,
+                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                  errmsg("table \"%s\" without OIDs cannot inherit from table \"%s\" with OIDs",
+                         RelationGetRelationName(rel), parent->relname)));
+
+     /*
+      * Reject duplications in the list of parents. -- this is the same check as
+      * when creating a table, but maybe we should check for the parent anywhere
+      * higher in the inheritance structure?
+      */
+     catalogRelation = heap_open(InheritsRelationId, RowExclusiveLock);
+     ScanKeyInit(&key,
+                 Anum_pg_inherits_inhrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(RelationGetRelid(rel)));
+     scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true, SnapshotNow, 1, &key);
+     inhseqno = 0; /* inhseqno sequences are supposed to start at 1 */
+     while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
+     {
+         Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
+         if (inh->inhparent == RelationGetRelid(relation))
+             ereport(ERROR,
+                     (errcode(ERRCODE_DUPLICATE_TABLE),
+                      errmsg("inherited relation \"%s\" duplicated",
+                             parent->relname)));
+         /* Accumulate the max seqno -- BUT if we spot a hole use it instead
+          * This means if you DROP and ADD the same parent the order will be maintained
+          * which will mean pg_dump won't gratuitously reorder your columns.
+          */
+         if (inh->inhseqno == inhseqno+1)
+             inhseqno = inh->inhseqno;
+     }
+     systable_endscan(scan);
+     heap_close(catalogRelation, RowExclusiveLock);
+
+     /* Get children because we have to manually recurse and also because we
+      * have to check for recursive inheritance graphs */
+
+     /* this routine is actually in the planner */
+     children = find_all_inheritors(RelationGetRelid(rel));
+
+     if (list_member_oid(children, RelationGetRelid(relation)))
+         ereport(ERROR,
+                 (errcode(ERRCODE_DUPLICATE_TABLE),
+                  errmsg("circular inheritance structure found, \"%s\" is already a child of \"%s\"",
+                         parent->relname, RelationGetRelationName(rel))));
+
+     foreach(child, children)
+         {
+             Oid            childrelid = lfirst_oid(child);
+             Relation    childrel;
+
+             childrel = relation_open(childrelid, AccessExclusiveLock);
+             MergeAttributesIntoExisting(childrel, relation);
+             relation_close(childrel, NoLock);
+         }
+
+
+
+     /* Now check the constraints */
+     /* First gather up the child's constraint definitions */
+     catalogRelation = heap_open(ConstraintRelationId, AccessShareLock);
+     tupleDesc = RelationGetDescr(catalogRelation);
+
+     ScanKeyInit(&key,
+                 Anum_pg_constraint_conrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(RelationGetRelid(rel)));
+     scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId, true, SnapshotNow, 1, &key);
+     constraints = NIL;
+     while (HeapTupleIsValid(constraintTuple = systable_getnext(scan))) {
+         Form_pg_constraint con = (Form_pg_constraint)(GETSTRUCT(constraintTuple));
+         bool isnull;
+         Datum consrc;
+         char *consrc_string;
+         if (con->contype != 'c')
+             continue;
+         consrc = fastgetattr(constraintTuple, Anum_pg_constraint_conbin, tupleDesc, &isnull);
+         if (isnull)
+             continue;
+         consrc = DirectFunctionCall2(pg_get_expr, consrc, ObjectIdGetDatum(con->conrelid));
+         consrc_string = DatumGetCString(DirectFunctionCall1(textout, consrc));
+         elog(DEBUG1, "Found child constraint \"%s\": \"%s\"", NameStr(con->conname), consrc_string);
+         constraints = lappend(constraints, consrc_string);
+     }
+     systable_endscan(scan);
+
+     ScanKeyInit(&key,
+                 Anum_pg_constraint_conrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(RelationGetRelid(relation)));
+     scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId, true, SnapshotNow, 1, &key);
+     while (HeapTupleIsValid(constraintTuple = systable_getnext(scan))) {
+         Form_pg_constraint con = (Form_pg_constraint)(GETSTRUCT(constraintTuple));
+         bool isnull;
+         Datum consrc;
+         char *consrc_string;
+         if (con->contype != 'c')
+             continue;
+         consrc = fastgetattr(constraintTuple, Anum_pg_constraint_conbin, tupleDesc, &isnull);
+         if (isnull)
+             continue;
+         consrc = DirectFunctionCall2(pg_get_expr, consrc, ObjectIdGetDatum(con->conrelid));
+         consrc_string = DatumGetCString(DirectFunctionCall1(textout, consrc));
+         elog(DEBUG1, "Looking for parent constraint \"%s\": \"%s\"", NameStr(con->conname), consrc_string);
+
+         if (!list_member_string(constraints, consrc_string))
+             ereport(ERROR,
+                     (errcode(ERRCODE_DATATYPE_MISMATCH),
+                      errmsg("child table missing constraint matching parent table constraint \"%s\"",
+                             NameStr(con->conname))));
+     }
+     systable_endscan(scan);
+
+     heap_close(catalogRelation, AccessShareLock);
+
+     catalogRelation = heap_open(InheritsRelationId, RowExclusiveLock);
+     StoreCatalogInheritance1(RelationGetRelid(rel), RelationGetRelid(relation), inhseqno+1, catalogRelation);
+     heap_close(catalogRelation, RowExclusiveLock);
+
+     heap_close(relation, AccessShareLock);
+ }
+
+ static void
+ MergeAttributesIntoExisting(Relation rel, Relation relation)
+ {
+     Relation     attrdesc;
+     AttrNumber    parent_attno, child_attno;
+     TupleDesc    tupleDesc;
+     TupleConstr *constr;
+     HeapTuple     tuple;
+
+     child_attno = RelationGetNumberOfAttributes(rel);
+
+     tupleDesc = RelationGetDescr(relation);
+     constr = tupleDesc->constr;
+
+     for (parent_attno = 1; parent_attno <= tupleDesc->natts;
+          parent_attno++)
+     {
+         Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];
+         char       *attributeName = NameStr(attribute->attname);
+
+         /* Ignore dropped columns in the parent. */
+         if (attribute->attisdropped)
+             continue;
+
+         /* Does it conflict with an existing column? */
+         attrdesc = heap_open(AttributeRelationId, RowExclusiveLock);
+
+         tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), attributeName);
+         if (HeapTupleIsValid(tuple)) {
+             /*
+              * Yes, try to merge the two column definitions. They must
+              * have the same type and typmod.
+              */
+             Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
+             if (attribute->atttypid  != childatt->atttypid ||
+                 attribute->atttypmod != childatt->atttypmod ||
+                 (attribute->attnotnull && !childatt->attnotnull))
+                 ereport(ERROR,
+                         (errcode(ERRCODE_DATATYPE_MISMATCH),
+                          errmsg("child table \"%s\" has different type for column \"%s\"",
+                                 RelationGetRelationName(rel), NameStr(attribute->attname))));
+
+             childatt->attinhcount++;
+             simple_heap_update(attrdesc, &tuple->t_self, tuple);
+             CatalogUpdateIndexes(attrdesc, tuple); /* XXX strength reduce openindexes to outside loop? */
+             heap_freetuple(tuple);
+
+             /* We don't touch default at all since we're not making any other
+              * DDL changes to the child */
+
+         } else {
+             /*
+              * No, create a new inherited column
+              *
+              * Creating inherited columns in this case seems to be unpopular.
+              * In the common use case of partitioned tables it's a foot-gun.
+              */
+             ereport(ERROR,
+                     (errcode(ERRCODE_DATATYPE_MISMATCH),
+                      errmsg("child table missing column \"%s\"",
+                             NameStr(attribute->attname))));
+         }
+         heap_close(attrdesc, RowExclusiveLock);
+     }
+
+ }
+
+ static void
+ ATExecDropInherits(Relation rel, RangeVar *parent)
+ {
+
+
+     Relation    catalogRelation;
+     SysScanDesc scan;
+     ScanKeyData key[2];
+     HeapTuple    inheritsTuple, attributeTuple, depTuple;
+     Oid            inhparent;
+     Oid            dropparent;
+     int         found = 0;
+
+     /* Get the OID of parent -- if no schema is specified use the regular
+      * search path and only drop the one table that's found. We could try to be
+      * clever and look at each parent and see if it matches but that would be
+      * inconsistent with other operations I think. */
+
+     Assert(rel);
+     Assert(parent);
+
+     dropparent = RangeVarGetRelid(parent, false);
+
+     /* Search through the direct parents of rel looking for dropparent oid */
+
+     catalogRelation = heap_open(InheritsRelationId, RowExclusiveLock);
+     ScanKeyInit(key,
+                 Anum_pg_inherits_inhrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(RelationGetRelid(rel)));
+     scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true, SnapshotNow, 1, key);
+     while (!found && HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
+     {
+         inhparent = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhparent;
+         if (inhparent == dropparent) {
+             simple_heap_delete(catalogRelation, &inheritsTuple->t_self);
+             found = 1;
+         }
+     }
+     systable_endscan(scan);
+     heap_close(catalogRelation, RowExclusiveLock);
+
+
+     if (!found) {
+         /* would it be better to look up the actual schema of dropparent and
+          * make the error message explicitly name the qualified name it's
+          * trying to drop ?*/
+         if (parent->schemaname)
+             ereport(ERROR,
+                     (errcode(ERRCODE_UNDEFINED_TABLE),
+                      errmsg("relation \"%s.%s\" is not a parent of relation \"%s\"",
+                             parent->schemaname, parent->relname, RelationGetRelationName(rel))));
+         else
+             ereport(ERROR,
+                     (errcode(ERRCODE_UNDEFINED_TABLE),
+                      errmsg("relation \"%s\" is not a parent of relation \"%s\"",
+                             parent->relname, RelationGetRelationName(rel))));
+     }
+
+     /* Search through columns looking for matching columns from parent table */
+
+     catalogRelation = heap_open(AttributeRelationId, RowExclusiveLock);
+     ScanKeyInit(key,
+                 Anum_pg_attribute_attrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(RelationGetRelid(rel)));
+     scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId, true, SnapshotNow, 1, key);
+     while (HeapTupleIsValid(attributeTuple = systable_getnext(scan))) {
+         Form_pg_attribute att = ((Form_pg_attribute)GETSTRUCT(attributeTuple));
+         /* Not an inherited column at all
+          * (do NOT use islocal for this test--it can be true for inherited columns)
+          */
+         if (att->attinhcount == 0)
+             continue;
+         if (att->attisdropped) /* XXX Is this right? */
+             continue;
+         if (SearchSysCacheExistsAttName(dropparent, NameStr(att->attname))) {
+             /* Decrement inhcount and possibly set islocal to 1 */
+             HeapTuple copyTuple = heap_copytuple(attributeTuple);
+             Form_pg_attribute copy_att = ((Form_pg_attribute)GETSTRUCT(copyTuple));
+
+             copy_att->attinhcount--;
+             if (copy_att->attinhcount == 0)
+                 copy_att->attislocal = 1;
+
+             simple_heap_update(catalogRelation, ©Tuple->t_self, copyTuple);
+             /* XXX "Avoid using it for multiple tuples, since opening the
+              * indexes and building the index info structures is moderately
+              * expensive." Perhaps this can be moved outside the loop or else
+              * at least the CatalogOpenIndexes/CatalogCloseIndexes moved
+              * outside the loop but when I try that it seg faults?!*/
+             CatalogUpdateIndexes(catalogRelation, copyTuple);
+             heap_freetuple(copyTuple);
+         }
+     }
+     systable_endscan(scan);
+     heap_close(catalogRelation, RowExclusiveLock);
+
+
+     /* Drop the dependency
+      *
+      * There's no convenient way to do this, so go trawling through pg_depend
+      */
+
+     catalogRelation = heap_open(DependRelationId, RowExclusiveLock);
+
+     ScanKeyInit(&key[0],
+                 Anum_pg_depend_classid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 RelationRelationId);
+     ScanKeyInit(&key[1],
+                 Anum_pg_depend_objid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(RelationGetRelid(rel)));
+
+     scan = systable_beginscan(catalogRelation, DependDependerIndexId, true,
+                               SnapshotNow, 2, key);
+
+     while (HeapTupleIsValid(depTuple = systable_getnext(scan))) {
+         Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(depTuple);
+
+         if (dep->refclassid == RelationRelationId &&
+             dep->refobjid == dropparent &&
+             dep->deptype == DEPENDENCY_NORMAL) {
+
+             /* Only delete a single dependency -- there shouldn't be more but just in case... */
+             simple_heap_delete(catalogRelation, &depTuple->t_self);
+
+             break;
+         }
+     }
+     systable_endscan(scan);
+
+     heap_close(catalogRelation, RowExclusiveLock);
+ }
+
+
+
  /*
   * ALTER TABLE CREATE TOAST TABLE
   *
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.335
diff -u -p -c -r1.335 copyfuncs.c
cvs diff: conflicting specifications of output style
*** src/backend/nodes/copyfuncs.c    30 Apr 2006 18:30:38 -0000    1.335
--- src/backend/nodes/copyfuncs.c    9 Jun 2006 21:28:14 -0000
*************** _copyAlterTableCmd(AlterTableCmd *from)
*** 1799,1804 ****
--- 1799,1805 ----
      COPY_SCALAR_FIELD(subtype);
      COPY_STRING_FIELD(name);
      COPY_NODE_FIELD(def);
+     COPY_NODE_FIELD(parent);
      COPY_NODE_FIELD(transform);
      COPY_SCALAR_FIELD(behavior);

Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.545
diff -u -p -c -r2.545 gram.y
cvs diff: conflicting specifications of output style
*** src/backend/parser/gram.y    27 May 2006 17:38:45 -0000    2.545
--- src/backend/parser/gram.y    9 Jun 2006 21:28:15 -0000
*************** alter_table_cmd:
*** 1514,1519 ****
--- 1514,1535 ----
                      n->subtype = AT_DisableTrigUser;
                      $$ = (Node *)n;
                  }
+             /* ALTER TABLE <name> ALTER INHERITS ADD <parent> */
+             | INHERIT qualified_name
+                 {
+                     AlterTableCmd *n = makeNode(AlterTableCmd);
+                     n->subtype = AT_AddInherits;
+                     n->parent = $2;
+                     $$ = (Node *)n;
+                 }
+             /* ALTER TABLE <name> alter INHERITS DROP <parent> */
+             | NO INHERIT qualified_name
+                 {
+                     AlterTableCmd *n = makeNode(AlterTableCmd);
+                     n->subtype = AT_DropInherits;
+                     n->parent = $3;
+                     $$ = (Node *)n;
+                 }
              | alter_rel_cmd
                  {
                      $$ = $1;
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.310
diff -u -p -c -r1.310 parsenodes.h
cvs diff: conflicting specifications of output style
*** src/include/nodes/parsenodes.h    30 Apr 2006 18:30:40 -0000    1.310
--- src/include/nodes/parsenodes.h    9 Jun 2006 21:28:17 -0000
*************** typedef enum AlterTableType
*** 874,880 ****
      AT_EnableTrigAll,            /* ENABLE TRIGGER ALL */
      AT_DisableTrigAll,            /* DISABLE TRIGGER ALL */
      AT_EnableTrigUser,            /* ENABLE TRIGGER USER */
!     AT_DisableTrigUser            /* DISABLE TRIGGER USER */
  } AlterTableType;

  typedef struct AlterTableCmd    /* one subcommand of an ALTER TABLE */
--- 874,882 ----
      AT_EnableTrigAll,            /* ENABLE TRIGGER ALL */
      AT_DisableTrigAll,            /* DISABLE TRIGGER ALL */
      AT_EnableTrigUser,            /* ENABLE TRIGGER USER */
!     AT_DisableTrigUser,            /* DISABLE TRIGGER USER */
!     AT_AddInherits,                /* ADD INHERITS parent */
!     AT_DropInherits                /* DROP INHERITS parent */
  } AlterTableType;

  typedef struct AlterTableCmd    /* one subcommand of an ALTER TABLE */
*************** typedef struct AlterTableCmd    /* one subc
*** 883,888 ****
--- 885,891 ----
      AlterTableType subtype;        /* Type of table alteration to apply */
      char       *name;            /* column, constraint, or trigger to act on,
                                   * or new owner or tablespace */
+     RangeVar   *parent;            /* Parent table for add/drop inherits */
      Node       *def;            /* definition of new column, column type,
                                   * index, or constraint */
      Node       *transform;        /* transformation expr for ALTER TYPE */


--
greg

pgsql-patches by date:

Previous
From: Andreas Pflug
Date:
Subject: Re: Patch for - Allow server logs to be remotely read
Next
From: Andrew Dunstan
Date:
Subject: drop if exists remnainder (reprise)