OSDN Git Service

Fix all known problems with pg_dump's handling of serial sequences
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 21 Aug 2006 00:57:26 +0000 (00:57 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 21 Aug 2006 00:57:26 +0000 (00:57 +0000)
by abandoning the idea that it should say SERIAL in the dump.  Instead,
dump serial sequences and column defaults just like regular ones.
Add a new backend command ALTER SEQUENCE OWNED BY to let pg_dump recreate
the sequence-to-column dependency that was formerly created "behind the
scenes" by SERIAL.  This restores SERIAL to being truly "just a macro"
consisting of component operations that can be stated explicitly in SQL.
Furthermore, the new command allows sequence ownership to be reassigned,
so that old mistakes can be cleaned up.

Also, downgrade the OWNED-BY dependency from INTERNAL to AUTO, since there
is no longer any very compelling argument why the sequence couldn't be
dropped while keeping the column.  (This forces initdb, to be sure the
right kinds of dependencies are in there.)

Along the way, add checks to prevent ALTER OWNER or SET SCHEMA on an
owned sequence; you can now only do this indirectly by changing the
owning table's owner or schema.  This is an oversight in previous
releases, but probably not worth back-patching.

29 files changed:
doc/src/sgml/datatype.sgml
doc/src/sgml/func.sgml
doc/src/sgml/ref/alter_sequence.sgml
doc/src/sgml/ref/alter_table.sgml
doc/src/sgml/ref/create_sequence.sgml
doc/src/sgml/ref/drop_sequence.sgml
src/backend/catalog/pg_depend.c
src/backend/catalog/pg_shdepend.c
src/backend/commands/sequence.c
src/backend/commands/tablecmds.c
src/backend/commands/view.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/makefuncs.c
src/backend/nodes/outfuncs.c
src/backend/parser/analyze.c
src/backend/parser/gram.y
src/backend/utils/adt/ruleutils.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/include/catalog/catversion.h
src/include/catalog/dependency.h
src/include/nodes/makefuncs.h
src/include/nodes/parsenodes.h
src/test/regress/expected/alter_table.out
src/test/regress/expected/dependency.out
src/test/regress/expected/namespace.out
src/test/regress/expected/sequence.out
src/test/regress/sql/dependency.sql

index 35e7100..c5ba6c4 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.169 2006/07/06 01:46:37 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.170 2006/08/21 00:57:23 tgl Exp $ -->
 
  <chapter id="datatype">
   <title id="datatype-title">Data Types</title>
@@ -705,17 +705,19 @@ CREATE TABLE <replaceable class="parameter">tablename</replaceable> (
 <programlisting>
 CREATE SEQUENCE <replaceable class="parameter">tablename</replaceable>_<replaceable class="parameter">colname</replaceable>_seq;
 CREATE TABLE <replaceable class="parameter">tablename</replaceable> (
-    <replaceable class="parameter">colname</replaceable> integer DEFAULT nextval('<replaceable class="parameter">tablename</replaceable>_<replaceable class="parameter">colname</replaceable>_seq') NOT NULL
+    <replaceable class="parameter">colname</replaceable> integer NOT NULL DEFAULT nextval('<replaceable class="parameter">tablename</replaceable>_<replaceable class="parameter">colname</replaceable>_seq')
 );
+ALTER SEQUENCE <replaceable class="parameter">tablename</replaceable>_<replaceable class="parameter">colname</replaceable>_seq OWNED BY <replaceable class="parameter">tablename</replaceable>.<replaceable class="parameter">colname</replaceable>;
 </programlisting>
 
      Thus, we have created an integer column and arranged for its default
      values to be assigned from a sequence generator.  A <literal>NOT NULL</>
      constraint is applied to ensure that a null value cannot be explicitly
-     inserted, either.  In most cases you would also want to attach a
+     inserted, either.  (In most cases you would also want to attach a
      <literal>UNIQUE</> or <literal>PRIMARY KEY</> constraint to prevent
      duplicate values from being inserted by accident, but this is
-     not automatic.
+     not automatic.)  Lastly, the sequence is marked as <quote>owned by</>
+     the column, so that it will be dropped if the column or table is dropped.
     </para>
 
     <note>
@@ -749,20 +751,9 @@ CREATE TABLE <replaceable class="parameter">tablename</replaceable> (
 
     <para>
      The sequence created for a <type>serial</type> column is
-     automatically dropped when the owning column is dropped, and
-     cannot be dropped otherwise.  (This was not true in
-     <productname>PostgreSQL</productname> releases before 7.3.  Note
-     that this automatic drop linkage will not occur for a sequence
-     created by reloading a dump from a pre-7.3 database; the dump
-     file does not contain the information needed to establish the
-     dependency link.) Furthermore, this dependency between sequence
-     and column is made only for the <type>serial</> column itself. If
-     any other columns reference the sequence (perhaps by manually
-     calling the <function>nextval</> function), they will be broken
-     if the sequence is removed. Using a <type>serial</> column's sequence
-     in such a fashion is considered bad form; if you wish to feed several
-     columns from the same sequence generator, create the sequence as an
-     independent object.
+     automatically dropped when the owning column is dropped.
+     You can drop the sequence without dropping the column, but this
+     will force removal of the column default expression.
     </para>
    </sect2>
   </sect1>
index 113411f..2b2a0a0 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.330 2006/08/17 23:04:03 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.331 2006/08/21 00:57:23 tgl Exp $ -->
 
  <chapter id="functions">
   <title>Functions and Operators</title>
@@ -9863,10 +9863,14 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
 
   <para>
    <function>pg_get_serial_sequence</function> fetches the name of the
-   sequence associated with a <type>serial</> or <type>bigserial</>
-   column.  The name is suitably formatted for passing to the sequence
-   functions (see <xref linkend="functions-sequence">).  NULL is
-   returned if the column does not have an associated sequence.
+   sequence associated with a column, or NULL if there is no sequence
+   associated with the column.  The result is suitably formatted for passing
+   to the sequence functions (see <xref linkend="functions-sequence">).
+   This association can be modified or removed with <command>ALTER SEQUENCE
+   OWNED BY</>.  (The function probably should have been called
+   <function>pg_get_owned_sequence</function>; its name reflects the fact
+   that it's typically used with <type>serial</> or <type>bigserial</>
+   columns.)
   </para>
 
   <para>
index 3e7937e..3d6d5ca 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_sequence.sgml,v 1.13 2005/11/01 21:09:50 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_sequence.sgml,v 1.14 2006/08/21 00:57:24 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -27,6 +27,7 @@ PostgreSQL documentation
 ALTER SEQUENCE <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ]
     [ MINVALUE <replaceable class="parameter">minvalue</replaceable> | NO MINVALUE ] [ MAXVALUE <replaceable class="parameter">maxvalue</replaceable> | NO MAXVALUE ]
     [ RESTART [ WITH ] <replaceable class="parameter">start</replaceable> ] [ CACHE <replaceable class="parameter">cache</replaceable> ] [ [ NO ] CYCLE ]
+    [ OWNED BY { <replaceable class="parameter">table</replaceable>.<replaceable class="parameter">column</replaceable> | NONE } ]
 ALTER SEQUENCE <replaceable class="parameter">name</replaceable> SET SCHEMA <replaceable class="parameter">new_schema</replaceable>
   </synopsis>
  </refsynopsisdiv>
@@ -163,6 +164,24 @@ ALTER SEQUENCE <replaceable class="parameter">name</replaceable> SET SCHEMA <rep
       </listitem>
      </varlistentry>
 
+   <varlistentry>
+    <term><literal>OWNED BY</literal> <replaceable class="parameter">table</replaceable>.<replaceable class="parameter">column</replaceable></term>
+    <term><literal>OWNED BY NONE</literal></term>
+    <listitem>
+     <para>
+      The <literal>OWNED BY</literal> option causes the sequence to be
+      associated with a specific table column, such that if that column
+      (or its whole table) is dropped, the sequence will be automatically
+      dropped as well.  If specified, this association replaces any
+      previously specified association for the sequence.  The specified
+      table must have the same owner and be in the same schema as the
+      sequence.
+      Specifying <literal>OWNED BY NONE</literal> removes any existing
+      association, making the sequence <quote>free-standing</>.
+     </para>
+    </listitem>
+   </varlistentry>
+
      <varlistentry>
       <term><replaceable class="parameter">new_schema</replaceable></term>
       <listitem>
@@ -191,8 +210,11 @@ ALTER SEQUENCE serial RESTART WITH 105;
 
   <para>
    To avoid blocking of concurrent transactions that obtain numbers from the
-   same sequence, <command>ALTER SEQUENCE</command> is never rolled back;
-   the changes take effect immediately and are not reversible.
+   same sequence, <command>ALTER SEQUENCE</command>'s effects on the sequence
+   generation parameters are never rolled back;
+   those changes take effect immediately and are not reversible.  However,
+   the <literal>OWNED BY</> and <literal>SET SCHEMA</> clauses are ordinary
+   catalog updates and can be rolled back.
   </para>
 
   <para>
@@ -200,7 +222,8 @@ ALTER SEQUENCE serial RESTART WITH 105;
    <function>nextval</> results in backends,
    other than the current one, that have preallocated (cached) sequence
    values. They will use up all cached values prior to noticing the changed
-   sequence parameters.  The current backend will be affected immediately.
+   sequence generation parameters.  The current backend will be affected
+   immediately.
   </para>
 
   <para>
@@ -217,10 +240,20 @@ ALTER SEQUENCE serial RESTART WITH 105;
   <para>
    <command>ALTER SEQUENCE</command> conforms to the <acronym>SQL</acronym>
    standard,
-   except for the <literal>SET SCHEMA</literal> variant, which is a
-   <productname>PostgreSQL</productname> extension.
+   except for the <literal>OWNED BY</> and <literal>SET SCHEMA</literal>
+   clauses, which are <productname>PostgreSQL</productname> extensions.
   </para>
  </refsect1>
+
+ <refsect1>
+  <title>See Also</title>
+
+  <simplelist type="inline">
+   <member><xref linkend="sql-createsequence" endterm="sql-createsequence-title"></member>
+   <member><xref linkend="sql-dropsequence" endterm="sql-dropsequence-title"></member>
+  </simplelist>
+ </refsect1>
+
 </refentry>
 
 <!-- Keep this comment at the end of the file
index 17b0f36..d7c3106 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.88 2006/08/03 20:57:06 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.89 2006/08/21 00:57:24 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -371,7 +371,7 @@ where <replaceable class="PARAMETER">action</replaceable> is one of:
     <listitem>
      <para>
       This form moves the table into another schema.  Associated indexes,
-      constraints, and SERIAL-column sequences are moved as well.
+      constraints, and sequences owned by table columns are moved as well.
      </para>
     </listitem>
    </varlistentry>
index 7a094f6..5fa16c2 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_sequence.sgml,v 1.43 2005/11/01 21:09:50 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_sequence.sgml,v 1.44 2006/08/21 00:57:24 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -23,6 +23,7 @@ PostgreSQL documentation
 CREATE [ TEMPORARY | TEMP ] SEQUENCE <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ]
     [ MINVALUE <replaceable class="parameter">minvalue</replaceable> | NO MINVALUE ] [ MAXVALUE <replaceable class="parameter">maxvalue</replaceable> | NO MAXVALUE ]
     [ START [ WITH ] <replaceable class="parameter">start</replaceable> ] [ CACHE <replaceable class="parameter">cache</replaceable> ] [ [ NO ] CYCLE ]
+    [ OWNED BY { <replaceable class="parameter">table</replaceable>.<replaceable class="parameter">column</replaceable> | NONE } ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -193,6 +194,22 @@ SELECT * FROM <replaceable>name</replaceable>;
      </para>
     </listitem>
    </varlistentry>
+
+   <varlistentry>
+    <term><literal>OWNED BY</literal> <replaceable class="parameter">table</replaceable>.<replaceable class="parameter">column</replaceable></term>
+    <term><literal>OWNED BY NONE</literal></term>
+    <listitem>
+     <para>
+      The <literal>OWNED BY</literal> option causes the sequence to be
+      associated with a specific table column, such that if that column
+      (or its whole table) is dropped, the sequence will be automatically
+      dropped as well.  The specified table must have the same owner and be in
+      the same schema as the sequence.
+      <literal>OWNED BY NONE</literal>, the default, specifies that there
+      is no such association.
+     </para>
+    </listitem>
+   </varlistentry>
   </variablelist>
  </refsect1>
 
@@ -300,11 +317,38 @@ END;
    <command>CREATE SEQUENCE</command> conforms to the <acronym>SQL</acronym>
    standard, with the following exceptions:
    <itemizedlist>
-    <listitem><para>The standard's <literal>AS &lt;data type&gt;</literal> expression is not supported.</para></listitem>
-    <listitem><para>Obtaining the next value is done using the <function>nextval()</> function instead of the standard's <command>NEXT VALUE FOR</command> expression.</para></listitem>
+    <listitem>
+     <para>
+      The standard's <literal>AS &lt;data type&gt;</literal> expression is not
+      supported.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Obtaining the next value is done using the <function>nextval()</>
+      function instead of the standard's <command>NEXT VALUE FOR</command>
+      expression.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      The <literal>OWNED BY</> clause is a <productname>PostgreSQL</>
+      extension. 
+     </para>
+    </listitem>
    </itemizedlist>
   </para>
  </refsect1>
+
+ <refsect1>
+  <title>See Also</title>
+
+  <simplelist type="inline">
+   <member><xref linkend="sql-altersequence" endterm="sql-altersequence-title"></member>
+   <member><xref linkend="sql-dropsequence" endterm="sql-dropsequence-title"></member>
+  </simplelist>
+ </refsect1>
+
 </refentry>
 
 <!-- Keep this comment at the end of the file
index 074f4e7..d730d68 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/drop_sequence.sgml,v 1.24 2005/11/19 17:39:44 adunstan Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/drop_sequence.sgml,v 1.25 2006/08/21 00:57:24 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -105,6 +105,7 @@ DROP SEQUENCE serial;
 
   <simplelist type="inline">
    <member><xref linkend="sql-createsequence" endterm="sql-createsequence-title"></member>
+   <member><xref linkend="sql-altersequence" endterm="sql-altersequence-title"></member>
   </simplelist>
  </refsect1>
 
index 5a297d4..99cdf5e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.21 2006/07/11 17:26:58 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.22 2006/08/21 00:57:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -163,58 +163,6 @@ deleteDependencyRecordsFor(Oid classId, Oid objectId)
 }
 
 /*
- * objectIsInternalDependency -- return whether the specified object
- * is listed as an internal dependency for some other object.
- *
- * This is used to implement DROP/REASSIGN OWNED.  We cannot invoke
- * performDeletion blindly, because it may try to drop or modify an internal-
- * dependent object before the "main" object, so we need to skip the first
- * object and expect it to be automatically dropped when the main object is
- * dropped.
- */
-bool
-objectIsInternalDependency(Oid classId, Oid objectId)
-{
-       Relation        depRel;
-       ScanKeyData key[2];
-       SysScanDesc scan;
-       HeapTuple       tup;
-       bool            isdep = false;
-
-       depRel = heap_open(DependRelationId, AccessShareLock);
-
-       ScanKeyInit(&key[0],
-                               Anum_pg_depend_classid,
-                               BTEqualStrategyNumber, F_OIDEQ,
-                               ObjectIdGetDatum(classId));
-       ScanKeyInit(&key[1],
-                               Anum_pg_depend_objid,
-                               BTEqualStrategyNumber, F_OIDEQ,
-                               ObjectIdGetDatum(objectId));
-
-       scan = systable_beginscan(depRel, DependDependerIndexId, true,
-                                                         SnapshotNow, 2, key);
-
-       while (HeapTupleIsValid(tup = systable_getnext(scan)))
-       {
-               Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
-
-               if (depForm->deptype == DEPENDENCY_INTERNAL)
-               {
-                       /* No need to keep scanning */
-                       isdep = true;
-                       break;
-               }
-       }
-
-       systable_endscan(scan);
-
-       heap_close(depRel, AccessShareLock);
-
-       return isdep;
-}
-
-/*
  * Adjust dependency record(s) to point to a different object of the same type
  *
  * classId/objectId specify the referencing object.
@@ -313,6 +261,105 @@ changeDependencyFor(Oid classId, Oid objectId,
 }
 
 /*
+ * Detect whether a sequence is marked as "owned" by a column
+ *
+ * An ownership marker is an AUTO dependency from the sequence to the
+ * column.  If we find one, store the identity of the owning column
+ * into *tableId and *colId and return TRUE; else return FALSE.
+ *
+ * Note: if there's more than one such pg_depend entry then you get
+ * a random one of them returned into the out parameters.  This should
+ * not happen, though.
+ */
+bool
+sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
+{
+       bool            ret = false;
+       Relation        depRel;
+       ScanKeyData key[2];
+       SysScanDesc scan;
+       HeapTuple       tup;
+
+       depRel = heap_open(DependRelationId, AccessShareLock);
+
+       ScanKeyInit(&key[0],
+                               Anum_pg_depend_classid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(RelationRelationId));
+       ScanKeyInit(&key[1],
+                               Anum_pg_depend_objid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(seqId));
+
+       scan = systable_beginscan(depRel, DependDependerIndexId, true,
+                                                         SnapshotNow, 2, key);
+
+       while (HeapTupleIsValid((tup = systable_getnext(scan))))
+       {
+               Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
+
+               if (depform->refclassid == RelationRelationId &&
+                       depform->deptype == DEPENDENCY_AUTO)
+               {
+                       *tableId = depform->refobjid;
+                       *colId = depform->refobjsubid;
+                       ret = true;
+                       break;                          /* no need to keep scanning */
+               }
+       }
+
+       systable_endscan(scan);
+
+       heap_close(depRel, AccessShareLock);
+
+       return ret;
+}
+
+/*
+ * Remove any existing "owned" markers for the specified sequence.
+ *
+ * Note: we don't provide a special function to install an "owned"
+ * marker; just use recordDependencyOn().
+ */
+void
+markSequenceUnowned(Oid seqId)
+{
+       Relation        depRel;
+       ScanKeyData key[2];
+       SysScanDesc scan;
+       HeapTuple       tup;
+
+       depRel = heap_open(DependRelationId, RowExclusiveLock);
+
+       ScanKeyInit(&key[0],
+                               Anum_pg_depend_classid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(RelationRelationId));
+       ScanKeyInit(&key[1],
+                               Anum_pg_depend_objid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(seqId));
+
+       scan = systable_beginscan(depRel, DependDependerIndexId, true,
+                                                         SnapshotNow, 2, key);
+
+       while (HeapTupleIsValid((tup = systable_getnext(scan))))
+       {
+               Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
+
+               if (depform->refclassid == RelationRelationId &&
+                       depform->deptype == DEPENDENCY_AUTO)
+               {
+                       simple_heap_delete(depRel, &tup->t_self);
+               }
+       }
+
+       systable_endscan(scan);
+
+       heap_close(depRel, RowExclusiveLock);
+}
+
+/*
  * isObjectPinned()
  *
  * Test if an object is required for basic database functionality.
index 31f1f65..85e3d96 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.13 2006/08/20 21:56:16 alvherre Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.14 2006/08/21 00:57:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/xact.h"
+#include "catalog/catalog.h"
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/pg_authid.h"
@@ -869,30 +870,17 @@ shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId,
  * Get the database Id that should be used in pg_shdepend, given the OID
  * of the catalog containing the object.  For shared objects, it's 0
  * (InvalidOid); for all other objects, it's the current database Id.
- *
- * XXX it's awfully tempting to hard-wire this instead of doing a syscache
- * lookup ... but resist the temptation, unless you can prove it's a
- * bottleneck.
  */
 static Oid
 classIdGetDbId(Oid classId)
 {
        Oid                     dbId;
-       HeapTuple       tup;
-
-       tup = SearchSysCache(RELOID,
-                                                ObjectIdGetDatum(classId),
-                                                0, 0, 0);
-       if (!HeapTupleIsValid(tup))
-               elog(ERROR, "cache lookup failed for relation %u", classId);
 
-       if (((Form_pg_class) GETSTRUCT(tup))->relisshared)
+       if (IsSharedRelation(classId))
                dbId = InvalidOid;
        else
                dbId = MyDatabaseId;
 
-       ReleaseSysCache(tup);
-
        return dbId;
 }
 
@@ -1055,6 +1043,11 @@ isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel)
  * Drop the objects owned by any one of the given RoleIds.     If a role has
  * access to an object, the grant will be removed as well (but the object
  * will not, of course.)
+ *
+ * We can revoke grants immediately while doing the scan, but drops are
+ * saved up and done all at once with performMultipleDeletions.  This
+ * is necessary so that we don't get failures from trying to delete
+ * interdependent objects in the wrong order.
  */
 void
 shdepDropOwned(List *roleids, DropBehavior behavior)
@@ -1113,7 +1106,7 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
                        InternalGrant   istmt;
                        Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
 
-                       /* We only operate on objects on the current database */
+                       /* We only operate on objects in the current database */
                        if (sdepForm->dbid != MyDatabaseId)
                                continue;
 
@@ -1128,24 +1121,8 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
                                        switch (sdepForm->classid)
                                        {
                                                case RelationRelationId:
-                                                       {
-                                                               /* is it a sequence or non-sequence? */
-                                                               Form_pg_class pg_class_tuple;
-                                                               HeapTuple       tuple;
-
-                                                               tuple = SearchSysCache(RELOID,
-                                                                                                          ObjectIdGetDatum(sdepForm->objid),
-                                                                                                          0, 0, 0);
-                                                               if (!HeapTupleIsValid(tuple))
-                                                                       elog(ERROR, "cache lookup failed for relation %u",
-                                                                                sdepForm->objid);
-                                                               pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
-                                                               if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
-                                                                       istmt.objtype = ACL_OBJECT_SEQUENCE;
-                                                               else
-                                                                       istmt.objtype = ACL_OBJECT_RELATION;
-                                                               ReleaseSysCache(tuple);
-                                                       }
+                                                       /* it's OK to use RELATION for a sequence */
+                                                       istmt.objtype = ACL_OBJECT_RELATION;
                                                        break;
                                                case DatabaseRelationId:
                                                        istmt.objtype = ACL_OBJECT_DATABASE;
@@ -1180,11 +1157,10 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
                                        ExecGrantStmt_oids(&istmt);
                                        break;
                                case SHARED_DEPENDENCY_OWNER:
-                                       /* Save it for later deleting it */
+                                       /* Save it for deletion below */
                                        obj.classId = sdepForm->classid;
                                        obj.objectId = sdepForm->objid;
                                        obj.objectSubId = 0;
-
                                        add_exact_object_address(&obj, deleteobjs);
                                        break;
                        }
@@ -1259,7 +1235,7 @@ shdepReassignOwned(List *roleids, Oid newrole)
                {
                        Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
 
-                       /* We only operate on objects on the current database */
+                       /* We only operate on objects in the current database */
                        if (sdepForm->dbid != MyDatabaseId)
                                continue;
 
@@ -1271,15 +1247,7 @@ shdepReassignOwned(List *roleids, Oid newrole)
                        if (sdepForm->deptype != SHARED_DEPENDENCY_OWNER)
                                continue;
 
-                       /*
-                        * If there's a regular (non-shared) dependency on this object
-                        * marked with DEPENDENCY_INTERNAL, skip this object.  We will
-                        * alter the referencer object instead.
-                        */
-                       if (objectIsInternalDependency(sdepForm->classid, sdepForm->objid))
-                               continue;
-
-                       /* Issue the appropiate ALTER OWNER call */
+                       /* Issue the appropriate ALTER OWNER call */
                        switch (sdepForm->classid)
                        {
                                case ConversionRelationId:
@@ -1299,7 +1267,12 @@ shdepReassignOwned(List *roleids, Oid newrole)
                                        break;
 
                                case RelationRelationId:
-                                       ATExecChangeOwner(sdepForm->objid, newrole, false);
+                                       /*
+                                        * Pass recursing = true so that we don't fail on
+                                        * indexes, owned sequences, etc when we happen
+                                        * to visit them before their parent table.
+                                        */
+                                       ATExecChangeOwner(sdepForm->objid, newrole, true);
                                        break;
 
                                case ProcedureRelationId:
index 6154a4e..865c2f6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.138 2006/07/31 20:09:00 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.139 2006/08/21 00:57:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,7 @@
 #include "access/heapam.h"
 #include "access/transam.h"
 #include "access/xact.h"
+#include "catalog/dependency.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_type.h"
 #include "commands/defrem.h"
@@ -26,6 +27,7 @@
 #include "nodes/makefuncs.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
+#include "utils/lsyscache.h"
 #include "utils/resowner.h"
 #include "utils/syscache.h"
 
@@ -82,8 +84,11 @@ static int64 nextval_internal(Oid relid);
 static Relation open_share_lock(SeqTable seq);
 static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
 static Form_pg_sequence read_info(SeqTable elm, Relation rel, Buffer *buf);
-static void init_params(List *options, Form_pg_sequence new, bool isInit);
+static void init_params(List *options, bool isInit,
+                                               Form_pg_sequence new, List **owned_by);
 static void do_setval(Oid relid, int64 next, bool iscalled);
+static void process_owned_by(Relation seqrel, List *owned_by);
+
 
 /*
  * DefineSequence
@@ -93,6 +98,7 @@ void
 DefineSequence(CreateSeqStmt *seq)
 {
        FormData_pg_sequence new;
+       List       *owned_by;
        CreateStmt *stmt = makeNode(CreateStmt);
        Oid                     seqoid;
        Relation        rel;
@@ -107,7 +113,7 @@ DefineSequence(CreateSeqStmt *seq)
        NameData        name;
 
        /* Check and set all option values */
-       init_params(seq->options, &new, true);
+       init_params(seq->options, true, &new, &owned_by);
 
        /*
         * Create relation (and fill *null & *value)
@@ -123,7 +129,6 @@ DefineSequence(CreateSeqStmt *seq)
                coldef->raw_default = NULL;
                coldef->cooked_default = NULL;
                coldef->constraints = NIL;
-               coldef->support = NULL;
 
                null[i - 1] = ' ';
 
@@ -287,6 +292,10 @@ DefineSequence(CreateSeqStmt *seq)
 
        UnlockReleaseBuffer(buf);
 
+       /* process OWNED BY if given */
+       if (owned_by)
+               process_owned_by(rel, owned_by);
+
        heap_close(rel, NoLock);
 }
 
@@ -305,6 +314,7 @@ AlterSequence(AlterSeqStmt *stmt)
        Page            page;
        Form_pg_sequence seq;
        FormData_pg_sequence new;
+       List       *owned_by;
 
        /* open and AccessShareLock sequence */
        relid = RangeVarGetRelid(stmt->sequence, false);
@@ -323,7 +333,7 @@ AlterSequence(AlterSeqStmt *stmt)
        memcpy(&new, seq, sizeof(FormData_pg_sequence));
 
        /* Check and set new values */
-       init_params(stmt->options, &new, false);
+       init_params(stmt->options, false, &new, &owned_by);
 
        /* Now okay to update the on-disk tuple */
        memcpy(seq, &new, sizeof(FormData_pg_sequence));
@@ -366,6 +376,10 @@ AlterSequence(AlterSeqStmt *stmt)
 
        UnlockReleaseBuffer(buf);
 
+       /* process OWNED BY if given */
+       if (owned_by)
+               process_owned_by(seqrel, owned_by);
+
        relation_close(seqrel, NoLock);
 }
 
@@ -933,13 +947,15 @@ read_info(SeqTable elm, Relation rel, Buffer *buf)
 
 /*
  * init_params: process the options list of CREATE or ALTER SEQUENCE,
- * and store the values into appropriate fields of *new.
+ * and store the values into appropriate fields of *new.  Also set
+ * *owned_by to any OWNED BY option, or to NIL if there is none.
  *
  * If isInit is true, fill any unspecified options with default values;
  * otherwise, do not change existing options that aren't explicitly overridden.
  */
 static void
-init_params(List *options, Form_pg_sequence new, bool isInit)
+init_params(List *options, bool isInit,
+                       Form_pg_sequence new, List **owned_by)
 {
        DefElem    *last_value = NULL;
        DefElem    *increment_by = NULL;
@@ -949,6 +965,8 @@ init_params(List *options, Form_pg_sequence new, bool isInit)
        DefElem    *is_cycled = NULL;
        ListCell   *option;
 
+       *owned_by = NIL;
+
        foreach(option, options)
        {
                DefElem    *defel = (DefElem *) lfirst(option);
@@ -1006,6 +1024,14 @@ init_params(List *options, Form_pg_sequence new, bool isInit)
                                                 errmsg("conflicting or redundant options")));
                        is_cycled = defel;
                }
+               else if (strcmp(defel->defname, "owned_by") == 0)
+               {
+                       if (*owned_by)
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_SYNTAX_ERROR),
+                                                errmsg("conflicting or redundant options")));
+                       *owned_by = defGetQualifiedName(defel);
+               }
                else
                        elog(ERROR, "option \"%s\" not recognized",
                                 defel->defname);
@@ -1130,6 +1156,99 @@ init_params(List *options, Form_pg_sequence new, bool isInit)
                new->cache_value = 1;
 }
 
+/*
+ * Process an OWNED BY option for CREATE/ALTER SEQUENCE
+ *
+ * Ownership permissions on the sequence are already checked,
+ * but if we are establishing a new owned-by dependency, we must
+ * enforce that the referenced table has the same owner and namespace
+ * as the sequence.
+ */
+static void
+process_owned_by(Relation seqrel, List *owned_by)
+{
+       int                     nnames;
+       Relation        tablerel;
+       AttrNumber      attnum;
+
+       nnames = list_length(owned_by);
+       Assert(nnames > 0);
+       if (nnames == 1)
+       {
+               /* Must be OWNED BY NONE */
+               if (strcmp(strVal(linitial(owned_by)), "none") != 0)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_SYNTAX_ERROR),
+                                        errmsg("invalid OWNED BY option"),
+                                        errhint("Specify OWNED BY table.column or OWNED BY NONE.")));
+               tablerel = NULL;
+               attnum = 0;
+       }
+       else
+       {
+               List       *relname;
+               char       *attrname;
+               RangeVar   *rel;
+
+               /* Separate relname and attr name */
+               relname = list_truncate(list_copy(owned_by), nnames - 1);
+               attrname = strVal(lfirst(list_tail(owned_by)));
+
+               /* Open and lock rel to ensure it won't go away meanwhile */
+               rel = makeRangeVarFromNameList(relname);
+               tablerel = relation_openrv(rel, AccessShareLock);
+
+               /* Must be a regular table */
+               if (tablerel->rd_rel->relkind != RELKIND_RELATION)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                                        errmsg("referenced relation \"%s\" is not a table",
+                                                       RelationGetRelationName(tablerel))));
+
+               /* We insist on same owner and schema */
+               if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                        errmsg("sequence must have same owner as table it is owned by")));
+               if (RelationGetNamespace(seqrel) != RelationGetNamespace(tablerel))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                        errmsg("sequence must be in same schema as table it is owned by")));
+
+               /* Now, fetch the attribute number from the system cache */
+               attnum = get_attnum(RelationGetRelid(tablerel), attrname);
+               if (attnum == InvalidAttrNumber)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_UNDEFINED_COLUMN),
+                                        errmsg("column \"%s\" of relation \"%s\" does not exist",
+                                                       attrname, RelationGetRelationName(tablerel))));
+       }
+
+       /*
+        * OK, we are ready to update pg_depend.  First remove any existing
+        * AUTO dependencies for the sequence, then optionally add a new one.
+        */
+       markSequenceUnowned(RelationGetRelid(seqrel));
+
+       if (tablerel)
+       {
+               ObjectAddress refobject,
+                                       depobject;
+
+               refobject.classId = RelationRelationId;
+               refobject.objectId = RelationGetRelid(tablerel);
+               refobject.objectSubId = attnum;
+               depobject.classId = RelationRelationId;
+               depobject.objectId = RelationGetRelid(seqrel);
+               depobject.objectSubId = 0;
+               recordDependencyOn(&depobject, &refobject, DEPENDENCY_AUTO);
+       }
+
+       /* Done, but hold lock until commit */
+       if (tablerel)
+               relation_close(tablerel, NoLock);
+}
+
 
 void
 seq_redo(XLogRecPtr lsn, XLogRecord *record)
index cd4c4eb..a1f7603 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.199 2006/08/03 20:57:06 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.200 2006/08/21 00:57:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -209,8 +209,6 @@ static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
 static void ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
                                ColumnDef *colDef);
 static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
-static void add_column_support_dependency(Oid relid, int32 attnum,
-                                                         RangeVar *support);
 static void ATExecDropNotNull(Relation rel, const char *colName);
 static void ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
                                 const char *colName);
@@ -476,10 +474,6 @@ DefineRelation(CreateStmt *stmt, char relkind)
         * work unless we have a pre-existing relation. So, the transformation has
         * to be postponed to this final step of CREATE TABLE.
         *
-        * Another task that's conveniently done at this step is to add dependency
-        * links between columns and supporting relations (such as SERIAL
-        * sequences).
-        *
         * First, scan schema to find new column defaults.
         */
        rawDefaults = NIL;
@@ -502,10 +496,6 @@ DefineRelation(CreateStmt *stmt, char relkind)
                        rawEnt->raw_default = colDef->raw_default;
                        rawDefaults = lappend(rawDefaults, rawEnt);
                }
-
-               /* Create dependency for supporting relation for this column */
-               if (colDef->support != NULL)
-                       add_column_support_dependency(relationId, attnum, colDef->support);
        }
 
        /*
@@ -944,7 +934,6 @@ MergeAttributes(List *schema, List *supers, bool istemp,
                                def->raw_default = NULL;
                                def->cooked_default = NULL;
                                def->constraints = NIL;
-                               def->support = NULL;
                                inhSchema = lappend(inhSchema, def);
                                newattno[parent_attno - 1] = ++child_attno;
                        }
@@ -1159,9 +1148,10 @@ varattnos_map(TupleDesc old, TupleDesc new)
        return attmap;
 }
 
-/* Generate a map for change_varattnos_of_a_node from a tupledesc and a list of
- * ColumnDefs */
-
+/*
+ * Generate a map for change_varattnos_of_a_node from a tupledesc and a list of
+ * ColumnDefs
+ */
 AttrNumber *
 varattnos_map_schema(TupleDesc old, List *schema) 
 {
@@ -3017,8 +3007,6 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
                /* Child should see column as singly inherited */
                colDefChild->inhcount = 1;
                colDefChild->is_local = false;
-               /* and don't make a support dependency on the child */
-               colDefChild->support = NULL;
 
                ATOneLevelRecursion(wqueue, rel, childCmd);
        }
@@ -3259,8 +3247,6 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
         * Add needed dependency entries for the new column.
         */
        add_column_datatype_dependency(myrelid, i, attribute->atttypid);
-       if (colDef->support != NULL)
-               add_column_support_dependency(myrelid, i, colDef->support);
 }
 
 /*
@@ -3282,24 +3268,6 @@ add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
 }
 
 /*
- * Install a dependency for a column's supporting relation (serial sequence).
- */
-static void
-add_column_support_dependency(Oid relid, int32 attnum, RangeVar *support)
-{
-       ObjectAddress colobject,
-                               suppobject;
-
-       colobject.classId = RelationRelationId;
-       colobject.objectId = relid;
-       colobject.objectSubId = attnum;
-       suppobject.classId = RelationRelationId;
-       suppobject.objectId = RangeVarGetRelid(support, false);
-       suppobject.objectSubId = 0;
-       recordDependencyOn(&suppobject, &colobject, DEPENDENCY_INTERNAL);
-}
-
-/*
  * ALTER TABLE ALTER COLUMN DROP NOT NULL
  */
 static void
@@ -5444,9 +5412,9 @@ ATPostAlterTypeParse(char *cmd, List **wqueue)
 /*
  * ALTER TABLE OWNER
  *
- * recursing is true if we are recursing from a table to its indexes or
- * toast table.  We don't allow the ownership of those things to be
- * changed separately from the parent table.  Also, we can skip permission
+ * recursing is true if we are recursing from a table to its indexes,
+ * sequences, or toast table.  We don't allow the ownership of those things to
+ * be changed separately from the parent table.  Also, we can skip permission
  * checks (this is necessary not just an optimization, else we'd fail to
  * handle toast tables properly).
  */
@@ -5479,7 +5447,6 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing)
        {
                case RELKIND_RELATION:
                case RELKIND_VIEW:
-               case RELKIND_SEQUENCE:
                        /* ok to change owner */
                        break;
                case RELKIND_INDEX:
@@ -5502,6 +5469,24 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing)
                                newOwnerId = tuple_class->relowner;
                        }
                        break;
+               case RELKIND_SEQUENCE:
+                       if (!recursing &&
+                               tuple_class->relowner != newOwnerId)
+                       {
+                               /* if it's an owned sequence, disallow changing it by itself */
+                               Oid             tableId;
+                               int32   colId;
+
+                               if (sequenceIsOwned(relationOid, &tableId, &colId))
+                                       ereport(ERROR,
+                                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                                        errmsg("cannot change owner of sequence \"%s\"",
+                                                                       NameStr(tuple_class->relname)),
+                                                        errdetail("Sequence \"%s\" is linked to table \"%s\".",
+                                                                          NameStr(tuple_class->relname),
+                                                                          get_rel_name(tableId))));
+                       }
+                       break;
                case RELKIND_TOASTVALUE:
                        if (recursing)
                                break;
@@ -5644,7 +5629,7 @@ change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId)
        HeapTuple       tup;
 
        /*
-        * SERIAL sequences are those having an internal dependency on one of the
+        * SERIAL sequences are those having an auto dependency on one of the
         * table's columns (we don't care *which* column, exactly).
         */
        depRel = heap_open(DependRelationId, AccessShareLock);
@@ -5667,11 +5652,11 @@ change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId)
                Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
                Relation        seqRel;
 
-               /* skip dependencies other than internal dependencies on columns */
+               /* skip dependencies other than auto dependencies on columns */
                if (depForm->refobjsubid == 0 ||
                        depForm->classid != RelationRelationId ||
                        depForm->objsubid != 0 ||
-                       depForm->deptype != DEPENDENCY_INTERNAL)
+                       depForm->deptype != DEPENDENCY_AUTO)
                        continue;
 
                /* Use relation_open just in case it's an index */
@@ -5686,7 +5671,7 @@ change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId)
                }
 
                /* We don't need to close the sequence while we alter it. */
-               ATExecChangeOwner(depForm->objid, newOwnerId, false);
+               ATExecChangeOwner(depForm->objid, newOwnerId, true);
 
                /* Now we can close it.  Keep the lock till end of transaction. */
                relation_close(seqRel, NoLock);
@@ -6549,6 +6534,9 @@ AlterTableNamespace(RangeVar *relation, const char *newschema)
 
        rel = heap_openrv(relation, AccessExclusiveLock);
 
+       relid = RelationGetRelid(rel);
+       oldNspOid = RelationGetNamespace(rel);
+
        /* heap_openrv allows TOAST, but we don't want to */
        if (rel->rd_rel->relkind == RELKIND_TOASTVALUE)
                ereport(ERROR,
@@ -6556,8 +6544,20 @@ AlterTableNamespace(RangeVar *relation, const char *newschema)
                                 errmsg("\"%s\" is a TOAST relation",
                                                RelationGetRelationName(rel))));
 
-       relid = RelationGetRelid(rel);
-       oldNspOid = RelationGetNamespace(rel);
+       /* if it's an owned sequence, disallow moving it by itself */
+       if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
+       {
+               Oid             tableId;
+               int32   colId;
+
+               if (sequenceIsOwned(relid, &tableId, &colId))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                        errmsg("cannot move an owned sequence into another schema"),
+                                        errdetail("Sequence \"%s\" is linked to table \"%s\".",
+                                                          RelationGetRelationName(rel),
+                                                          get_rel_name(tableId))));
+       }
 
        /* get schema OID and check its permissions */
        nspOid = LookupCreationNamespace(newschema);
@@ -6699,7 +6699,7 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
        HeapTuple       tup;
 
        /*
-        * SERIAL sequences are those having an internal dependency on one of the
+        * SERIAL sequences are those having an auto dependency on one of the
         * table's columns (we don't care *which* column, exactly).
         */
        depRel = heap_open(DependRelationId, AccessShareLock);
@@ -6722,11 +6722,11 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
                Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
                Relation        seqRel;
 
-               /* skip dependencies other than internal dependencies on columns */
+               /* skip dependencies other than auto dependencies on columns */
                if (depForm->refobjsubid == 0 ||
                        depForm->classid != RelationRelationId ||
                        depForm->objsubid != 0 ||
-                       depForm->deptype != DEPENDENCY_INTERNAL)
+                       depForm->deptype != DEPENDENCY_AUTO)
                        continue;
 
                /* Use relation_open just in case it's an index */
index 63850cb..df7f479 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.96 2006/07/13 16:49:14 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.97 2006/08/21 00:57:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -126,7 +126,6 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
                        def->raw_default = NULL;
                        def->cooked_default = NULL;
                        def->constraints = NIL;
-                       def->support = NULL;
 
                        attrList = lappend(attrList, def);
                }
index 2b8f3af..40e35a3 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.347 2006/08/12 02:52:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.348 2006/08/21 00:57:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1641,7 +1641,6 @@ _copyColumnDef(ColumnDef *from)
        COPY_NODE_FIELD(raw_default);
        COPY_STRING_FIELD(cooked_default);
        COPY_NODE_FIELD(constraints);
-       COPY_NODE_FIELD(support);
 
        return newnode;
 }
index 665d483..b4d0632 100644 (file)
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.281 2006/08/12 02:52:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.282 2006/08/21 00:57:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1665,7 +1665,6 @@ _equalColumnDef(ColumnDef *a, ColumnDef *b)
        COMPARE_NODE_FIELD(raw_default);
        COMPARE_STRING_FIELD(cooked_default);
        COMPARE_NODE_FIELD(constraints);
-       COMPARE_NODE_FIELD(support);
 
        return true;
 }
index 784dd57..7555cbd 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.50 2006/03/14 22:48:19 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.51 2006/08/21 00:57:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -322,3 +322,17 @@ makeFuncExpr(Oid funcid, Oid rettype, List *args, CoercionForm fformat)
 
        return funcexpr;
 }
+
+/*
+ * makeDefElem -
+ *     build a DefElem node
+ */
+DefElem *
+makeDefElem(char *name, Node *arg)
+{
+       DefElem *res = makeNode(DefElem);
+
+       res->defname = name;
+       res->arg = arg;
+       return res;
+}
index a1ed403..a4b4044 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.282 2006/08/12 02:52:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.283 2006/08/21 00:57:24 tgl Exp $
  *
  * NOTES
  *       Every node type that can appear in stored rules' parsetrees *must*
@@ -1444,7 +1444,6 @@ _outColumnDef(StringInfo str, ColumnDef *node)
        WRITE_NODE_FIELD(raw_default);
        WRITE_STRING_FIELD(cooked_default);
        WRITE_NODE_FIELD(constraints);
-       WRITE_NODE_FIELD(support);
 }
 
 static void
index 39c7372..8eb50fb 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.346 2006/08/12 20:05:55 tgl Exp $
+ *     $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.347 2006/08/21 00:57:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -980,6 +980,14 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
                }
        }
 
+       /*
+        * transformIndexConstraints wants cxt.alist to contain only index
+        * statements, so transfer anything we already have into extras_after
+        * immediately.
+        */
+       *extras_after = list_concat(cxt.alist, *extras_after);
+       cxt.alist = NIL;
+
        Assert(stmt->constraints == NIL);
 
        /*
@@ -1052,6 +1060,8 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                A_Const    *snamenode;
                FuncCall   *funccallnode;
                CreateSeqStmt *seqstmt;
+               AlterSeqStmt *altseqstmt;
+               List       *attnamelist;
 
                /*
                 * Determine namespace and name to use for the sequence.
@@ -1088,10 +1098,19 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                cxt->blist = lappend(cxt->blist, seqstmt);
 
                /*
-                * Mark the ColumnDef so that during execution, an appropriate
-                * dependency will be added from the sequence to the column.
+                * Build an ALTER SEQUENCE ... OWNED BY command to mark the sequence
+                * as owned by this column, and add it to the list of things to be
+                * done after this CREATE/ALTER TABLE.
                 */
-               column->support = makeRangeVar(snamespace, sname);
+               altseqstmt = makeNode(AlterSeqStmt);
+               altseqstmt->sequence = makeRangeVar(snamespace, sname);
+               attnamelist = list_make3(makeString(snamespace),
+                                                                makeString(cxt->relation->relname),
+                                                                makeString(column->colname));
+               altseqstmt->options = list_make1(makeDefElem("owned_by",
+                                                                                                        (Node *) attnamelist));
+
+               cxt->alist = lappend(cxt->alist, altseqstmt);
 
                /*
                 * Create appropriate constraints for SERIAL.  We do this in full,
@@ -1349,7 +1368,6 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
                def->raw_default = NULL;
                def->cooked_default = NULL;
                def->constraints = NIL;
-               def->support = NULL;
 
                /*
                 * Add to column list
@@ -1604,7 +1622,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
         * XXX in ALTER TABLE case, it'd be nice to look for duplicate
         * pre-existing indexes, too.
         */
-       cxt->alist = NIL;
+       Assert(cxt->alist == NIL);
        if (cxt->pkey != NULL)
        {
                /* Make sure we keep the PKEY index in preference to others... */
@@ -3041,6 +3059,14 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
                }
        }
 
+       /*
+        * transformIndexConstraints wants cxt.alist to contain only index
+        * statements, so transfer anything we already have into extras_after
+        * immediately.
+        */
+       *extras_after = list_concat(cxt.alist, *extras_after);
+       cxt.alist = NIL;
+
        /* Postprocess index and FK constraints */
        transformIndexConstraints(pstate, &cxt);
 
index c0744a7..60761ae 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.556 2006/08/12 18:58:54 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.557 2006/08/21 00:57:25 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -95,7 +95,6 @@ static Node *makeIntConst(int val);
 static Node *makeFloatConst(char *str);
 static Node *makeAConst(Value *v);
 static Node *makeRowNullTest(NullTestType test, RowExpr *row);
-static DefElem *makeDefElem(char *name, Node *arg);
 static A_Const *makeBoolAConst(bool state);
 static FuncCall *makeOverlaps(List *largs, List *rargs, int location);
 static void check_qualified_name(List *names);
@@ -2275,7 +2274,6 @@ CreateAsElement:
                                        n->raw_default = NULL;
                                        n->cooked_default = NULL;
                                        n->constraints = NIL;
-                                       n->support = NULL;
                                        $$ = (Node *)n;
                                }
                ;
@@ -2346,6 +2344,10 @@ OptSeqElem: CACHE NumericOnly
                                {
                                        $$ = makeDefElem("minvalue", NULL);
                                }
+                       | OWNED BY any_name
+                               {
+                                       $$ = makeDefElem("owned_by", (Node *)$3);
+                               }
                        | START opt_with NumericOnly
                                {
                                        $$ = makeDefElem("start", (Node *)$3);
@@ -8977,19 +8979,6 @@ makeAConst(Value *v)
        return n;
 }
 
-/* makeDefElem()
- * Create a DefElem node and set contents.
- * Could be moved to nodes/makefuncs.c if this is useful elsewhere.
- */
-static DefElem *
-makeDefElem(char *name, Node *arg)
-{
-       DefElem *f = makeNode(DefElem);
-       f->defname = name;
-       f->arg = arg;
-       return f;
-}
-
 /* makeBoolAConst()
  * Create an A_Const node and initialize to a boolean constant.
  */
index e814310..a88f5ef 100644 (file)
@@ -2,7 +2,7 @@
  * ruleutils.c - Functions to convert stored expressions/querytrees
  *                             back to source text
  *
- *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.231 2006/08/12 02:52:05 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.232 2006/08/21 00:57:25 tgl Exp $
  **********************************************************************/
 
 #include "postgres.h"
@@ -1287,12 +1287,12 @@ pg_get_serial_sequence(PG_FUNCTION_ARGS)
                Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
 
                /*
-                * We assume any internal dependency of a relation on a column must be
+                * We assume any auto dependency of a relation on a column must be
                 * what we are looking for.
                 */
                if (deprec->classid == RelationRelationId &&
                        deprec->objsubid == 0 &&
-                       deprec->deptype == DEPENDENCY_INTERNAL)
+                       deprec->deptype == DEPENDENCY_AUTO)
                {
                        sequenceId = deprec->objid;
                        break;
index d48cd25..78a653f 100644 (file)
@@ -12,7 +12,7 @@
  *     by PostgreSQL
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.446 2006/08/04 18:32:15 momjian Exp $
+ *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.447 2006/08/21 00:57:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2833,14 +2833,14 @@ getTables(int *numTables)
         * Note: in this phase we should collect only a minimal amount of
         * information about each table, basically just enough to decide if it is
         * interesting. We must fetch all tables in this phase because otherwise
-        * we cannot correctly identify inherited columns, serial columns, etc.
+        * we cannot correctly identify inherited columns, owned sequences, etc.
         */
 
        if (g_fout->remoteVersion >= 80200)
        {
                /*
                 * Left join to pick up dependency info linking sequences to their
-                * serial column, if any
+                * owning column, if any (note this dependency is AUTO as of 8.2)
                 */
                appendPQExpBuffer(query,
                                                  "SELECT c.tableoid, c.oid, relname, "
@@ -2857,7 +2857,7 @@ getTables(int *numTables)
                                                  "(c.relkind = '%c' and "
                                                  "d.classid = c.tableoid and d.objid = c.oid and "
                                                  "d.objsubid = 0 and "
-                                                 "d.refclassid = c.tableoid and d.deptype = 'i') "
+                                                 "d.refclassid = c.tableoid and d.deptype = 'a') "
                                                  "where relkind in ('%c', '%c', '%c', '%c') "
                                                  "order by c.oid",
                                                  username_subquery,
@@ -2869,7 +2869,7 @@ getTables(int *numTables)
        {
                /*
                 * Left join to pick up dependency info linking sequences to their
-                * serial column, if any
+                * owning column, if any
                 */
                appendPQExpBuffer(query,
                                                  "SELECT c.tableoid, c.oid, relname, "
@@ -2898,7 +2898,7 @@ getTables(int *numTables)
        {
                /*
                 * Left join to pick up dependency info linking sequences to their
-                * serial column, if any
+                * owning column, if any
                 */
                appendPQExpBuffer(query,
                                                  "SELECT c.tableoid, c.oid, relname, "
@@ -3061,14 +3061,10 @@ getTables(int *numTables)
                /* other fields were zeroed above */
 
                /*
-                * Decide whether we want to dump this table.  Sequences owned by
-                * serial columns are never dumpable on their own; we will transpose
-                * their owning table's dump flag to them below.
+                * Decide whether we want to dump this table.
                 */
                if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
                        tblinfo[i].dobj.dump = false;
-               else if (OidIsValid(tblinfo[i].owning_tab))
-                       tblinfo[i].dobj.dump = false;
                else
                        selectDumpableTable(&tblinfo[i]);
                tblinfo[i].interesting = tblinfo[i].dobj.dump;
@@ -3101,6 +3097,36 @@ getTables(int *numTables)
        }
 
        PQclear(res);
+
+       /*
+        * Force sequences that are "owned" by table columns to be dumped
+        * whenever their owning table is being dumped.
+        */
+       for (i = 0; i < ntups; i++)
+       {
+               TableInfo  *seqinfo = &tblinfo[i];
+               int             j;
+
+               if (!OidIsValid(seqinfo->owning_tab))
+                       continue;                       /* not an owned sequence */
+               if (seqinfo->dobj.dump)
+                       continue;                       /* no need to search */
+
+               /* can't use findTableByOid yet, unfortunately */
+               for (j = 0; j < ntups; j++)
+               {
+                       if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
+                       {
+                               if (tblinfo[j].dobj.dump)
+                               {
+                                       seqinfo->interesting = true;
+                                       seqinfo->dobj.dump = true;
+                               }
+                               break;
+                       }
+               }
+       }
+
        destroyPQExpBuffer(query);
        destroyPQExpBuffer(delqry);
        destroyPQExpBuffer(lockquery);
@@ -4161,8 +4187,7 @@ void
 getTableAttrs(TableInfo *tblinfo, int numTables)
 {
        int                     i,
-                               j,
-                               k;
+                               j;
        PQExpBuffer q = createPQExpBuffer();
        int                     i_attnum;
        int                     i_attname;
@@ -4281,7 +4306,6 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
                tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
                tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool));
-               tbinfo->attisserial = (bool *) malloc(ntups * sizeof(bool));
                tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
                tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
                tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
@@ -4305,7 +4329,6 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                        tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
                        tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
                        tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
-                       tbinfo->attisserial[j] = false;         /* fix below */
                        tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
                        tbinfo->attrdefs[j] = NULL; /* fix below */
                        if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
@@ -4538,44 +4561,6 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                        }
                        PQclear(res);
                }
-
-               /*
-                * Check to see if any columns are serial columns.      Our first quick
-                * filter is that it must be integer or bigint with a default.  If so,
-                * we scan to see if we found a sequence linked to this column. If we
-                * did, mark the column and sequence appropriately.
-                */
-               for (j = 0; j < ntups; j++)
-               {
-                       /*
-                        * Note assumption that format_type will show these types as
-                        * exactly "integer" and "bigint" regardless of schema path. This
-                        * is correct in 7.3 but needs to be watched.
-                        */
-                       if (strcmp(tbinfo->atttypnames[j], "integer") != 0 &&
-                               strcmp(tbinfo->atttypnames[j], "bigint") != 0)
-                               continue;
-                       if (tbinfo->attrdefs[j] == NULL)
-                               continue;
-                       for (k = 0; k < numTables; k++)
-                       {
-                               TableInfo  *seqinfo = &tblinfo[k];
-
-                               if (OidIsValid(seqinfo->owning_tab) &&
-                                       seqinfo->owning_tab == tbinfo->dobj.catId.oid &&
-                                       seqinfo->owning_col == j + 1)
-                               {
-                                       /*
-                                        * Found a match.  Copy the table's interesting and
-                                        * dumpable flags to the sequence.
-                                        */
-                                       tbinfo->attisserial[j] = true;
-                                       seqinfo->interesting = tbinfo->interesting;
-                                       seqinfo->dobj.dump = tbinfo->dobj.dump;
-                                       break;
-                               }
-                       }
-               }
        }
 
        destroyPQExpBuffer(q);
@@ -7403,16 +7388,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                                /* Attribute type */
                                if (g_fout->remoteVersion >= 70100)
                                {
-                                       char       *typname = tbinfo->atttypnames[j];
-
-                                       if (tbinfo->attisserial[j])
-                                       {
-                                               if (strcmp(typname, "integer") == 0)
-                                                       typname = "serial";
-                                               else if (strcmp(typname, "bigint") == 0)
-                                                       typname = "bigserial";
-                                       }
-                                       appendPQExpBuffer(q, "%s", typname);
+                                       appendPQExpBuffer(q, "%s",
+                                                                         tbinfo->atttypnames[j]);
                                }
                                else
                                {
@@ -7423,24 +7400,17 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                                }
 
                                /*
-                                * Default value --- suppress if inherited, serial, or to be
+                                * Default value --- suppress if inherited or to be
                                 * printed separately.
                                 */
                                if (tbinfo->attrdefs[j] != NULL &&
                                        !tbinfo->inhAttrDef[j] &&
-                                       !tbinfo->attisserial[j] &&
                                        !tbinfo->attrdefs[j]->separate)
                                        appendPQExpBuffer(q, " DEFAULT %s",
                                                                          tbinfo->attrdefs[j]->adef_expr);
 
                                /*
                                 * Not Null constraint --- suppress if inherited
-                                *
-                                * Note: we could suppress this for serial columns since
-                                * SERIAL implies NOT NULL.  We choose not to for forward
-                                * compatibility, since there has been some talk of making
-                                * SERIAL not imply NOT NULL, in which case the explicit
-                                * specification would be needed.
                                 */
                                if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
                                        appendPQExpBuffer(q, " NOT NULL");
@@ -7597,8 +7567,8 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
        if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
                return;
 
-       /* Don't print inherited or serial defaults, either */
-       if (tbinfo->inhAttrDef[adnum - 1] || tbinfo->attisserial[adnum - 1])
+       /* Don't print inherited defaults, either */
+       if (tbinfo->inhAttrDef[adnum - 1])
                return;
 
        q = createPQExpBuffer();
@@ -8111,15 +8081,14 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
        /*
         * The logic we use for restoring sequences is as follows:
         *
-        * Add a basic CREATE SEQUENCE statement (use last_val for start if called
-        * is false, else use min_val for start_val).  Skip this if the sequence
-        * came from a SERIAL column.
+        * Add a CREATE SEQUENCE statement as part of a "schema" dump
+        * (use last_val for start if called is false, else use min_val for
+        * start_val).  Also, if the sequence is owned by a column, add an
+        * ALTER SEQUENCE SET OWNED command for it.
         *
-        * Add a 'SETVAL(seq, last_val, iscalled)' at restore-time iff we load
-        * data. We do this for serial sequences too.
+        * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
         */
-
-       if (!dataOnly && !OidIsValid(tbinfo->owning_tab))
+       if (!dataOnly)
        {
                resetPQExpBuffer(delqry);
 
@@ -8166,32 +8135,57 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
                                         false, "SEQUENCE", query->data, delqry->data, NULL,
                                         tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
                                         NULL, NULL);
+
+               /*
+                * If the sequence is owned by a table column, emit the ALTER for it
+                * as a separate TOC entry immediately following the sequence's own
+                * entry.  It's OK to do this rather than using full sorting logic,
+                * because the dependency that tells us it's owned will have forced
+                * the table to be created first.  We can't just include the ALTER
+                * in the TOC entry because it will fail if we haven't reassigned
+                * the sequence owner to match the table's owner.
+                *
+                * We need not schema-qualify the table reference because both
+                * sequence and table must be in the same schema.
+                */
+               if (OidIsValid(tbinfo->owning_tab))
+               {
+                       TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
+
+                       if (owning_tab)
+                       {
+                               resetPQExpBuffer(query);
+                               appendPQExpBuffer(query, "ALTER SEQUENCE %s",
+                                                                 fmtId(tbinfo->dobj.name));
+                               appendPQExpBuffer(query, " OWNED BY %s",
+                                                                 fmtId(owning_tab->dobj.name));
+                               appendPQExpBuffer(query, ".%s;\n",
+                                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
+
+                               ArchiveEntry(fout, nilCatalogId, createDumpId(),
+                                                        tbinfo->dobj.name,
+                                                        tbinfo->dobj.namespace->dobj.name,
+                                                        NULL,
+                                                        tbinfo->rolname,
+                                                        false, "SEQUENCE OWNED BY", query->data, "", NULL,
+                                                        &(tbinfo->dobj.dumpId), 1,
+                                                        NULL, NULL);
+                       }
+               }
+
+               /* Dump Sequence Comments */
+               resetPQExpBuffer(query);
+               appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
+               dumpComment(fout, query->data,
+                                       tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+                                       tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
        }
 
        if (!schemaOnly)
        {
-               TableInfo  *owning_tab;
-
                resetPQExpBuffer(query);
                appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
-
-               /*
-                * If this is a SERIAL sequence, then use the pg_get_serial_sequence
-                * function to avoid hard-coding the sequence name.  Note that this
-                * implicitly assumes that the sequence and its owning table are in
-                * the same schema, because we don't schema-qualify the reference.
-                */
-               if (OidIsValid(tbinfo->owning_tab) &&
-                       (owning_tab = findTableByOid(tbinfo->owning_tab)) != NULL)
-               {
-                       appendPQExpBuffer(query, "pg_catalog.pg_get_serial_sequence(");
-                       appendStringLiteralAH(query, fmtId(owning_tab->dobj.name), fout);
-                       appendPQExpBuffer(query, ", ");
-                       appendStringLiteralAH(query, owning_tab->attnames[tbinfo->owning_col - 1], fout);
-                       appendPQExpBuffer(query, ")");
-               }
-               else
-                       appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
+               appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
                appendPQExpBuffer(query, ", %s, %s);\n",
                                                  last, (called ? "true" : "false"));
 
@@ -8205,16 +8199,6 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
                                         NULL, NULL);
        }
 
-       if (!dataOnly)
-       {
-               /* Dump Sequence Comments */
-               resetPQExpBuffer(query);
-               appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
-               dumpComment(fout, query->data,
-                                       tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-                                       tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
-       }
-
        PQclear(res);
 
        destroyPQExpBuffer(query);
index 3650ae5..65f5e84 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.128 2006/08/01 18:05:04 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.129 2006/08/21 00:57:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -185,7 +185,7 @@ typedef struct _tableInfo
        bool            hasoids;                /* does it have OIDs? */
        int                     ncheck;                 /* # of CHECK expressions */
        int                     ntrig;                  /* # of triggers */
-       /* these two are set only if table is a SERIAL column's sequence: */
+       /* these two are set only if table is a sequence owned by a column: */
        Oid                     owning_tab;             /* OID of table owning sequence */
        int                     owning_col;             /* attr # of column owning sequence */
 
@@ -204,7 +204,6 @@ typedef struct _tableInfo
        char       *typstorage;         /* type storage scheme */
        bool       *attisdropped;       /* true if attr is dropped; don't dump it */
        bool       *attislocal;         /* true if attr has local definition */
-       bool       *attisserial;        /* true if attr is serial or bigserial */
 
        /*
         * Note: we need to store per-attribute notnull, default, and constraint
index b27acf5..448f9e4 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.351 2006/08/19 01:36:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.352 2006/08/21 00:57:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200608181
+#define CATALOG_VERSION_NO     200608191
 
 #endif
index 04dc3ac..da7d7ac 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.26 2006/08/20 21:56:16 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.27 2006/08/21 00:57:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -112,7 +112,7 @@ typedef struct ObjectAddress
        int32           objectSubId;    /* Subitem within the object (column of table) */
 } ObjectAddress;
 
-/* expansible list of ObjectAddresses */
+/* expansible list of ObjectAddresses (private in dependency.c) */
 typedef struct ObjectAddresses ObjectAddresses;
 
 /*
@@ -192,7 +192,9 @@ extern long changeDependencyFor(Oid classId, Oid objectId,
                                        Oid refClassId, Oid oldRefObjectId,
                                        Oid newRefObjectId);
 
-extern bool objectIsInternalDependency(Oid classId, Oid objectId);
+extern bool sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId);
+
+extern void markSequenceUnowned(Oid seqId);
 
 /* in pg_shdepend.c */
 
index 23cb002..3118cfb 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.55 2006/03/14 22:48:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.56 2006/08/21 00:57:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -62,4 +62,6 @@ extern TypeName *makeTypeNameFromOid(Oid typeid, int32 typmod);
 extern FuncExpr *makeFuncExpr(Oid funcid, Oid rettype,
                         List *args, CoercionForm fformat);
 
+extern DefElem *makeDefElem(char *name, Node *arg);
+
 #endif   /* MAKEFUNC_H */
index 222f5d2..a3ae58d 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.323 2006/08/12 20:05:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.324 2006/08/21 00:57:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -393,10 +393,6 @@ typedef struct RangeFunction
  * parsetree produced by gram.y, but transformCreateStmt will remove
  * the item and set raw_default instead.  CONSTR_DEFAULT items
  * should not appear in any subsequent processing.
- *
- * The "support" field, if not null, denotes a supporting relation that
- * should be linked by an internal dependency to the column.  Currently
- * this is only used to link a SERIAL column's sequence to the column.
  */
 typedef struct ColumnDef
 {
@@ -409,7 +405,6 @@ typedef struct ColumnDef
        Node       *raw_default;        /* default value (untransformed parse tree) */
        char       *cooked_default; /* nodeToString representation */
        List       *constraints;        /* other constraints on column */
-       RangeVar   *support;            /* supporting relation, if any */
 } ColumnDef;
 
 /*
index 3e15228..e664a15 100644 (file)
@@ -1443,6 +1443,6 @@ NOTICE:  drop cascades to function alter2.plus1(integer)
 NOTICE:  drop cascades to view alter2.v1
 NOTICE:  drop cascades to rule _RETURN on view alter2.v1
 NOTICE:  drop cascades to sequence alter2.t1_f1_seq
-NOTICE:  drop cascades to table alter2.t1 column f1
+NOTICE:  drop cascades to default for table alter2.t1 column f1
 NOTICE:  drop cascades to table alter2.t1
 NOTICE:  drop cascades to constraint t1_f2_check on table alter2.t1
index 4781b5f..ba65a35 100644 (file)
@@ -58,7 +58,8 @@ REASSIGN OWNED BY regression_user1 TO regression_user0;
 ERROR:  permission denied to reassign objects
 -- this one is allowed
 DROP OWNED BY regression_user0;
-CREATE TABLE deptest1 ();
+CREATE TABLE deptest1 (f1 int unique);
+NOTICE:  CREATE TABLE / UNIQUE will create implicit index "deptest1_f1_key" for table "deptest1"
 GRANT ALL ON deptest1 TO regression_user1 WITH GRANT OPTION;
 SET SESSION AUTHORIZATION regression_user1;
 CREATE TABLE deptest (a serial primary key, b text);
@@ -90,6 +91,11 @@ SET SESSION AUTHORIZATION regression_user1;
 CREATE TABLE deptest (a serial primary key, b text);
 NOTICE:  CREATE TABLE will create implicit sequence "deptest_a_seq" for serial column "deptest.a"
 NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "deptest_pkey" for table "deptest"
+CREATE TABLE deptest2 (f1 int);
+-- make a serial column the hard way
+CREATE SEQUENCE ss1;
+ALTER TABLE deptest2 ALTER f1 SET DEFAULT nextval('ss1');
+ALTER SEQUENCE ss1 OWNED BY deptest2.f1;
 RESET SESSION AUTHORIZATION;
 REASSIGN OWNED BY regression_user1 TO regression_user2;
 \dt deptest
index 646bb63..a9f3e4a 100644 (file)
@@ -42,6 +42,7 @@ DROP SCHEMA test_schema_1 CASCADE;
 NOTICE:  drop cascades to view test_schema_1.abc_view
 NOTICE:  drop cascades to rule _RETURN on view test_schema_1.abc_view
 NOTICE:  drop cascades to table test_schema_1.abc
+NOTICE:  drop cascades to default for table test_schema_1.abc column a
 -- verify that the objects were dropped
 SELECT COUNT(*) FROM pg_class WHERE relnamespace =
     (SELECT oid FROM pg_namespace WHERE nspname = 'test_schema_1');
index ca9ece2..0576b57 100644 (file)
@@ -130,8 +130,9 @@ CREATE TEMP TABLE t1 (
 NOTICE:  CREATE TABLE will create implicit sequence "t1_f1_seq" for serial column "t1.f1"
 -- Both drops should fail, but with different error messages:
 DROP SEQUENCE t1_f1_seq;
-ERROR:  cannot drop sequence t1_f1_seq because table t1 column f1 requires it
-HINT:  You may drop table t1 column f1 instead.
+NOTICE:  default for table t1 column f1 depends on sequence t1_f1_seq
+ERROR:  cannot drop sequence t1_f1_seq because other objects depend on it
+HINT:  Use DROP ... CASCADE to drop the dependent objects too.
 DROP SEQUENCE myseq2;
 NOTICE:  default for table t1 column f2 depends on sequence myseq2
 ERROR:  cannot drop sequence myseq2 because other objects depend on it
index c1b189f..6f8e0e8 100644 (file)
@@ -57,7 +57,7 @@ REASSIGN OWNED BY regression_user1 TO regression_user0;
 -- this one is allowed
 DROP OWNED BY regression_user0;
 
-CREATE TABLE deptest1 ();
+CREATE TABLE deptest1 (f1 int unique);
 GRANT ALL ON deptest1 TO regression_user1 WITH GRANT OPTION;
 
 SET SESSION AUTHORIZATION regression_user1;
@@ -77,10 +77,17 @@ GRANT ALL ON deptest1 TO regression_user1;
 
 SET SESSION AUTHORIZATION regression_user1;
 CREATE TABLE deptest (a serial primary key, b text);
+
+CREATE TABLE deptest2 (f1 int);
+-- make a serial column the hard way
+CREATE SEQUENCE ss1;
+ALTER TABLE deptest2 ALTER f1 SET DEFAULT nextval('ss1');
+ALTER SEQUENCE ss1 OWNED BY deptest2.f1;
 RESET SESSION AUTHORIZATION;
 
 REASSIGN OWNED BY regression_user1 TO regression_user2;
 \dt deptest
+
 -- doesn't work: grant still exists
 DROP USER regression_user1;
 DROP OWNED BY regression_user1;