]> granicus.if.org Git - postgresql/commitdiff
Fix pg_dump to dump serial columns as serials. Per pghackers discussion,
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 19 Aug 2002 19:33:36 +0000 (19:33 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 19 Aug 2002 19:33:36 +0000 (19:33 +0000)
cause SERIAL column declaration not to imply UNIQUE, so that this can be
done without creating an extra index.

doc/src/sgml/datatype.sgml
doc/src/sgml/release.sgml
src/backend/parser/analyze.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/test/regress/expected/copy2.out
src/test/regress/expected/create_misc.out
src/test/regress/expected/sanity_check.out

index bf53769a1e0d8219c4fa4369c2523a4023456130..aa4e25ccb60cb86c2ec6c434495702e879ef3235 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.98 2002/08/13 20:40:43 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.99 2002/08/19 19:33:33 tgl Exp $
 -->
 
  <chapter id="datatype">
@@ -665,14 +665,17 @@ 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') UNIQUE NOT NULL
+    <replaceable class="parameter">colname</replaceable> integer DEFAULT nextval('<replaceable class="parameter">tablename</replaceable>_<replaceable class="parameter">colname</replaceable>_seq') NOT NULL
 );
 </programlisting>
 
      Thus, we have created an integer column and arranged for its default
-     values to be assigned from a sequence generator.  UNIQUE and NOT NULL
-     constraints are applied to ensure that explicitly-inserted values
-     will never be duplicates, either.
+     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
+     <literal>UNIQUE</> or <literal>PRIMARY KEY</> constraint to prevent
+     duplicate values from being inserted by accident, but this is
+     not automatic.
     </para>
 
     <para>
@@ -685,20 +688,23 @@ CREATE TABLE <replaceable class="parameter">tablename</replaceable> (
     </para>
 
     <para>
-     Implicit sequences supporting the <type>serial</type> types are
-     not automatically dropped when a table containing a serial type
-     is dropped. So, the following commands executed in order will likely fail:
-
-<programlisting>
-CREATE TABLE <replaceable class="parameter">tablename</replaceable> (<replaceable class="parameter">colname</replaceable> SERIAL);
-DROP TABLE <replaceable class="parameter">tablename</replaceable>;
-CREATE TABLE <replaceable class="parameter">tablename</replaceable> (<replaceable class="parameter">colname</replaceable> SERIAL);
-</programlisting>
-
-     The sequence will remain in the database until explicitly dropped using
-     <command>DROP SEQUENCE</command>.  (This annoyance will probably be
-     fixed in some future release.)
+     The sequence created by a <type>serial</type> type 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.)
     </para>
+
+    <note><para>
+     Prior to <productname>PostgreSQL</productname> 7.3, <type>serial</type>
+     implied <literal>UNIQUE</literal>.  This is no longer automatic.  If
+     you wish a serial column to be <literal>UNIQUE</literal> or a 
+     <literal>PRIMARY KEY</literal> it must now be specified, same as with
+     any other datatype.
+    </para></note>
    </sect2>
   </sect1>
 
index 9bfc6de17b05fc262784f8427f84d1cbe36ddfa5..1878fd356efa9e04d12d4fe52c8ea3cf1a327eea 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.147 2002/08/18 09:36:25 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.148 2002/08/19 19:33:34 tgl Exp $
 -->
 
 <appendix id="release">
@@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
 worries about funny characters.
 -->
 <literallayout><![CDATA[
+SERIAL no longer implies UNIQUE; specify explicitly if index is wanted
 pg_dump -n and -N options have been removed.  The new behavior is like -n but knows about key words.
 CLUSTER is no longer hazardous to your schema
 COPY accepts a list of columns to copy
index 94a367885e34fe700a276acff540adfd9cc73672..1890f01c6f066bb24fd04fe9a259ef2e7fe185b8 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.241 2002/08/19 15:08:47 tgl Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.242 2002/08/19 19:33:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -876,11 +876,6 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                constraint->keys = NIL;
                column->constraints = lappend(column->constraints, constraint);
 
-               constraint = makeNode(Constraint);
-               constraint->contype = CONSTR_UNIQUE;
-               constraint->name = NULL;        /* assign later */
-               column->constraints = lappend(column->constraints, constraint);
-
                constraint = makeNode(Constraint);
                constraint->contype = CONSTR_NOTNULL;
                column->constraints = lappend(column->constraints, constraint);
@@ -1209,10 +1204,9 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
 
        /*
         * Scan the index list and remove any redundant index specifications.
-        * This can happen if, for instance, the user writes SERIAL PRIMARY
-        * KEY or SERIAL UNIQUE.  A strict reading of SQL92 would suggest
-        * raising an error instead, but that strikes me as too
-        * anal-retentive. - tgl 2001-02-14
+        * This can happen if, for instance, the user writes UNIQUE PRIMARY KEY.
+        * A strict reading of SQL92 would suggest raising an error instead,
+        * but that strikes me as too anal-retentive. - tgl 2001-02-14
         *
         * XXX in ALTER TABLE case, it'd be nice to look for duplicate
         * pre-existing indexes, too.
@@ -1262,7 +1256,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
 
        /*
         * Finally, select unique names for all not-previously-named indices,
-        * and display WARNING messages.
+        * and display NOTICE messages.
         *
         * XXX in ALTER TABLE case, we fail to consider name collisions against
         * pre-existing indexes.
index 031677424f6eec821dd23b86ec4ee5d2aac8cc3d..abe6a0238e67cb6b3f37b7242b3f932c411473d9 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.286 2002/08/18 21:05:32 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.287 2002/08/19 19:33:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2056,6 +2056,8 @@ getTables(int *numTables)
        int                     i_relhasindex;
        int                     i_relhasrules;
        int                     i_relhasoids;
+       int                     i_owning_tab;
+       int                     i_owning_col;
 
        /* Make sure we are in proper schema */
        selectSourceSchema("pg_catalog");
@@ -2071,20 +2073,34 @@ 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.
+        * it is interesting.  We must fetch all tables in this phase because
+        * otherwise we cannot correctly identify inherited columns, serial
+        * columns, etc.
         */
 
        if (g_fout->remoteVersion >= 70300)
        {
+               /*
+                * Left join to pick up dependency info linking sequences to their
+                * serial column, if any
+                */
                appendPQExpBuffer(query,
-                                                 "SELECT pg_class.oid, relname, relacl, relkind, "
+                                                 "SELECT c.oid, relname, relacl, relkind, "
                                                  "relnamespace, "
                                                  "(select usename from pg_user where relowner = usesysid) as usename, "
                                                  "relchecks, reltriggers, "
-                                                 "relhasindex, relhasrules, relhasoids "
-                                                 "from pg_class "
+                                                 "relhasindex, relhasrules, relhasoids, "
+                                                 "d.refobjid as owning_tab, "
+                                                 "d.refobjsubid as owning_col "
+                                                 "from pg_class c "
+                                                 "left join pg_depend d on "
+                                                 "(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') "
                                                  "where relkind in ('%c', '%c', '%c') "
-                                                 "order by oid",
+                                                 "order by c.oid",
+                                                 RELKIND_SEQUENCE,
                                                  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
        }
        else if (g_fout->remoteVersion >= 70200)
@@ -2095,7 +2111,9 @@ getTables(int *numTables)
                                                  "0::oid as relnamespace, "
                                                  "(select usename from pg_user where relowner = usesysid) as usename, "
                                                  "relchecks, reltriggers, "
-                                                 "relhasindex, relhasrules, relhasoids "
+                                                 "relhasindex, relhasrules, relhasoids, "
+                                                 "NULL::oid as owning_tab, "
+                                                 "NULL::int4 as owning_col "
                                                  "from pg_class "
                                                  "where relkind in ('%c', '%c', '%c') "
                                                  "order by oid",
@@ -2109,7 +2127,10 @@ getTables(int *numTables)
                                                  "0::oid as relnamespace, "
                                                  "(select usename from pg_user where relowner = usesysid) as usename, "
                                                  "relchecks, reltriggers, "
-                                                 "relhasindex, relhasrules, 't'::bool as relhasoids "
+                                                 "relhasindex, relhasrules, "
+                                                 "'t'::bool as relhasoids, "
+                                                 "NULL::oid as owning_tab, "
+                                                 "NULL::int4 as owning_col "
                                                  "from pg_class "
                                                  "where relkind in ('%c', '%c', '%c') "
                                                  "order by oid",
@@ -2131,7 +2152,10 @@ getTables(int *numTables)
                                                  "0::oid as relnamespace, "
                                                  "(select usename from pg_user where relowner = usesysid) as usename, "
                                                  "relchecks, reltriggers, "
-                                                 "relhasindex, relhasrules, 't'::bool as relhasoids "
+                                                 "relhasindex, relhasrules, "
+                                                 "'t'::bool as relhasoids, "
+                                                 "NULL::oid as owning_tab, "
+                                                 "NULL::int4 as owning_col "
                                                  "from pg_class c "
                                                  "where relkind in ('%c', '%c') "
                                                  "order by oid",
@@ -2175,6 +2199,8 @@ getTables(int *numTables)
        i_relhasindex = PQfnumber(res, "relhasindex");
        i_relhasrules = PQfnumber(res, "relhasrules");
        i_relhasoids = PQfnumber(res, "relhasoids");
+       i_owning_tab = PQfnumber(res, "owning_tab");
+       i_owning_col = PQfnumber(res, "owning_col");
 
        for (i = 0; i < ntups; i++)
        {
@@ -2190,13 +2216,28 @@ getTables(int *numTables)
                tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
                tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
                tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
+               if (PQgetisnull(res, i, i_owning_tab))
+               {
+                       tblinfo[i].owning_tab = NULL;
+                       tblinfo[i].owning_col = 0;
+               }
+               else
+               {
+                       tblinfo[i].owning_tab = strdup(PQgetvalue(res, i, i_owning_tab));
+                       tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
+               }
 
                /* other fields were zeroed above */
 
                /*
-                * Decide whether we want to dump this table.
+                * 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.
                 */
-               selectDumpableTable(&tblinfo[i]);
+               if (tblinfo[i].owning_tab == NULL)
+                       selectDumpableTable(&tblinfo[i]);
+               else
+                       tblinfo[i].dump = false;
                tblinfo[i].interesting = tblinfo[i].dump;
 
                /*
@@ -2314,7 +2355,8 @@ void
 getTableAttrs(TableInfo *tblinfo, int numTables)
 {
        int                     i,
-                               j;
+                               j,
+                               k;
        PQExpBuffer q = createPQExpBuffer();
        int                     i_attname;
        int                     i_atttypname;
@@ -2329,23 +2371,25 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 
        for (i = 0; i < numTables; i++)
        {
+               TableInfo *tbinfo = &tblinfo[i];
+
                /* Don't bother to collect info for sequences */
-               if (tblinfo[i].relkind == RELKIND_SEQUENCE)
+               if (tbinfo->relkind == RELKIND_SEQUENCE)
                        continue;
 
                /* Don't bother to collect info for type relations */
-               if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
+               if (tbinfo->relkind == RELKIND_COMPOSITE_TYPE)
                        continue;
 
                /* Don't bother with uninteresting tables, either */
-               if (!tblinfo[i].interesting)
+               if (!tbinfo->interesting)
                        continue;
 
                /*
                 * Make sure we are in proper schema for this table; this allows
                 * correct retrieval of formatted type names and default exprs
                 */
-               selectSourceSchema(tblinfo[i].relnamespace->nspname);
+               selectSourceSchema(tbinfo->relnamespace->nspname);
 
                /* find all the user attributes and their types */
 
@@ -2359,7 +2403,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                 */
                if (g_verbose)
                        write_msg(NULL, "finding the columns and types for table %s\n",
-                                         tblinfo[i].relname);
+                                         tbinfo->relname);
 
                resetPQExpBuffer(q);
 
@@ -2372,7 +2416,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                                                          "where attrelid = '%s'::pg_catalog.oid "
                                                          "and attnum > 0::pg_catalog.int2 "
                                                          "order by attrelid, attnum",
-                                                         tblinfo[i].oid);
+                                                         tbinfo->oid);
                }
                else if (g_fout->remoteVersion >= 70100)
                {
@@ -2388,7 +2432,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                                                          "where attrelid = '%s'::oid "
                                                          "and attnum > 0::int2 "
                                                          "order by attrelid, attnum",
-                                                         tblinfo[i].oid);
+                                                         tbinfo->oid);
                }
                else
                {
@@ -2400,7 +2444,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                                                          "where attrelid = '%s'::oid "
                                                          "and attnum > 0::int2 "
                                                          "order by attrelid, attnum",
-                                                         tblinfo[i].oid);
+                                                         tbinfo->oid);
                }
 
                res = PQexec(g_conn, q->data);
@@ -2421,34 +2465,36 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                i_atthasdef = PQfnumber(res, "atthasdef");
                i_attisdropped = PQfnumber(res, "attisdropped");
 
-               tblinfo[i].numatts = ntups;
-               tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
-               tblinfo[i].atttypnames = (char **) malloc(ntups * sizeof(char *));
-               tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
-               tblinfo[i].attstattarget = (int *) malloc(ntups * sizeof(int));
-               tblinfo[i].attisdropped = (bool *) malloc(ntups * sizeof(bool));
-               tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
-               tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
-               tblinfo[i].inhAttrs = (bool *) malloc(ntups * sizeof(bool));
-               tblinfo[i].inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
-               tblinfo[i].inhNotNull = (bool *) malloc(ntups * sizeof(bool));
+               tbinfo->numatts = ntups;
+               tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
+               tbinfo->atttypnames = (char **) malloc(ntups * sizeof(char *));
+               tbinfo->atttypmod = (int *) malloc(ntups * sizeof(int));
+               tbinfo->attstattarget = (int *) malloc(ntups * sizeof(int));
+               tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
+               tbinfo->attisserial = (bool *) malloc(ntups * sizeof(bool));
+               tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
+               tbinfo->adef_expr = (char **) malloc(ntups * sizeof(char *));
+               tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
+               tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
+               tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool));
                hasdefaults = false;
 
                for (j = 0; j < ntups; j++)
                {
-                       tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
-                       tblinfo[i].atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
-                       tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
-                       tblinfo[i].attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
-                       tblinfo[i].attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
-                       tblinfo[i].notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
-                       tblinfo[i].adef_expr[j] = NULL; /* fix below */
+                       tbinfo->attnames[j] = strdup(PQgetvalue(res, j, i_attname));
+                       tbinfo->atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
+                       tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
+                       tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
+                       tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
+                       tbinfo->attisserial[j] = false; /* fix below */
+                       tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
+                       tbinfo->adef_expr[j] = NULL;    /* fix below */
                        if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
                                hasdefaults = true;
                        /* these flags will be set in flagInhAttrs() */
-                       tblinfo[i].inhAttrs[j] = false;
-                       tblinfo[i].inhAttrDef[j] = false;
-                       tblinfo[i].inhNotNull[j] = false;
+                       tbinfo->inhAttrs[j] = false;
+                       tbinfo->inhAttrDef[j] = false;
+                       tbinfo->inhNotNull[j] = false;
                }
 
                PQclear(res);
@@ -2459,7 +2505,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 
                        if (g_verbose)
                                write_msg(NULL, "finding DEFAULT expressions for table %s\n",
-                                                 tblinfo[i].relname);
+                                                 tbinfo->relname);
 
                        resetPQExpBuffer(q);
                        if (g_fout->remoteVersion >= 70300)
@@ -2468,7 +2514,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                                                                  "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
                                                                  "FROM pg_catalog.pg_attrdef "
                                                                  "WHERE adrelid = '%s'::pg_catalog.oid",
-                                                                 tblinfo[i].oid);
+                                                                 tbinfo->oid);
                        }
                        else if (g_fout->remoteVersion >= 70200)
                        {
@@ -2476,14 +2522,14 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                                                                  "pg_get_expr(adbin, adrelid) AS adsrc "
                                                                  "FROM pg_attrdef "
                                                                  "WHERE adrelid = '%s'::oid",
-                                                                 tblinfo[i].oid);
+                                                                 tbinfo->oid);
                        }
                        else
                        {
                                /* no pg_get_expr, so must rely on adsrc */
                                appendPQExpBuffer(q, "SELECT adnum, adsrc FROM pg_attrdef "
                                                                  "WHERE adrelid = '%s'::oid",
-                                                                 tblinfo[i].oid);
+                                                                 tbinfo->oid);
                        }
                        res = PQexec(g_conn, q->data);
                        if (!res ||
@@ -2502,13 +2548,51 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                                if (adnum <= 0 || adnum > ntups)
                                {
                                        write_msg(NULL, "bogus adnum value %d for table %s\n",
-                                                         adnum, tblinfo[i].relname);
+                                                         adnum, tbinfo->relname);
                                        exit_nicely();
                                }
-                               tblinfo[i].adef_expr[adnum-1] = strdup(PQgetvalue(res, j, 1));
+                               tbinfo->adef_expr[adnum-1] = strdup(PQgetvalue(res, j, 1));
                        }
                        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->adef_expr[j] == NULL)
+                               continue;
+                       for (k = 0; k < numTables; k++)
+                       {
+                               TableInfo *seqinfo = &tblinfo[k];
+
+                               if (seqinfo->owning_tab != NULL &&
+                                       strcmp(seqinfo->owning_tab, tbinfo->oid) == 0 &&
+                                       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->dump = tbinfo->dump;
+                                       break;
+                               }
+                       }
+               }
        }
 
        destroyPQExpBuffer(q);
@@ -4884,11 +4968,26 @@ dumpACL(Archive *fout, const char *type, const char *name,
 static void
 dumpTableACL(Archive *fout, TableInfo *tbinfo)
 {
-       char *tmp = strdup(fmtId(tbinfo->relname));
-       dumpACL(fout, "TABLE", tmp, tbinfo->relname,
+       char *namecopy = strdup(fmtId(tbinfo->relname));
+       char *dumpoid;
+
+       /*
+        * Choose OID to use for sorting ACL into position.  For a view, sort
+        * by the view OID; for a serial sequence, sort by the owning table's
+        * OID; otherwise use the table's own OID.
+        */
+       if (tbinfo->viewoid != NULL)
+               dumpoid = tbinfo->viewoid;
+       else if (tbinfo->owning_tab != NULL)
+               dumpoid = tbinfo->owning_tab;
+       else
+               dumpoid = tbinfo->oid;
+
+       dumpACL(fout, "TABLE", namecopy, tbinfo->relname,
                        tbinfo->relnamespace->nspname, tbinfo->usename, tbinfo->relacl,
-                       tbinfo->viewoid != NULL ? tbinfo->viewoid : tbinfo->oid);
-       free(tmp);
+                       dumpoid);
+
+       free(namecopy);
 }
 
 
@@ -4902,7 +5001,10 @@ dumpTables(Archive *fout, TableInfo tblinfo[], int numTables,
 {
        int                     i;
 
-       /* Dump sequences first, in case they are referenced in table defn's */
+       /*
+        * Dump non-serial sequences first, in case they are referenced in
+        * table defn's
+        */
        for (i = 0; i < numTables; i++)
        {
                TableInfo          *tbinfo = &tblinfo[i];
@@ -4910,7 +5012,7 @@ dumpTables(Archive *fout, TableInfo tblinfo[], int numTables,
                if (tbinfo->relkind != RELKIND_SEQUENCE)
                        continue;
 
-               if (tbinfo->dump)
+               if (tbinfo->dump && tbinfo->owning_tab == NULL)
                {
                        dumpOneSequence(fout, tbinfo, schemaOnly, dataOnly);
                        if (!dataOnly && !aclsSkip)
@@ -4937,6 +5039,25 @@ dumpTables(Archive *fout, TableInfo tblinfo[], int numTables,
                        }
                }
        }
+
+       /*
+        * Dump serial sequences last (we will not emit any CREATE commands,
+        * but we do have to think about ACLs and setval operations).
+        */
+       for (i = 0; i < numTables; i++)
+       {
+               TableInfo          *tbinfo = &tblinfo[i];
+
+               if (tbinfo->relkind != RELKIND_SEQUENCE)
+                       continue;
+
+               if (tbinfo->dump && tbinfo->owning_tab != NULL)
+               {
+                       dumpOneSequence(fout, tbinfo, schemaOnly, dataOnly);
+                       if (!dataOnly && !aclsSkip)
+                               dumpTableACL(fout, tbinfo);
+               }
+       }
 }
 
 /*
@@ -5089,24 +5210,48 @@ dumpOneTable(Archive *fout, TableInfo *tbinfo, TableInfo *g_tblinfo)
                                        appendPQExpBuffer(q, ",");
                                appendPQExpBuffer(q, "\n    ");
 
-                               /* Attr name & type */
+                               /* Attribute name */
                                appendPQExpBuffer(q, "%s ",
                                                                  fmtId(tbinfo->attnames[j]));
 
-                               /* If no format_type, fake it */
+                               /* Attribute type */
                                if (g_fout->remoteVersion >= 70100)
-                                       appendPQExpBuffer(q, "%s", tbinfo->atttypnames[j]);
+                               {
+                                       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);
+                               }
                                else
+                               {
+                                       /* If no format_type, fake it */
                                        appendPQExpBuffer(q, "%s",
                                                                          myFormatType(tbinfo->atttypnames[j],
                                                                                                   tbinfo->atttypmod[j]));
+                               }
 
-                               /* Default value */
-                               if (tbinfo->adef_expr[j] != NULL && !tbinfo->inhAttrDef[j])
+                               /* Default value --- suppress if inherited or serial */
+                               if (tbinfo->adef_expr[j] != NULL &&
+                                       !tbinfo->inhAttrDef[j] &&
+                                       !tbinfo->attisserial[j])
                                        appendPQExpBuffer(q, " DEFAULT %s",
                                                                          tbinfo->adef_expr[j]);
 
-                               /* Not Null constraint */
+                               /*
+                                * 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");
 
@@ -5708,15 +5853,17 @@ dumpOneSequence(Archive *fout, TableInfo *tbinfo,
        called = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
 
        /*
-        * 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).
+        * 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 'SETVAL(seq, last_val, iscalled)' at restore-time iff we load
-        * data
+        * data.  We do this for serial sequences too.
         */
 
-       if (!dataOnly)
+       if (!dataOnly && tbinfo->owning_tab == NULL)
        {
                resetPQExpBuffer(delqry);
 
index b8fcfdc4ff53c0543b1186f4656c29369e549849..060c4396b4293d3444b25cf0863e3bbcfaa513a8 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_dump.h,v 1.96 2002/08/18 09:36:26 petere Exp $
+ * $Id: pg_dump.h,v 1.97 2002/08/19 19:33:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -110,6 +110,9 @@ 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: */
+       char       *owning_tab;         /* OID of table owning sequence */
+       int                     owning_col;             /* attr # of column owning sequence */
 
        bool            interesting;    /* true if need to collect more data */
        bool            dump;                   /* true if we want to dump it */
@@ -123,12 +126,13 @@ typedef struct _tableInfo
        char      **atttypnames;        /* attribute type names */
        int                *atttypmod;          /* type-specific type modifiers */
        int                *attstattarget;      /* attribute statistics targets */
+       bool       *attisdropped;       /* true if attr is dropped; don't dump it */
+       bool       *attisserial;        /* true if attr is serial or bigserial */
        /*
         * Note: we need to store per-attribute notnull and default stuff for
         * all interesting tables so that we can tell which constraints were
         * inherited.
         */
-       bool       *attisdropped;       /* true if attr is dropped; don't dump it */
        bool       *notnull;            /* Not null constraints on attributes */
        char      **adef_expr;          /* DEFAULT expressions */
        bool       *inhAttrs;           /* true if each attribute is inherited */
index 58a5b6eb22a20cef58c6b30ffb80d2448867f729..300e1744a2497db816f7562abac32476ffa33bc6 100644 (file)
@@ -6,7 +6,6 @@ CREATE TABLE x (
        e text
 );
 NOTICE:  CREATE TABLE will create implicit sequence 'x_a_seq' for SERIAL column 'x.a'
-NOTICE:  CREATE TABLE / UNIQUE will create implicit index 'x_a_key' for table 'x'
 CREATE FUNCTION fn_x_before () RETURNS OPAQUE AS '
   BEGIN
                NEW.e := ''before trigger fired''::text;
index 9e1faa0a37feefdaa4c8f6efd53fc568949b9ac9..a2620f0b67520915a8670a855729c8678fa7fdb2 100644 (file)
@@ -137,7 +137,6 @@ INSERT INTO iportaltest (i, d, p)
 ---
 CREATE TABLE serialTest (f1 text, f2 serial);
 NOTICE:  CREATE TABLE will create implicit sequence 'serialtest_f2_seq' for SERIAL column 'serialtest.f2'
-NOTICE:  CREATE TABLE / UNIQUE will create implicit index 'serialtest_f2_key' for table 'serialtest'
 INSERT INTO serialTest VALUES ('foo');
 INSERT INTO serialTest VALUES ('bar');
 INSERT INTO serialTest VALUES ('force', 100);
index 36837f11063238cfc50b982db61db450dd4ef044..2dd74613d997efe39572c42b92c4a1e62b8bce49 100644 (file)
@@ -59,11 +59,10 @@ SELECT relname, relhasindex
  pg_trigger          | t
  pg_type             | t
  road                | t
- serialtest          | t
  shighway            | t
  tenk1               | t
  tenk2               | t
-(53 rows)
+(52 rows)
 
 --
 -- another sanity check: every system catalog that has OIDs should have