Re: Removing pg_migrator limitations - Mailing list pgsql-hackers

From Bruce Momjian
Subject Re: Removing pg_migrator limitations
Date
Msg-id 200912261850.nBQIoX228323@momjian.us
Whole thread Raw
In response to Re: Removing pg_migrator limitations  (Bruce Momjian <bruce@momjian.us>)
Responses Re: Removing pg_migrator limitations  (Bruce Momjian <bruce@momjian.us>)
List pgsql-hackers
Bruce Momjian wrote:
> Bruce Momjian wrote:
> > Tom Lane wrote:
> > > Bruce Momjian <bruce@momjian.us> writes:
> > > > Tom Lane wrote:
> > > >> The reason I don't want to do it that way is that then you need two
> > > >> ugly kluges in the backend, not just one.  With the zero-and-add-one
> > > >> approach there is no need to have a "next enum oid" variable at all.
> > >
> > > > Uh, I still need that variable because that is how we are going to set
> > > > the oid in EnumValuesCreate(), unless we want to add dummy oid-value
> > > > arguments to that function for use only by the binary upgrade
> > > > server-side function.
> > >
> > > Please go back and re-read what I suggested: you need a function along
> > > the lines of
> > >     add_enum_member(enum-type, 'value name', value-oid)
> > > and then there's no need for any saved state.  So what if it has a
> > > different signature from the other pg_migrator special functions?
> > > It's not doing the same thing.
> >
> > OK, right, I can get rid of the enum function that just sets the next
> > oid value if I do all the enum value creation via function calls.  I
> > will work in that direction then.
>
> There is only one call to EnumValuesCreate() so maybe adding a
> binary-upgrade-only parameter to the function will be the cleanest
> approach.

Here is a patch to allow EnumValuesCreate() to create labels with
specified oids, with pg_dump support.  This is done cleanly now that we
allow zero-label enums.

--
  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +
Index: src/backend/catalog/pg_enum.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/catalog/pg_enum.c,v
retrieving revision 1.11
diff -c -c -r1.11 pg_enum.c
*** src/backend/catalog/pg_enum.c    24 Dec 2009 22:17:58 -0000    1.11
--- src/backend/catalog/pg_enum.c    26 Dec 2009 18:48:55 -0000
***************
*** 33,39 ****
   * vals is a list of Value strings.
   */
  void
! EnumValuesCreate(Oid enumTypeOid, List *vals)
  {
      Relation    pg_enum;
      TupleDesc    tupDesc;
--- 33,40 ----
   * vals is a list of Value strings.
   */
  void
! EnumValuesCreate(Oid enumTypeOid, List *vals,
!                  Oid binary_upgrade_next_pg_enum_oid)
  {
      Relation    pg_enum;
      TupleDesc    tupDesc;
***************
*** 58,82 ****
      tupDesc = pg_enum->rd_att;

      /*
!      * Allocate oids.  While this method does not absolutely guarantee that we
!      * generate no duplicate oids (since we haven't entered each oid into the
!      * table before allocating the next), trouble could only occur if the oid
!      * counter wraps all the way around before we finish. Which seems
!      * unlikely.
       */
      oids = (Oid *) palloc(num_elems * sizeof(Oid));
!     for (elemno = 0; elemno < num_elems; elemno++)
      {
          /*
!          *    The pg_enum.oid is stored in user tables.  This oid must be
!          *    preserved by binary upgrades.
           */
!         oids[elemno] = GetNewOid(pg_enum);
      }

-     /* sort them, just in case counter wrapped from high to low */
-     qsort(oids, num_elems, sizeof(Oid), oid_cmp);
-
      /* and make the entries */
      memset(nulls, false, sizeof(nulls));

--- 59,97 ----
      tupDesc = pg_enum->rd_att;

      /*
!      *    Allocate oids
       */
      oids = (Oid *) palloc(num_elems * sizeof(Oid));
!     if (OidIsValid(binary_upgrade_next_pg_enum_oid))
!     {
!             if (num_elems != 1)
!                 ereport(ERROR,
!                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
!                          errmsg("EnumValuesCreate() can only set a single OID")));
!             oids[0] = binary_upgrade_next_pg_enum_oid;
!             binary_upgrade_next_pg_enum_oid = InvalidOid;
!     }
!     else
      {
          /*
!          * While this method does not absolutely guarantee that we generate
!          * no duplicate oids (since we haven't entered each oid into the
!          * table before allocating the next), trouble could only occur if
!          * the oid counter wraps all the way around before we finish. Which
!          * seems unlikely.
           */
!         for (elemno = 0; elemno < num_elems; elemno++)
!         {
!             /*
!              *    The pg_enum.oid is stored in user tables.  This oid must be
!              *    preserved by binary upgrades.
!              */
!             oids[elemno] = GetNewOid(pg_enum);
!         }
!         /* sort them, just in case counter wrapped from high to low */
!         qsort(oids, num_elems, sizeof(Oid), oid_cmp);
      }

      /* and make the entries */
      memset(nulls, false, sizeof(nulls));

Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/typecmds.c,v
retrieving revision 1.141
diff -c -c -r1.141 typecmds.c
*** src/backend/commands/typecmds.c    24 Dec 2009 22:09:23 -0000    1.141
--- src/backend/commands/typecmds.c    26 Dec 2009 18:48:56 -0000
***************
*** 1161,1167 ****
                     false);        /* Type NOT NULL */

      /* Enter the enum's values into pg_enum */
!     EnumValuesCreate(enumTypeOid, stmt->vals);

      /*
       * Create the array type that goes with it.
--- 1161,1167 ----
                     false);        /* Type NOT NULL */

      /* Enter the enum's values into pg_enum */
!     EnumValuesCreate(enumTypeOid, stmt->vals, InvalidOid);

      /*
       * Create the array type that goes with it.
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.562
diff -c -c -r1.562 pg_dump.c
*** src/bin/pg_dump/pg_dump.c    26 Dec 2009 16:55:21 -0000    1.562
--- src/bin/pg_dump/pg_dump.c    26 Dec 2009 18:48:57 -0000
***************
*** 6528,6539 ****
      PGresult   *res;
      int            num,
                  i;
      char       *label;

      /* Set proper schema search path so regproc references list correctly */
      selectSourceSchema(tyinfo->dobj.namespace->dobj.name);

!     appendPQExpBuffer(query, "SELECT enumlabel FROM pg_catalog.pg_enum "
                        "WHERE enumtypid = '%u'"
                        "ORDER BY oid",
                        tyinfo->dobj.catId.oid);
--- 6528,6541 ----
      PGresult   *res;
      int            num,
                  i;
+     Oid            enum_oid;
      char       *label;

      /* Set proper schema search path so regproc references list correctly */
      selectSourceSchema(tyinfo->dobj.namespace->dobj.name);

!     appendPQExpBuffer(query, "SELECT oid, enumlabel "
!                       "FROM pg_catalog.pg_enum "
                        "WHERE enumtypid = '%u'"
                        "ORDER BY oid",
                        tyinfo->dobj.catId.oid);
***************
*** 6556,6573 ****
      if (binary_upgrade)
          binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);

!     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (\n",
                        fmtId(tyinfo->dobj.name));
!     for (i = 0; i < num; i++)
      {
!         label = PQgetvalue(res, i, 0);
!         if (i > 0)
!             appendPQExpBuffer(q, ",\n");
!         appendPQExpBuffer(q, "    ");
!         appendStringLiteralAH(q, label, fout);
      }
      appendPQExpBuffer(q, "\n);\n");

      ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
                   tyinfo->dobj.name,
                   tyinfo->dobj.namespace->dobj.name,
--- 6558,6601 ----
      if (binary_upgrade)
          binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);

!     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
                        fmtId(tyinfo->dobj.name));
!
!     if (!binary_upgrade)
      {
!         /* Labels with server-assigned oids */
!         for (i = 0; i < num; i++)
!         {
!             label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
!             if (i > 0)
!                 appendPQExpBuffer(q, ",");
!             appendPQExpBuffer(q, "\n    ");
!             appendStringLiteralAH(q, label, fout);
!         }
      }
+
      appendPQExpBuffer(q, "\n);\n");

+     if (binary_upgrade)
+     {
+         /* Labels with dump-assigned (preserved) oids */
+         for (i = 0; i < num; i++)
+         {
+             enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
+             label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
+
+             if (i == 0)
+                 appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
+             appendPQExpBuffer(q,
+                 "SELECT binary_upgrade.add_pg_enum_label('%u'::pg_catalog.oid, "
+                 "'%u'::pg_catalog.oid, ",
+                 enum_oid, tyinfo->dobj.catId.oid);
+             appendStringLiteralAH(q, label, fout);
+             appendPQExpBuffer(q, ");\n");
+         }
+         appendPQExpBuffer(q, "\n");
+     }
+
      ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
                   tyinfo->dobj.name,
                   tyinfo->dobj.namespace->dobj.name,
Index: src/include/catalog/pg_enum.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/catalog/pg_enum.h,v
retrieving revision 1.5
diff -c -c -r1.5 pg_enum.h
*** src/include/catalog/pg_enum.h    1 Jan 2009 17:23:57 -0000    1.5
--- src/include/catalog/pg_enum.h    26 Dec 2009 18:49:00 -0000
***************
*** 60,66 ****
  /*
   * prototypes for functions in pg_enum.c
   */
! extern void EnumValuesCreate(Oid enumTypeOid, List *vals);
  extern void EnumValuesDelete(Oid enumTypeOid);

  #endif   /* PG_ENUM_H */
--- 60,67 ----
  /*
   * prototypes for functions in pg_enum.c
   */
! extern void EnumValuesCreate(Oid enumTypeOid, List *vals,
!             Oid binary_upgrade_next_pg_enum_oid);
  extern void EnumValuesDelete(Oid enumTypeOid);

  #endif   /* PG_ENUM_H */

pgsql-hackers by date:

Previous
From: Andres Freund
Date:
Subject: Re: join ordering via Simulated Annealing
Next
From: Andres Freund
Date:
Subject: Re: Hot Standby and cancelling idle queries