Thread: Removing pg_migrator limitations

Removing pg_migrator limitations

From
Bruce Momjian
Date:
There are several pg_migrator limitations that appeared late in the 8.4
development cycle and were impossible to fix at that point.  I would
like to fix them for Postgres 8.5:
       o  a user-defined composite data type       o  a user-defined array data type       o  a user-defined enum data
type

I have discussed this with Alvaro.  I think pg_migrator needs the
ability to set the pg_type.oid and pg_enum.oid for user-defined
composites, arrays, and enums to match the values in the old server, and
hence match references to those rows in user data tables.

The general solution will involve creating place-hold rows in pg_type
and pg_enum with the desired oids, and deleting those placeholder rows
at the time pg_dump creates the new type or enum, and passing the
desired oid to the creation command.  We do something similar for toast
tables now, but it is easier there because the oids are actually file
system files.

There is no ability to specify an OID column value on insert.  However,
pg_migrator has the ability to call backend C functions via shared
library functions so it could potentially insert the needed system
catalog dummy rows.  As far as creating rows with the proper oids, we
could modify the SQL grammar to allow it, or modify DefineType() so it
accepts oids and passes them to TypeCreate(), or a simpler approach
would be to set the oid counter before calling CREATE TYPE, but that
would be error-prone because other oids might be assigned in
indeterminate order ---  we removed that code from pg_migrator for toast
tables before 8.4 shipped, so I am not excited to re-add it.  The same
approach is necessary for enums.

Another approach could be to create the dummy rows, load all of the
pg_dump schema, then renumber the rows to the proper oids, but this
assumes that I will be able to find all references to the current oids
and renumber those too.

Seems I need some help here.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Alvaro Herrera
Date:
Bruce Momjian wrote:
> There are several pg_migrator limitations that appeared late in the 8.4
> development cycle and were impossible to fix at that point.  I would
> like to fix them for Postgres 8.5:
> 
>         o  a user-defined composite data type
>         o  a user-defined array data type
>         o  a user-defined enum data type
> 
> I have discussed this with Alvaro.  I think pg_migrator needs the
> ability to set the pg_type.oid and pg_enum.oid for user-defined
> composites, arrays, and enums to match the values in the old server, and
> hence match references to those rows in user data tables.

To be more precise, the pg_enum.oid needs to be set for ENUM types;
there's no need for setting the pg_type.oid (for ENUM types).  I don't
know about composites but I think the problem with user defined arrays
is the OID of the element type, not the array itself.

> The general solution will involve creating place-hold rows in pg_type
> and pg_enum with the desired oids, and deleting those placeholder rows
> at the time pg_dump creates the new type or enum, and passing the
> desired oid to the creation command.

I don't think there's a need for pg_enum placeholders.  Just create them
with the correct OIDs as the first step.  Nobody else is going to use
pg_enum.oids anyway.  Again, I don't know about arrays or composites.

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Alvaro Herrera wrote:
> Bruce Momjian wrote:
> > There are several pg_migrator limitations that appeared late in the 8.4
> > development cycle and were impossible to fix at that point.  I would
> > like to fix them for Postgres 8.5:
> > 
> >         o  a user-defined composite data type
> >         o  a user-defined array data type
> >         o  a user-defined enum data type
> > 
> > I have discussed this with Alvaro.  I think pg_migrator needs the
> > ability to set the pg_type.oid and pg_enum.oid for user-defined
> > composites, arrays, and enums to match the values in the old server, and
> > hence match references to those rows in user data tables.
> 
> To be more precise, the pg_enum.oid needs to be set for ENUM types;
> there's no need for setting the pg_type.oid (for ENUM types).  I don't
> know about composites but I think the problem with user defined arrays
> is the OID of the element type, not the array itself.

Yes, good point.  I can see where the oids are assigned in our C code:
       oids[i] = GetNewOid(pg_enum);
array_oid = GetNewOid(pg_type);

I need a way of controlling that.  Now, ideally, I would just be able to
add an optional oid field to DefineType() and call it from a server-side
C function called by pg_migrator, but the problem is that that function
assumes it is receiving a complex struct DefineStmt which can't easily
be created by pg_migrator.

> > The general solution will involve creating place-hold rows in pg_type
> > and pg_enum with the desired oids, and deleting those placeholder rows
> > at the time pg_dump creates the new type or enum, and passing the
> > desired oid to the creation command.
> 
> I don't think there's a need for pg_enum placeholders.  Just create them
> with the correct OIDs as the first step.  Nobody else is going to use
> pg_enum.oids anyway.  Again, I don't know about arrays or composites.

That will make things easier because of the large number of oids
consumed by enumerated types.

I am now thinking that setting the oid counter before calling CREATE
TYPE/ENUM might be the cleanest, and of course with pg_dump setting this
all up when in --binary-upgrade mode.  It does make pg_migrator
dependent on the order of oid allocation in those routines.  It also
might make some migrations impossible if concurrent enum creation caused
gaps in the assignment of oids in a single enumerated type.

A crazier idea would be for pg_migrator to set server-side global
variables that contain the oids to be used.  pg_dump would call those
functions to set and clear the global variables when in --binary-upgrade
mode, and the backend code would consult those variables before calling
GetNewOid(), or GetNewOid() would consult those global variables.

You can now see why this was not fixed in 8.4.  :-(

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Alvaro Herrera
Date:
Bruce Momjian wrote:
> Alvaro Herrera wrote:
> > Bruce Momjian wrote:
> > > There are several pg_migrator limitations that appeared late in the 8.4
> > > development cycle and were impossible to fix at that point.  I would
> > > like to fix them for Postgres 8.5:
> > > 
> > >         o  a user-defined composite data type
> > >         o  a user-defined array data type
> > >         o  a user-defined enum data type
> > > 
> > > I have discussed this with Alvaro.  I think pg_migrator needs the
> > > ability to set the pg_type.oid and pg_enum.oid for user-defined
> > > composites, arrays, and enums to match the values in the old server, and
> > > hence match references to those rows in user data tables.
> > 
> > To be more precise, the pg_enum.oid needs to be set for ENUM types;
> > there's no need for setting the pg_type.oid (for ENUM types).  I don't
> > know about composites but I think the problem with user defined arrays
> > is the OID of the element type, not the array itself.
> 
> Yes, good point.  I can see where the oids are assigned in our C code:
> 
>         oids[i] = GetNewOid(pg_enum);
> 
>     array_oid = GetNewOid(pg_type);
> 
> I need a way of controlling that.

You're (partly?) missing my point which is that the important OID to
control is the one that actually gets stored on table files.

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Alvaro Herrera wrote:
> Bruce Momjian wrote:
> > Alvaro Herrera wrote:
> > > Bruce Momjian wrote:
> > > > There are several pg_migrator limitations that appeared late in the 8.4
> > > > development cycle and were impossible to fix at that point.  I would
> > > > like to fix them for Postgres 8.5:
> > > > 
> > > >         o  a user-defined composite data type
> > > >         o  a user-defined array data type
> > > >         o  a user-defined enum data type
> > > > 
> > > > I have discussed this with Alvaro.  I think pg_migrator needs the
> > > > ability to set the pg_type.oid and pg_enum.oid for user-defined
> > > > composites, arrays, and enums to match the values in the old server, and
> > > > hence match references to those rows in user data tables.
> > > 
> > > To be more precise, the pg_enum.oid needs to be set for ENUM types;
> > > there's no need for setting the pg_type.oid (for ENUM types).  I don't
> > > know about composites but I think the problem with user defined arrays
> > > is the OID of the element type, not the array itself.
> > 
> > Yes, good point.  I can see where the oids are assigned in our C code:
> > 
> >         oids[i] = GetNewOid(pg_enum);
> > 
> >     array_oid = GetNewOid(pg_type);
> > 
> > I need a way of controlling that.
> 
> You're (partly?) missing my point which is that the important OID to
> control is the one that actually gets stored on table files.

Well, I thought the idea was to set the system table oid to match the
oids already in the user tables.  I realize that is not all system oids.
What am I missing exactly?

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Alvaro Herrera
Date:
Bruce Momjian wrote:
> Alvaro Herrera wrote:
> > Bruce Momjian wrote:
> > > Alvaro Herrera wrote:

> > > > To be more precise, the pg_enum.oid needs to be set for ENUM types;
> > > > there's no need for setting the pg_type.oid (for ENUM types).  I don't
> > > > know about composites but I think the problem with user defined arrays
> > > > is the OID of the element type, not the array itself.
> > > 
> > > Yes, good point.  I can see where the oids are assigned in our C code:
> > > 
> > >         oids[i] = GetNewOid(pg_enum);
> > > 
> > >     array_oid = GetNewOid(pg_type);
> > > 
> > > I need a way of controlling that.
> > 
> > You're (partly?) missing my point which is that the important OID to
> > control is the one that actually gets stored on table files.
> 
> Well, I thought the idea was to set the system table oid to match the
> oids already in the user tables.  I realize that is not all system oids.
> What am I missing exactly?

I think the OIDs for user-defined arrays stored in table data are
element types, not the array type which is what you're pointing at with
the line you quote:

> > >     array_oid = GetNewOid(pg_type);

IMBFOS.

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Alvaro Herrera wrote:
> Bruce Momjian wrote:
> > Alvaro Herrera wrote:
> > > Bruce Momjian wrote:
> > > > Alvaro Herrera wrote:
> 
> > > > > To be more precise, the pg_enum.oid needs to be set for ENUM types;
> > > > > there's no need for setting the pg_type.oid (for ENUM types).  I don't
> > > > > know about composites but I think the problem with user defined arrays
> > > > > is the OID of the element type, not the array itself.
> > > > 
> > > > Yes, good point.  I can see where the oids are assigned in our C code:
> > > > 
> > > >         oids[i] = GetNewOid(pg_enum);
> > > > 
> > > >     array_oid = GetNewOid(pg_type);
> > > > 
> > > > I need a way of controlling that.
> > > 
> > > You're (partly?) missing my point which is that the important OID to
> > > control is the one that actually gets stored on table files.
> > 
> > Well, I thought the idea was to set the system table oid to match the
> > oids already in the user tables.  I realize that is not all system oids.
> > What am I missing exactly?
> 
> I think the OIDs for user-defined arrays stored in table data are
> element types, not the array type which is what you're pointing at with
> the line you quote:
> 
> > > >     array_oid = GetNewOid(pg_type);
> 
> IMBFOS.

Oh, yea, sorry, I was just showing examples of where we get the oids ---
I have not researched the exact calls yet, but I am doing that now and
will apply a patch that adds C comments to the C structures to identify
them.  I figure it would be good to document this no matter what we do.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Andrew Dunstan
Date:

Bruce Momjian wrote:
> There are several pg_migrator limitations that appeared late in the 8.4
> development cycle and were impossible to fix at that point.  I would
> like to fix them for Postgres 8.5:
>
>         o  a user-defined composite data type
>         o  a user-defined array data type
>         o  a user-defined enum data type
>
> I have discussed this with Alvaro.  I think pg_migrator needs the
> ability to set the pg_type.oid and pg_enum.oid for user-defined
> composites, arrays, and enums to match the values in the old server, and
> hence match references to those rows in user data tables.
>
> The general solution will involve creating place-hold rows in pg_type
> and pg_enum with the desired oids, and deleting those placeholder rows
> at the time pg_dump creates the new type or enum, and passing the
> desired oid to the creation command.  We do something similar for toast
> tables now, but it is easier there because the oids are actually file
> system files.
>
> There is no ability to specify an OID column value on insert.  However,
> pg_migrator has the ability to call backend C functions via shared
> library functions so it could potentially insert the needed system
> catalog dummy rows.  As far as creating rows with the proper oids, we
> could modify the SQL grammar to allow it, or modify DefineType() so it
> accepts oids and passes them to TypeCreate(), or a simpler approach
> would be to set the oid counter before calling CREATE TYPE, but that
> would be error-prone because other oids might be assigned in
> indeterminate order ---  we removed that code from pg_migrator for toast
> tables before 8.4 shipped, so I am not excited to re-add it.  The same
> approach is necessary for enums.
>
> Another approach could be to create the dummy rows, load all of the
> pg_dump schema, then renumber the rows to the proper oids, but this
> assumes that I will be able to find all references to the current oids
> and renumber those too.
>
> Seems I need some help here.
>
>   

I thought there was a suggestion that we would be able to specify the 
oids in the SQL that creates the types, along the lines of:
   create type foo as enum ( ...) with oids ( ... );

Is that a non-starter? I imagine it would need to require some special 
setting to be enabled to allow it.

cheers

andrew


Re: Removing pg_migrator limitations

From
Robert Haas
Date:
On Fri, Dec 18, 2009 at 6:44 PM, Andrew Dunstan <andrew@dunslane.net> wrote:
> I thought there was a suggestion that we would be able to specify the oids
> in the SQL that creates the types, along the lines of:
>
>   create type foo as enum ( ...) with oids ( ... );
>
> Is that a non-starter? I imagine it would need to require some special
> setting to be enabled to allow it.

This gets at a question that I've been wondering about.  There seems
to be something about OIDs that makes us want to not ever allow users
to specify them, or only when our back is absolutely against the wall.I have only the vaguest notions of what might be
dangerousabout 
that, though.

...Robert


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
> Bruce Momjian wrote:
>> Seems I need some help here.

I'm willing to work on this --- it doesn't look particularly fun but
we really need it.

Andrew Dunstan <andrew@dunslane.net> writes:
> I thought there was a suggestion that we would be able to specify the 
> oids in the SQL that creates the types, along the lines of:
>     create type foo as enum ( ...) with oids ( ... );
> Is that a non-starter? I imagine it would need to require some special 
> setting to be enabled to allow it.

The more I think about it the less I want such warts placed in the
regular SQL syntax for creation commands.  As soon as we add a wart like
that we'll be stuck with supporting it forever.  Whatever we do here
should be off in a little corner that only pg_migrator can get at.

And we already have a way to manage that: there's already something
in pg_migrator to let it install special functions that are present
only while migrating.  So I suggest that we make whatever hacks are
needed available only at the C-code level, and let pg_migrator get
at them via its special functions.

In practice, this would mean teaching pg_dump to call these functions
when it is making a --binary_upgrade dump.  The reason I think this
is less of a support hazard than changing SQL statements is that there
is no promise or intention that a --binary_upgrade dump will load into
anything but the specific PG version that it's intended for.  (We
could, and probably should, add some version labeling to the dump to
help enforce that.)

At the moment it appears that we need the following hacks:

* ability to control the OIDs assigned to user tables and types.
Because a table also has a rowtype, this means at least two separate
state variables.  And we already knew we had to control the OIDs
assigned to toast tables.  I'm imagining dump output like
select pg_migrator_set_next_table_oid(123456);select pg_migrator_set_next_type_oid(12347);select
pg_migrator_set_next_toast_table_oid(123458);
CREATE TABLE ...

where the functions cause static variables to become set, and the
core code gets changed to look like
if (next_table_oid){    newoid = next_table_oid;    next_table_oid = 0;}else    newoid = GetNewOid(...);

in selected places where currently there's just a GetNewOid(...) call.

* ability to control the OIDs assigned to enum values.  To keep this
sane I think the easiest way is to have pg_migrator have a function
that adds one value with a predetermined OID to an existing enum.
So instead of CREATE TYPE foo AS ENUM ('bar', 'baz', ...)
I envision the --binary_upgrade dump output looking like
-- force the OID of the enum type itselfselect pg_migrator_set_next_type_oid(12347);
CREATE TYPE foo AS ENUM ();
select pg_migrator_add_enum_value(12347, 'bar', 12348);select pg_migrator_add_enum_value(12347, 'baz', 12349);...


I don't see any value in the placeholder-row approach Bruce suggests;
AFAICS it would require significantly uglier backend hacks than the
above because dealing with an already-present row would be a bigger
code change.

Comments?
        regards, tom lane


Re: Removing pg_migrator limitations

From
Alvaro Herrera
Date:
Tom Lane wrote:

> * ability to control the OIDs assigned to user tables and types.
> Because a table also has a rowtype, this means at least two separate
> state variables.  And we already knew we had to control the OIDs
> assigned to toast tables.  I'm imagining dump output like
> 
>     select pg_migrator_set_next_table_oid(123456);
>     select pg_migrator_set_next_type_oid(12347);
>     select pg_migrator_set_next_toast_table_oid(123458);
> 
>     CREATE TABLE ...

Do we also need a knob for the table type's array type?

> * ability to control the OIDs assigned to enum values.  To keep this
> sane I think the easiest way is to have pg_migrator have a function
> that adds one value with a predetermined OID to an existing enum.
> So instead of CREATE TYPE foo AS ENUM ('bar', 'baz', ...)
> I envision the --binary_upgrade dump output looking like
> 
>     -- force the OID of the enum type itself
>     select pg_migrator_set_next_type_oid(12347);

This part isn't necessary AFAIK, except to be used as reference here:

>     CREATE TYPE foo AS ENUM ();
> 
>     select pg_migrator_add_enum_value(12347, 'bar', 12348);
>     select pg_migrator_add_enum_value(12347, 'baz', 12349);

on which we could perhaps use "foo" as a reference instead of the OID
value.  However, I think array and composite types need a specific type
OID, so the set_next_type_oid function would still be necessary.

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support


Re: Removing pg_migrator limitations

From
Andrew Dunstan
Date:

Tom Lane wrote:
> At the moment it appears that we need the following hacks:
>
> * ability to control the OIDs assigned to user tables and types.
> Because a table also has a rowtype, this means at least two separate
> state variables.  And we already knew we had to control the OIDs
> assigned to toast tables.  I'm imagining dump output like
>
>     select pg_migrator_set_next_table_oid(123456);
>     select pg_migrator_set_next_type_oid(12347);
>     select pg_migrator_set_next_toast_table_oid(123458);
>
>     CREATE TABLE ...
>
> where the functions cause static variables to become set, and the
> core code gets changed to look like
>
>     if (next_table_oid)
>     {
>         newoid = next_table_oid;
>         next_table_oid = 0;
>     }
>     else
>         newoid = GetNewOid(...);
>
> in selected places where currently there's just a GetNewOid(...) call.
>
> * ability to control the OIDs assigned to enum values.  To keep this
> sane I think the easiest way is to have pg_migrator have a function
> that adds one value with a predetermined OID to an existing enum.
> So instead of CREATE TYPE foo AS ENUM ('bar', 'baz', ...)
> I envision the --binary_upgrade dump output looking like
>
>     -- force the OID of the enum type itself
>     select pg_migrator_set_next_type_oid(12347);
>
>     CREATE TYPE foo AS ENUM ();
>
>     select pg_migrator_add_enum_value(12347, 'bar', 12348);
>     select pg_migrator_add_enum_value(12347, 'baz', 12349);
>     ...
>
>
> I don't see any value in the placeholder-row approach Bruce suggests;
> AFAICS it would require significantly uglier backend hacks than the
> above because dealing with an already-present row would be a bigger
> code change.
>
> Comments?
>
>             
>   

That looks fairly workable. The placeholder idea seems like a bit of a 
potential footgun, so I like the idea that we can in some limited 
circumstances set the oids fairly directly.

cheers

andrew


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
Alvaro Herrera <alvherre@commandprompt.com> writes:
> Tom Lane wrote:
>> select pg_migrator_set_next_table_oid(123456);
>> select pg_migrator_set_next_type_oid(12347);
>> select pg_migrator_set_next_toast_table_oid(123458);
>> 
>> CREATE TABLE ...

> Do we also need a knob for the table type's array type?

Well, we wouldn't care about the oid of the array type, except that if
the backend is allowed to assign it on its own, it might eat an oid that
we're going to need later for another type.  So yeah, array oids too.
(The above is just a sketch, I don't promise it's complete ;-))

>> -- force the OID of the enum type itself
>> select pg_migrator_set_next_type_oid(12347);

> This part isn't necessary AFAIK, except to be used as reference here:

>> CREATE TYPE foo AS ENUM ();

Exactly.  We have to assign the oid of the enum type just as much as any
other type.  Basically, to avoid collisions we'll need to ensure we nail
down the oids of every pg_class and pg_type row to be the same as they
were before.  We might have to nail down relfilenodes similarly, not
sure yet.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Bruce Momjian wrote:
> > I think the OIDs for user-defined arrays stored in table data are
> > element types, not the array type which is what you're pointing at with
> > the line you quote:
> >
> > > > >     array_oid = GetNewOid(pg_type);
> >
> > IMBFOS.
>
> Oh, yea, sorry, I was just showing examples of where we get the oids ---
> I have not researched the exact calls yet, but I am doing that now and
> will apply a patch that adds C comments to the C structures to identify
> them.  I figure it would be good to document this no matter what we do.

I have applied the attached patch which documents the locations where
system oids have to be preserved for binary upgrades.

--
  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.9
diff -c -c -r1.9 pg_enum.c
*** src/backend/catalog/pg_enum.c    1 Jan 2009 17:23:37 -0000    1.9
--- src/backend/catalog/pg_enum.c    19 Dec 2009 00:46:10 -0000
***************
*** 67,72 ****
--- 67,76 ----
      oids = (Oid *) palloc(n * sizeof(Oid));
      for (i = 0; i < n; i++)
      {
+         /*
+          *    The pg_enum.oid is stored in user tables.  This oid must be
+          *    preserved by binary upgrades.
+          */
          oids[i] = GetNewOid(pg_enum);
      }

Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/typecmds.c,v
retrieving revision 1.139
diff -c -c -r1.139 typecmds.c
*** src/backend/commands/typecmds.c    7 Dec 2009 05:22:21 -0000    1.139
--- src/backend/commands/typecmds.c    19 Dec 2009 00:46:10 -0000
***************
*** 531,536 ****
--- 531,542 ----
       * now have TypeCreate do all the real work.
       */
      typoid =
+         /*
+          *    The pg_type.oid is stored in user tables as array elements
+          *    (base types) in ArrayType and in composite types in
+          *    DatumTupleFields.  This oid must be preserved by binary
+          *    upgrades.
+          */
          TypeCreate(InvalidOid,    /* no predetermined type OID */
                     typeName,    /* type name */
                     typeNamespace,        /* namespace */
Index: src/backend/utils/adt/arrayfuncs.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v
retrieving revision 1.161
diff -c -c -r1.161 arrayfuncs.c
*** src/backend/utils/adt/arrayfuncs.c    4 Sep 2009 11:20:22 -0000    1.161
--- src/backend/utils/adt/arrayfuncs.c    19 Dec 2009 00:46:13 -0000
***************
*** 328,333 ****
--- 328,338 ----
      SET_VARSIZE(retval, nbytes);
      retval->ndim = ndim;
      retval->dataoffset = dataoffset;
+     /*
+      *    This comes from the array's pg_type.typelem (which points to the
+      *    base data type's pg_type.oid) and stores system oids in user tables.
+      *    This oid must be preserved by binary upgrades.
+      */
      retval->elemtype = element_type;
      memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int));
      memcpy(ARR_LBOUND(retval), lBound, ndim * sizeof(int));
Index: src/backend/utils/adt/enum.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/enum.c,v
retrieving revision 1.7
diff -c -c -r1.7 enum.c
*** src/backend/utils/adt/enum.c    1 Jan 2009 17:23:49 -0000    1.7
--- src/backend/utils/adt/enum.c    19 Dec 2009 00:46:13 -0000
***************
*** 56,61 ****
--- 56,65 ----
                          format_type_be(enumtypoid),
                          name)));

+     /*
+      *    This comes from pg_enum.oid and stores system oids in user tables.
+      *    This oid must be preserved by binary upgrades.
+      */
      enumoid = HeapTupleGetOid(tup);

      ReleaseSysCache(tup);
Index: src/backend/utils/adt/rowtypes.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/rowtypes.c,v
retrieving revision 1.25
diff -c -c -r1.25 rowtypes.c
*** src/backend/utils/adt/rowtypes.c    11 Jun 2009 14:49:04 -0000    1.25
--- src/backend/utils/adt/rowtypes.c    19 Dec 2009 00:46:14 -0000
***************
*** 97,102 ****
--- 97,107 ----
                  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
             errmsg("input of anonymous composite types is not implemented")));
      tupTypmod = -1;                /* for all non-anonymous types */
+     /*
+      *    This comes from the composite type's pg_type.oid and
+      *    stores system oids in user tables, specifically DatumTupleFields.
+      *    This oid must be preserved by binary upgrades.
+      */
      tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
      ncolumns = tupdesc->natts;


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Tom Lane wrote:
> The more I think about it the less I want such warts placed in the
> regular SQL syntax for creation commands.  As soon as we add a wart like
> that we'll be stuck with supporting it forever.  Whatever we do here
> should be off in a little corner that only pg_migrator can get at.

Yea, and we might need more some day so a system that can be easily
enhanced would help.  Adding to SQL syntax and maintaining it seems like
overkill.

> And we already have a way to manage that: there's already something
> in pg_migrator to let it install special functions that are present
> only while migrating.  So I suggest that we make whatever hacks are
> needed available only at the C-code level, and let pg_migrator get
> at them via its special functions.

Right.

> In practice, this would mean teaching pg_dump to call these functions
> when it is making a --binary_upgrade dump.  The reason I think this
> is less of a support hazard than changing SQL statements is that there
> is no promise or intention that a --binary_upgrade dump will load into
> anything but the specific PG version that it's intended for.  (We
> could, and probably should, add some version labeling to the dump to
> help enforce that.)

Yea, that is easy.

> At the moment it appears that we need the following hacks:
> 
> * ability to control the OIDs assigned to user tables and types.
> Because a table also has a rowtype, this means at least two separate
> state variables.  And we already knew we had to control the OIDs
> assigned to toast tables.  I'm imagining dump output like
> 
>     select pg_migrator_set_next_table_oid(123456);
>     select pg_migrator_set_next_type_oid(12347);
>     select pg_migrator_set_next_toast_table_oid(123458);

I was thinking of something even more general:
select pg_migrator_set_oid('pg_type', 100);select pg_migrator_set_oid('pg_type_array', 101);

and you just check for the strings in pg_migrator_set_oid and set the
proper variable.  The idea I had was to create a global structure:
struct pg_migrator_oids {    Oid    pg_type;    Oid    pg_type_array;    ...}

This would initialize to zero as a global structure, and only
pg_migrator server-side functions set it.

>     CREATE TABLE ...
> 
> where the functions cause static variables to become set, and the
> core code gets changed to look like
> 
>     if (next_table_oid)
>     {
>         newoid = next_table_oid;
>         next_table_oid = 0;
>     }
>     else
>         newoid = GetNewOid(...);

Yes, that is what I was thinking too:
    if (pg_migrator_oid.pg_type)    {        newoid = pg_migrator_oid.pg_type;        pg_migrator_oid.pg_type = 0;
}else       newoid = GetNewOid(...);
 

> in selected places where currently there's just a GetNewOid(...) call.
> 
> * ability to control the OIDs assigned to enum values.  To keep this
> sane I think the easiest way is to have pg_migrator have a function
> that adds one value with a predetermined OID to an existing enum.
> So instead of CREATE TYPE foo AS ENUM ('bar', 'baz', ...)
> I envision the --binary_upgrade dump output looking like
> 
>     -- force the OID of the enum type itself
>     select pg_migrator_set_next_type_oid(12347);
> 
>     CREATE TYPE foo AS ENUM ();
> 
>     select pg_migrator_add_enum_value(12347, 'bar', 12348);
>     select pg_migrator_add_enum_value(12347, 'baz', 12349);
>     ...


Good idea --- I was trying to figure out how to assign an array of oids
and couldn't think of a simple way.

> I don't see any value in the placeholder-row approach Bruce suggests;
> AFAICS it would require significantly uglier backend hacks than the
> above because dealing with an already-present row would be a bigger
> code change.

True.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Tom Lane wrote:
> Alvaro Herrera <alvherre@commandprompt.com> writes:
> > Tom Lane wrote:
> >> select pg_migrator_set_next_table_oid(123456);
> >> select pg_migrator_set_next_type_oid(12347);
> >> select pg_migrator_set_next_toast_table_oid(123458);
> >> 
> >> CREATE TABLE ...
> 
> > Do we also need a knob for the table type's array type?
> 
> Well, we wouldn't care about the oid of the array type, except that if
> the backend is allowed to assign it on its own, it might eat an oid that
> we're going to need later for another type.  So yeah, array oids too.
> (The above is just a sketch, I don't promise it's complete ;-))
> 
> >> -- force the OID of the enum type itself
> >> select pg_migrator_set_next_type_oid(12347);
> 
> > This part isn't necessary AFAIK, except to be used as reference here:
> 
> >> CREATE TYPE foo AS ENUM ();
> 
> Exactly.  We have to assign the oid of the enum type just as much as any
> other type.  Basically, to avoid collisions we'll need to ensure we nail
> down the oids of every pg_class and pg_type row to be the same as they

I assume you meant pg_type and pg_class above, or I hope you were.

> were before.  We might have to nail down relfilenodes similarly, not
> sure yet.

Yea, piggybacking on Alvaro's idea for pg_enum, if we set all the
pg_type oids we can clearly do this with no placeholders necessary.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Joe Conway
Date:
On 12/18/2009 04:09 PM, Tom Lane wrote:
> At the moment it appears that we need the following hacks:
>
> * ability to control the OIDs assigned to user tables and types.
> Because a table also has a rowtype, this means at least two separate
> state variables.  And we already knew we had to control the OIDs
> assigned to toast tables.  I'm imagining dump output like
>
>     select pg_migrator_set_next_table_oid(123456);
>     select pg_migrator_set_next_type_oid(12347);
>     select pg_migrator_set_next_toast_table_oid(123458);
>
>     CREATE TABLE ...

I like this approach overall, but wonder if it would be better to do:
select pg_migrator_set_next_oid('table', 123456);select pg_migrator_set_next_oid('type', 12347);select
pg_migrator_set_next_oid('toast_table',123458); 

etc. Later we could easily add other supported objects...


Joe


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
Bruce Momjian <bruce@momjian.us> writes:
> ... The idea I had was to create a global structure:

>     struct pg_migrator_oids {
>         Oid    pg_type;
>         Oid    pg_type_array;
>         ...
>     }

> This would initialize to zero as a global structure, and only
> pg_migrator server-side functions set it.

I would prefer *not* to do that, as that makes the list of settable oids
far more public than I would like; also you are totally dependent on
pg_migrator and the backend to be in sync about the definition of that
struct, which is going to be problematic in alpha releases in
particular, since PG_VERSION isn't going to distinguish them.

What I had in mind was more like
static Oid next_pg_class_oid = InvalidOid;
voidset_next_pg_class_oid(Oid oid){    next_pg_class_oid = oid;}

in each module that needs to be able to accept a next-oid setting,
and then the pg_migrator loadable module would expose SQL-callable
wrappers for these functions.  That way, any inconsistency shows up as
a link error: function needed not present.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
Joe Conway <mail@joeconway.com> writes:
> I like this approach overall, but wonder if it would be better to do:
>     select pg_migrator_set_next_oid('table', 123456);
>     select pg_migrator_set_next_oid('type', 12347);
>     select pg_migrator_set_next_oid('toast_table', 123458);
> etc. Later we could easily add other supported objects...

Yeah, Bruce was just suggesting the same.  I do like that part of what
he mentioned, just because it'll be fewer special functions to add and
drop in pg_migrator.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Tom Lane wrote:
> Bruce Momjian <bruce@momjian.us> writes:
> > ... The idea I had was to create a global structure:
> 
> >     struct pg_migrator_oids {
> >         Oid    pg_type;
> >         Oid    pg_type_array;
> >         ...
> >     }
> 
> > This would initialize to zero as a global structure, and only
> > pg_migrator server-side functions set it.
> 
> I would prefer *not* to do that, as that makes the list of settable oids
> far more public than I would like; also you are totally dependent on
> pg_migrator and the backend to be in sync about the definition of that
> struct, which is going to be problematic in alpha releases in
> particular, since PG_VERSION isn't going to distinguish them.
> 
> What I had in mind was more like
> 
>     static Oid next_pg_class_oid = InvalidOid;
> 
>     void
>     set_next_pg_class_oid(Oid oid)
>     {
>         next_pg_class_oid = oid;
>     }

Good point about requiring a link to a symbol;  a structure offset would
not link to anything and would silently fail.

Does exporting a function buy us anything vs. exporting a variable?

> in each module that needs to be able to accept a next-oid setting,
> and then the pg_migrator loadable module would expose SQL-callable
> wrappers for these functions.  That way, any inconsistency shows up as
> a link error: function needed not present.

I will work on a patch to accomplish this, and have pg_migrator link in
the .so only if the new server is >= 8.5, which allows a single
pg_migrator binary to work for migration to 8.4 and 8.5.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Tom Lane wrote:
> > Bruce Momjian wrote:
> >> Seems I need some help here.
> 
> I'm willing to work on this --- it doesn't look particularly fun but
> we really need it.

You don't know fun until you have tried to stack hack upon hack and
still create a reliable migration system.  :-(

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Robert Haas
Date:
On Sat, Dec 19, 2009 at 10:46 PM, Bruce Momjian <bruce@momjian.us> wrote:
> Tom Lane wrote:
>> > Bruce Momjian wrote:
>> >> Seems I need some help here.
>>
>> I'm willing to work on this --- it doesn't look particularly fun but
>> we really need it.
>
> You don't know fun until you have tried to stack hack upon hack and
> still create a reliable migration system.  :-(

They say that people who love sausage and respect the law should never
watch either one being made, and I have to say I'm coming to feel that
way about in-place upgrade, too.

...Robert


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Robert Haas wrote:
> On Sat, Dec 19, 2009 at 10:46 PM, Bruce Momjian <bruce@momjian.us> wrote:
> > Tom Lane wrote:
> >> > Bruce Momjian wrote:
> >> >> Seems I need some help here.
> >>
> >> I'm willing to work on this --- it doesn't look particularly fun but
> >> we really need it.
> >
> > You don't know fun until you have tried to stack hack upon hack and
> > still create a reliable migration system. ?:-(
> 
> They say that people who love sausage and respect the law should never
> watch either one being made, and I have to say I'm coming to feel that
> way about in-place upgrade, too.

Agreed ...  There is nothing to see here --- move along.  ;-)  LOL

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
Bruce Momjian <bruce@momjian.us> writes:
> Tom Lane wrote:
>> What I had in mind was more like
>> 
>> static Oid next_pg_class_oid = InvalidOid;
>> 
>> void
>> set_next_pg_class_oid(Oid oid)
>> {
>>    next_pg_class_oid = oid;
>> }

> Does exporting a function buy us anything vs. exporting a variable?

Hmm, probably not.  I generally like to avoid global variables, but
in this case it doesn't seem to buy us anything to do so.  Actually,
you could just have the core code do
/* don't make this static, pg_migrator needs to set it */Oid    next_pg_class_oid = InvalidOid;

and not even bother with an extern declaration in the backend header
files (AFAIK gcc won't complain about that).  That would help keep the
variable private to just the one core module plus pg_migrator.


> I will work on a patch to accomplish this, and have pg_migrator link in
> the .so only if the new server is >= 8.5, which allows a single
> pg_migrator binary to work for migration to 8.4 and 8.5.

I think you're just creating useless work for yourself by imagining that
pg_migrator is backend-version-independent.  In fact, I was thinking
about proposing that we pull it in as a contrib module.  Because so much
of what it does is tied to details of backend and pg_dump behavior, it's
just a pipe dream to think that developing it as a separate project is
helpful.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Tom Lane wrote:
> Bruce Momjian <bruce@momjian.us> writes:
> > Tom Lane wrote:
> >> What I had in mind was more like
> >> 
> >> static Oid next_pg_class_oid = InvalidOid;
> >> 
> >> void
> >> set_next_pg_class_oid(Oid oid)
> >> {
> >>    next_pg_class_oid = oid;
> >> }
> 
> > Does exporting a function buy us anything vs. exporting a variable?
> 
> Hmm, probably not.  I generally like to avoid global variables, but
> in this case it doesn't seem to buy us anything to do so.  Actually,
> you could just have the core code do
> 
>     /* don't make this static, pg_migrator needs to set it */
>     Oid    next_pg_class_oid = InvalidOid;
> 
> and not even bother with an extern declaration in the backend header
> files (AFAIK gcc won't complain about that).  That would help keep the
> variable private to just the one core module plus pg_migrator.

Yes, that was the idea.  We wouldn't expose the variable in other C
files unless necessary.

> > I will work on a patch to accomplish this, and have pg_migrator link in
> > the .so only if the new server is >= 8.5, which allows a single
> > pg_migrator binary to work for migration to 8.4 and 8.5.
> 
> I think you're just creating useless work for yourself by imagining that
> pg_migrator is backend-version-independent.  In fact, I was thinking
> about proposing that we pull it in as a contrib module.  Because so much
> of what it does is tied to details of backend and pg_dump behavior, it's
> just a pipe dream to think that developing it as a separate project is
> helpful.

Well, I do think it will work for 8.3 to 8.4 ,and 8.4 to 8.5 --- I test
that regularly and I have not seen any failures in that regard.  If we
move it into /contrib, I will make sure fixes get backpatched.  FYI, a
typical test is:
   if (GET_MAJOR_VERSION(ctx.old.pg_version) <= 803 &&       GET_MAJOR_VERSION(ctx.new.pg_version) >= 804)

The biggest issue with versions is that it is hard for pg_migrator to
text changes in the server during major development so for example once
we add pg_dump support for system oids, it will then require CVS HEAD
for 8.5, but there are not that many people testing pg_migrator with
non-HEAD versions.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
Bruce Momjian <bruce@momjian.us> writes:
> Tom Lane wrote:
>> I think you're just creating useless work for yourself by imagining that
>> pg_migrator is backend-version-independent.  In fact, I was thinking
>> about proposing that we pull it in as a contrib module.  Because so much
>> of what it does is tied to details of backend and pg_dump behavior, it's
>> just a pipe dream to think that developing it as a separate project is
>> helpful.

> Well, I do think it will work for 8.3 to 8.4 ,and 8.4 to 8.5 --- I test
> that regularly and I have not seen any failures in that regard.  If we
> move it into /contrib, I will make sure fixes get backpatched.  FYI, a
> typical test is:

>     if (GET_MAJOR_VERSION(ctx.old.pg_version) <= 803 &&
>         GET_MAJOR_VERSION(ctx.new.pg_version) >= 804)

Well, yeah, you can probably make it work if you're willing to carry
enoguh version tests and alternate sets of logic in the source code.
I don't think that is a particularly good engineering approach however.
It makes things less readable and probably more buggy.  Particularly
so since we are talking about some quite significant logic changes here.

There's a reason to clutter, eg, pg_dump with multiple version support.
I don't see the argument for doing so with pg_migrator.  Separate source
code branches seem like a much better idea.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Robert Haas
Date:
On Sun, Dec 20, 2009 at 1:49 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>>     if (GET_MAJOR_VERSION(ctx.old.pg_version) <= 803 &&
>>         GET_MAJOR_VERSION(ctx.new.pg_version) >= 804)
>
> Well, yeah, you can probably make it work if you're willing to carry
> enoguh version tests and alternate sets of logic in the source code.
> I don't think that is a particularly good engineering approach however.
> It makes things less readable and probably more buggy.  Particularly
> so since we are talking about some quite significant logic changes here.
>
> There's a reason to clutter, eg, pg_dump with multiple version support.
> I don't see the argument for doing so with pg_migrator.  Separate source
> code branches seem like a much better idea.

I guess we have to look at the specific cases that come up, but ISTM
that a branch here amounts to a second copy of the code that has to be
separately maintained.  I'm having a hard time working up much
enthusiasm for that prospect.

...Robert


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
Robert Haas <robertmhaas@gmail.com> writes:
> On Sun, Dec 20, 2009 at 1:49 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> There's a reason to clutter, eg, pg_dump with multiple version support.
>> I don't see the argument for doing so with pg_migrator. �Separate source
>> code branches seem like a much better idea.

> I guess we have to look at the specific cases that come up, but ISTM
> that a branch here amounts to a second copy of the code that has to be
> separately maintained.  I'm having a hard time working up much
> enthusiasm for that prospect.

Well, it'd be exactly like back-patching fixes across multiple branches
is for fixes in the core code now.  In code that hasn't changed across
branches, that's not terribly painful.  If the code has changed, then
you're going to have pain no matter which way you do it.

But the real problem with having pg_migrator be a separate project is
that a lot of the time "fix pg_migrator" is really going to mean "fix
pg_dump" or even "change the backend".  We already had problems with
version skew between pg_migrator and various 8.4 alpha/beta releases.
That type of problem isn't likely to magically go away in the future.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Robert Haas
Date:
On Sun, Dec 20, 2009 at 2:08 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Robert Haas <robertmhaas@gmail.com> writes:
>> On Sun, Dec 20, 2009 at 1:49 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>>> There's a reason to clutter, eg, pg_dump with multiple version support.
>>> I don't see the argument for doing so with pg_migrator.  Separate source
>>> code branches seem like a much better idea.
>
>> I guess we have to look at the specific cases that come up, but ISTM
>> that a branch here amounts to a second copy of the code that has to be
>> separately maintained.  I'm having a hard time working up much
>> enthusiasm for that prospect.
>
> Well, it'd be exactly like back-patching fixes across multiple branches
> is for fixes in the core code now.  In code that hasn't changed across
> branches, that's not terribly painful.  If the code has changed, then
> you're going to have pain no matter which way you do it.
>
> But the real problem with having pg_migrator be a separate project is
> that a lot of the time "fix pg_migrator" is really going to mean "fix
> pg_dump" or even "change the backend".  We already had problems with
> version skew between pg_migrator and various 8.4 alpha/beta releases.
> That type of problem isn't likely to magically go away in the future.

I agree that pulling pg_migrator into contrib seems pretty sensible.
What I want to make sure we're on the same page about is which
versions the 8.5 pg_migrator will allow you to upgrade from and to.  I
think we should at least support 8.3 -> 8.5 and 8.4 -> 8.5.  If you're
saying we don't need to support 8.3 -> 8.4 any more once 8.5 comes
out, I'm probably OK with that, but perhaps we should try to get a few
more opinions before setting that policy in stone.

...Robert


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
Robert Haas <robertmhaas@gmail.com> writes:
> I agree that pulling pg_migrator into contrib seems pretty sensible.
> What I want to make sure we're on the same page about is which
> versions the 8.5 pg_migrator will allow you to upgrade from and to.  I
> think we should at least support 8.3 -> 8.5 and 8.4 -> 8.5.  If you're
> saying we don't need to support 8.3 -> 8.4 any more once 8.5 comes
> out, I'm probably OK with that, but perhaps we should try to get a few
> more opinions before setting that policy in stone.

If we can do that reasonably (which might well be the case), I'd be for
it.  What I'm objecting to is what I take to be Bruce's plan of
supporting 8.3 -> 8.4 and 8.4 -> 8.5 with the same pg_migrator sources.
The stuff we're talking about doing in this thread is going to cause
those two cases to diverge rather drastically.  8.3 -> 8.5 and 8.4 ->
8.5 may be close enough together to be reasonable to support in one
set of source code.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Tom Lane wrote:
> Robert Haas <robertmhaas@gmail.com> writes:
> > I agree that pulling pg_migrator into contrib seems pretty sensible.
> > What I want to make sure we're on the same page about is which
> > versions the 8.5 pg_migrator will allow you to upgrade from and to.  I
> > think we should at least support 8.3 -> 8.5 and 8.4 -> 8.5.  If you're
> > saying we don't need to support 8.3 -> 8.4 any more once 8.5 comes
> > out, I'm probably OK with that, but perhaps we should try to get a few
> > more opinions before setting that policy in stone.
> 
> If we can do that reasonably (which might well be the case), I'd be for
> it.  What I'm objecting to is what I take to be Bruce's plan of
> supporting 8.3 -> 8.4 and 8.4 -> 8.5 with the same pg_migrator sources.
> The stuff we're talking about doing in this thread is going to cause
> those two cases to diverge rather drastically.  8.3 -> 8.5 and 8.4 ->
> 8.5 may be close enough together to be reasonable to support in one
> set of source code.

Basically there isn't much extra work to go from 8.3 to 8.4 compared to
8.3 to 8.5.  Now, if could support only 8.4 to 8.5 I could remove some
code, but that seems counterproductive.

The other problem with moving to /contrib is that I can't put out
pg_migrator updates independently of the main community release, which
could be bad.

I am glad some people think pg_migrator is ready for /contrib.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
"Marc G. Fournier"
Date:
On Sun, 20 Dec 2009, Bruce Momjian wrote:

> The other problem with moving to /contrib is that I can't put out 
> pg_migrator updates independently of the main community release, which 
> could be bad.

Why not?

----
Marc G. Fournier                        Hub.Org Hosting Solutions S.A.
scrappy@hub.org                                     http://www.hub.org

Yahoo:yscrappy    Skype: hub.org    ICQ:7615664    MSN:scrappy@hub.org


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
Bruce Momjian <bruce@momjian.us> writes:
> Basically there isn't much extra work to go from 8.3 to 8.4 compared to
> 8.3 to 8.5.

That might be true today, but it will stop being true once we replace
the oid/relfilenode management hac^Wcode with the proposed new approach.

> The other problem with moving to /contrib is that I can't put out
> pg_migrator updates independently of the main community release, which
> could be bad.

That was a good thing while pg_migrator was in its "wild west"
development stage.  But if you have ambitions that people should trust it
enough to risk their production DBs on it, then it had better be stable
enough for this not to be a big drawback.

Also note the point about how it'll be a lot easier to keep it in sync
with pg_dump and backend behavior if it's only got to work with the
pg_dump version that's in the same release.  Again, the proposed changes
tie it to a particular pg_dump and target backend version noticeably
more than it was before; so if you try to keep it separate this is going
to be an even bigger headache than it already was during the run-up to
8.4.

Lastly, getting pg_migrator working reliably would be a sufficiently
Big Deal that I think a critical pg_migrator bug would be sufficient
grounds for forcing a minor release, just as we sometimes force a
release for critical backend bugs.

> I am glad some people think pg_migrator is ready for /contrib.

To be clear, I don't think it's really ready for contrib today.  I think
it could be up to that level by the time 8.5 releases, but we have to
get serious about it, and stop pretending it's an arm's-length project
the core project doesn't really care about.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Tom Lane wrote:
> Bruce Momjian <bruce@momjian.us> writes:
> > Basically there isn't much extra work to go from 8.3 to 8.4 compared to
> > 8.3 to 8.5.
> 
> That might be true today, but it will stop being true once we replace
> the oid/relfilenode management hac^Wcode with the proposed new approach.
> 
> > The other problem with moving to /contrib is that I can't put out
> > pg_migrator updates independently of the main community release, which
> > could be bad.
> 
> That was a good thing while pg_migrator was in its "wild west"
> development stage.  But if you have ambitions that people should trust it
> enough to risk their production DBs on it, then it had better be stable
> enough for this not to be a big drawback.
> 
> Also note the point about how it'll be a lot easier to keep it in sync
> with pg_dump and backend behavior if it's only got to work with the
> pg_dump version that's in the same release.  Again, the proposed changes
> tie it to a particular pg_dump and target backend version noticeably
> more than it was before; so if you try to keep it separate this is going
> to be an even bigger headache than it already was during the run-up to
> 8.4.
> 
> Lastly, getting pg_migrator working reliably would be a sufficiently
> Big Deal that I think a critical pg_migrator bug would be sufficient
> grounds for forcing a minor release, just as we sometimes force a
> release for critical backend bugs.
> 
> > I am glad some people think pg_migrator is ready for /contrib.
> 
> To be clear, I don't think it's really ready for contrib today.  I think
> it could be up to that level by the time 8.5 releases, but we have to
> get serious about it, and stop pretending it's an arm's-length project
> the core project doesn't really care about.

OK, I am convinced.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
decibel
Date:
On Dec 19, 2009, at 9:52 PM, Robert Haas wrote:
> On Sat, Dec 19, 2009 at 10:46 PM, Bruce Momjian <bruce@momjian.us> wrote:
>> Tom Lane wrote:
>>>> Bruce Momjian wrote:
>>>>> Seems I need some help here.
>>>
>>> I'm willing to work on this --- it doesn't look particularly fun but
>>> we really need it.
>>
>> You don't know fun until you have tried to stack hack upon hack and
>> still create a reliable migration system.  :-(
>
> They say that people who love sausage and respect the law should never
> watch either one being made, and I have to say I'm coming to feel that
> way about in-place upgrade, too.

Perhaps we should be ordering bacon instead of sausage...

Is there some reason why OIDs were used for ENUM instead of a general sequence? Were we worried about people screwing
withthe sequence? 

A sequences would presumably eliminate all these issues. Even if we wanted to disallow user access to the sequence,
havingsomething that's not competing with all the other uses of OID would presumably make this a lot simpler. 
--
Jim C. Nasby, Database Architect                   jim@nasby.net
512.569.9461 (cell)                         http://jim.nasby.net




Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Bruce Momjian wrote:
> Tom Lane wrote:
> > Bruce Momjian <bruce@momjian.us> writes:
> > > ... The idea I had was to create a global structure:
> >
> > >     struct pg_migrator_oids {
> > >         Oid    pg_type;
> > >         Oid    pg_type_array;
> > >         ...
> > >     }
> >
> > > This would initialize to zero as a global structure, and only
> > > pg_migrator server-side functions set it.
> >
> > I would prefer *not* to do that, as that makes the list of settable oids
> > far more public than I would like; also you are totally dependent on
> > pg_migrator and the backend to be in sync about the definition of that
> > struct, which is going to be problematic in alpha releases in
> > particular, since PG_VERSION isn't going to distinguish them.
> >
> > What I had in mind was more like
> >
> >     static Oid next_pg_class_oid = InvalidOid;
> >
> >     void
> >     set_next_pg_class_oid(Oid oid)
> >     {
> >         next_pg_class_oid = oid;
> >     }
>
> Good point about requiring a link to a symbol;  a structure offset would
> not link to anything and would silently fail.
>
> Does exporting a function buy us anything vs. exporting a variable?
>
> > in each module that needs to be able to accept a next-oid setting,
> > and then the pg_migrator loadable module would expose SQL-callable
> > wrappers for these functions.  That way, any inconsistency shows up as
> > a link error: function needed not present.
>
> I will work on a patch to accomplish this, and have pg_migrator link in
> the .so only if the new server is >= 8.5, which allows a single
> pg_migrator binary to work for migration to 8.4 and 8.5.

I have completed the attached patch which assigns oids for all pg_type
rows when pg_dump --binary-upgrade is used.  This allows user-defined
arrays and composite types to be migrated cleanly.  I tested a reload of
the regression database with --binary-upgrade and all the pg_type oids
were identical.  The pg_migrator changes required to use this feature
are trivial.

The remaining issue is pg_enum oids.  Because it will be difficult to
pass an arbitrary number of oids into the backend, the idea was to
assign each enum value separately.  If we implement this TODO item:

    Allow adding/renaming/removing enumerated values to an existing
    enumerated data type

Particularly the "adding" part rather than the "renaming/removing" part,
pg_dump can create an enum type with one (or zero perhaps) enums, and
then use a pg_enum oid-setting function and then use ALTER TYPE ADD
ENUM to add each new value.

Comments?

--
  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/heap.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/catalog/heap.c,v
retrieving revision 1.361
diff -c -c -r1.361 heap.c
*** src/backend/catalog/heap.c    7 Dec 2009 05:22:21 -0000    1.361
--- src/backend/catalog/heap.c    23 Dec 2009 18:48:11 -0000
***************
*** 1001,1013 ****
      if (IsUnderPostmaster && (relkind == RELKIND_RELATION ||
                                relkind == RELKIND_VIEW ||
                                relkind == RELKIND_COMPOSITE_TYPE))
!     {
!         /* OK, so pre-assign a type OID for the array type */
!         Relation    pg_type = heap_open(TypeRelationId, AccessShareLock);
!
!         new_array_oid = GetNewOid(pg_type);
!         heap_close(pg_type, AccessShareLock);
!     }

      /*
       * Since defining a relation also defines a complex type, we add a new
--- 1001,1007 ----
      if (IsUnderPostmaster && (relkind == RELKIND_RELATION ||
                                relkind == RELKIND_VIEW ||
                                relkind == RELKIND_COMPOSITE_TYPE))
!         new_array_oid = AssignTypeArrayOid();

      /*
       * Since defining a relation also defines a complex type, we add a new
Index: src/backend/catalog/pg_type.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v
retrieving revision 1.127
diff -c -c -r1.127 pg_type.c
*** src/backend/catalog/pg_type.c    16 Aug 2009 18:14:34 -0000    1.127
--- src/backend/catalog/pg_type.c    23 Dec 2009 18:48:11 -0000
***************
*** 32,37 ****
--- 32,38 ----
  #include "utils/rel.h"
  #include "utils/syscache.h"

+ Oid binary_upgrade_next_pg_type_oid = InvalidOid;

  /* ----------------------------------------------------------------
   *        TypeShellMake
***************
*** 119,124 ****
--- 120,131 ----
       */
      tup = heap_form_tuple(tupDesc, values, nulls);

+     if (OidIsValid(binary_upgrade_next_pg_type_oid))
+     {
+         HeapTupleSetOid(tup, binary_upgrade_next_pg_type_oid);
+         binary_upgrade_next_pg_type_oid = InvalidOid;
+     }
+
      /*
       * insert the tuple in the relation and get the tuple's oid.
       */
***************
*** 409,418 ****
                                values,
                                nulls);

!         /* Force the OID if requested by caller, else heap_insert does it */
          if (OidIsValid(newTypeOid))
              HeapTupleSetOid(tup, newTypeOid);
!
          typeObjectId = simple_heap_insert(pg_type_desc, tup);
      }

--- 416,431 ----
                                values,
                                nulls);

!         /* Force the OID if requested by caller */
          if (OidIsValid(newTypeOid))
              HeapTupleSetOid(tup, newTypeOid);
!         else if (OidIsValid(binary_upgrade_next_pg_type_oid))
!         {
!             HeapTupleSetOid(tup, binary_upgrade_next_pg_type_oid);
!             binary_upgrade_next_pg_type_oid = InvalidOid;
!         }
!         /* else allow system to assign oid */
!
          typeObjectId = simple_heap_insert(pg_type_desc, tup);
      }

Index: src/backend/catalog/toasting.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/catalog/toasting.c,v
retrieving revision 1.22
diff -c -c -r1.22 toasting.c
*** src/backend/catalog/toasting.c    23 Dec 2009 02:35:18 -0000    1.22
--- src/backend/catalog/toasting.c    23 Dec 2009 18:48:11 -0000
***************
*** 31,36 ****
--- 31,37 ----
  #include "utils/builtins.h"
  #include "utils/syscache.h"

+ Oid binary_upgrade_next_pg_type_toast_oid = InvalidOid;

  static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
                     Datum reloptions, bool force);
***************
*** 121,126 ****
--- 122,128 ----
      Relation    class_rel;
      Oid            toast_relid;
      Oid            toast_idxid;
+     Oid            toast_typid = InvalidOid;
      Oid            namespaceid;
      char        toast_relname[NAMEDATALEN];
      char        toast_idxname[NAMEDATALEN];
***************
*** 199,209 ****
      else
          namespaceid = PG_TOAST_NAMESPACE;

      toast_relid = heap_create_with_catalog(toast_relname,
                                             namespaceid,
                                             rel->rd_rel->reltablespace,
                                             toastOid,
!                                            InvalidOid,
                                             rel->rd_rel->relowner,
                                             tupdesc,
                                             NIL,
--- 201,217 ----
      else
          namespaceid = PG_TOAST_NAMESPACE;

+     if (OidIsValid(binary_upgrade_next_pg_type_toast_oid))
+     {
+         toast_typid = binary_upgrade_next_pg_type_toast_oid;
+         binary_upgrade_next_pg_type_toast_oid = InvalidOid;
+     }
+
      toast_relid = heap_create_with_catalog(toast_relname,
                                             namespaceid,
                                             rel->rd_rel->reltablespace,
                                             toastOid,
!                                            toast_typid,
                                             rel->rd_rel->relowner,
                                             tupdesc,
                                             NIL,
Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/typecmds.c,v
retrieving revision 1.140
diff -c -c -r1.140 typecmds.c
*** src/backend/commands/typecmds.c    19 Dec 2009 00:47:57 -0000    1.140
--- src/backend/commands/typecmds.c    23 Dec 2009 18:48:11 -0000
***************
*** 74,79 ****
--- 74,80 ----
      /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
  } RelToCheck;

+ Oid binary_upgrade_next_pg_type_array_oid = InvalidOid;

  static Oid    findTypeInputFunction(List *procname, Oid typeOid);
  static Oid    findTypeOutputFunction(List *procname, Oid typeOid);
***************
*** 143,149 ****
      Oid            array_oid;
      Oid            typoid;
      Oid            resulttype;
-     Relation    pg_type;
      ListCell   *pl;

      /*
--- 144,149 ----
***************
*** 522,531 ****
                         NameListToString(analyzeName));
  #endif

!     /* Preassign array type OID so we can insert it in pg_type.typarray */
!     pg_type = heap_open(TypeRelationId, AccessShareLock);
!     array_oid = GetNewOid(pg_type);
!     heap_close(pg_type, AccessShareLock);

      /*
       * now have TypeCreate do all the real work.
--- 522,528 ----
                         NameListToString(analyzeName));
  #endif

!     array_oid = AssignTypeArrayOid();

      /*
       * now have TypeCreate do all the real work.
***************
*** 1101,1107 ****
      AclResult    aclresult;
      Oid            old_type_oid;
      Oid            enumArrayOid;
-     Relation    pg_type;

      /* Convert list of names to a name and namespace */
      enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
--- 1098,1103 ----
***************
*** 1129,1138 ****
                       errmsg("type \"%s\" already exists", enumName)));
      }

!     /* Preassign array type OID so we can insert it in pg_type.typarray */
!     pg_type = heap_open(TypeRelationId, AccessShareLock);
!     enumArrayOid = GetNewOid(pg_type);
!     heap_close(pg_type, AccessShareLock);

      /* Create the pg_type entry */
      enumTypeOid =
--- 1125,1131 ----
                       errmsg("type \"%s\" already exists", enumName)));
      }

!     enumArrayOid = AssignTypeArrayOid();

      /* Create the pg_type entry */
      enumTypeOid =
***************
*** 1470,1475 ****
--- 1463,1495 ----
      return procOid;
  }

+ /*
+  *    AssignTypeArrayOid
+  *
+  *    Pre-assign the type's array OID for use in pg_type.typarray
+  */
+ Oid
+ AssignTypeArrayOid(void)
+ {
+     Oid        type_array_oid;
+
+     /* Pre-assign the type's array OID for use in pg_type.typarray */
+     if (OidIsValid(binary_upgrade_next_pg_type_array_oid))
+     {
+         type_array_oid = binary_upgrade_next_pg_type_array_oid;
+         binary_upgrade_next_pg_type_array_oid = InvalidOid;
+     }
+     else
+     {
+         Relation    pg_type = heap_open(TypeRelationId, AccessShareLock);
+
+         type_array_oid = GetNewOid(pg_type);
+         heap_close(pg_type, AccessShareLock);
+     }
+
+     return type_array_oid;
+ }
+

  /*-------------------------------------------------------------------
   * DefineCompositeType
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.560
diff -c -c -r1.560 pg_dump.c
*** src/bin/pg_dump/pg_dump.c    23 Dec 2009 04:10:50 -0000    1.560
--- src/bin/pg_dump/pg_dump.c    23 Dec 2009 18:48:12 -0000
***************
*** 196,201 ****
--- 196,206 ----
  static void dumpDatabase(Archive *AH);
  static void dumpEncoding(Archive *AH);
  static void dumpStdStrings(Archive *AH);
+ static void binary_upgrade_set_type_oids_by_type_oid(
+                     PQExpBuffer upgrade_buffer, Oid pg_type_oid);
+ static bool binary_upgrade_set_type_oids_by_rel_oid(
+                     PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
+ static void binary_upgrade_clear_pg_type_toast_oid(PQExpBuffer upgrade_buffer);
  static const char *getAttrName(int attrnum, TableInfo *tblInfo);
  static const char *fmtCopyColumnList(const TableInfo *ti);
  static void do_sql_command(PGconn *conn, const char *query);
***************
*** 2176,2181 ****
--- 2181,2311 ----
      return 1;
  }

+ static void
+ binary_upgrade_set_type_oids_by_type_oid(PQExpBuffer upgrade_buffer,
+                                                Oid pg_type_oid)
+ {
+     PQExpBuffer upgrade_query = createPQExpBuffer();
+     int            ntups;
+     PGresult   *upgrade_res;
+     Oid            pg_type_array_oid;
+
+     appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
+     appendPQExpBuffer(upgrade_buffer,
+         "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
+         pg_type_oid);
+
+     /* we only support old >= 8.3 for binary upgrades */
+     appendPQExpBuffer(upgrade_query,
+                       "SELECT typarray "
+                       "FROM pg_catalog.pg_type "
+                       "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
+                       pg_type_oid);
+
+     upgrade_res = PQexec(g_conn, upgrade_query->data);
+     check_sql_result(upgrade_res, g_conn, upgrade_query->data, PGRES_TUPLES_OK);
+
+     /* Expecting a single result only */
+     ntups = PQntuples(upgrade_res);
+     if (ntups != 1)
+     {
+         write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
+                                "query returned %d rows instead of one: %s\n",
+                                  ntups),
+                   ntups, upgrade_query->data);
+         exit_nicely();
+     }
+
+     pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
+
+     if (OidIsValid(pg_type_array_oid))
+     {
+         appendPQExpBuffer(upgrade_buffer,
+                             "\n-- For binary upgrade, must preserve pg_type array oid\n");
+         appendPQExpBuffer(upgrade_buffer,
+             "SELECT binary_upgrade.set_next_pg_type_array_oid('%u'::pg_catalog.oid);\n\n",
+             pg_type_array_oid);
+     }
+
+     PQclear(upgrade_res);
+     destroyPQExpBuffer(upgrade_query);
+ }
+
+ static bool
+ binary_upgrade_set_type_oids_by_rel_oid(PQExpBuffer upgrade_buffer,
+                                                Oid pg_rel_oid)
+ {
+     PQExpBuffer upgrade_query = createPQExpBuffer();
+     int            ntups;
+     PGresult   *upgrade_res;
+     Oid            pg_type_oid;
+     bool        toast_set = false;
+
+     /* we only support old >= 8.3 for binary upgrades */
+     appendPQExpBuffer(upgrade_query,
+                       "SELECT c.reltype AS crel, t.reltype AS trel "
+                       "FROM pg_catalog.pg_class c "
+                       "LEFT JOIN pg_catalog.pg_class t ON "
+                       "  (c.reltoastrelid = t.oid) "
+                       "WHERE c.oid = '%u'::pg_catalog.oid;",
+                       pg_rel_oid);
+
+     upgrade_res = PQexec(g_conn, upgrade_query->data);
+     check_sql_result(upgrade_res, g_conn, upgrade_query->data, PGRES_TUPLES_OK);
+
+     /* Expecting a single result only */
+     ntups = PQntuples(upgrade_res);
+     if (ntups != 1)
+     {
+         write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
+                                "query returned %d rows instead of one: %s\n",
+                                  ntups),
+                   ntups, upgrade_query->data);
+         exit_nicely();
+     }
+
+     pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
+
+     binary_upgrade_set_type_oids_by_type_oid(upgrade_buffer, pg_type_oid);
+
+     if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
+     {
+         /* Toast tables do not have pg_type array rows */
+         Oid pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
+                                         PQfnumber(upgrade_res, "trel")));
+
+         appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
+         appendPQExpBuffer(upgrade_buffer,
+             "SELECT binary_upgrade.set_next_pg_type_toast_oid('%u'::pg_catalog.oid);\n\n",
+             pg_type_toast_oid);
+
+         toast_set = true;
+     }
+
+     PQclear(upgrade_res);
+     destroyPQExpBuffer(upgrade_query);
+
+     return toast_set;
+ }
+
+ static void
+ binary_upgrade_clear_pg_type_toast_oid(PQExpBuffer upgrade_buffer)
+ {
+     /*
+      *    One complexity is that while the heap might now have a TOAST table,
+      *    the TOAST table might have been created long after creation when
+      *    the table was loaded with wide data.  For that reason, we clear
+      *    binary_upgrade_set_next_pg_type_toast_oid so it is not reused
+      *    by a later table.  Logically any later creation that needs a TOAST
+      *    table should have its own TOAST pg_type oid, but we are cautious.
+      */
+     appendPQExpBuffer(upgrade_buffer,
+         "\n-- For binary upgrade, clear toast oid because it might not have been needed\n");
+     appendPQExpBuffer(upgrade_buffer,
+         "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
+         InvalidOid);
+ }
+
  /*
   * getNamespaces:
   *      read all namespaces in the system catalogs and return them in the
***************
*** 6428,6433 ****
--- 6558,6567 ----
                        fmtId(tyinfo->dobj.namespace->dobj.name));
      appendPQExpBuffer(delq, "%s;\n",
                        fmtId(tyinfo->dobj.name));
+
+     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++)
***************
*** 6723,6728 ****
--- 6857,6866 ----
      appendPQExpBuffer(delq, "%s CASCADE;\n",
                        fmtId(tyinfo->dobj.name));

+     /* We might already have a shell type, but setting pg_type_oid is harmless */
+     if (binary_upgrade)
+         binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
+
      appendPQExpBuffer(q,
                        "CREATE TYPE %s (\n"
                        "    INTERNALLENGTH = %s",
***************
*** 6892,6897 ****
--- 7030,7038 ----
      else
          typdefault = NULL;

+     if (binary_upgrade)
+         binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
+
      appendPQExpBuffer(q,
                        "CREATE DOMAIN %s AS %s",
                        fmtId(tyinfo->dobj.name),
***************
*** 7002,7007 ****
--- 7143,7151 ----
      i_attname = PQfnumber(res, "attname");
      i_atttypdefn = PQfnumber(res, "atttypdefn");

+     if (binary_upgrade)
+         binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
+
      appendPQExpBuffer(q, "CREATE TYPE %s AS (",
                        fmtId(tyinfo->dobj.name));

***************
*** 7191,7196 ****
--- 7335,7344 ----
       * after it's filled in, otherwise the backend complains.
       */

+     if (binary_upgrade)
+         binary_upgrade_set_type_oids_by_type_oid(q,
+                                 stinfo->baseType->dobj.catId.oid);
+
      appendPQExpBuffer(q, "CREATE TYPE %s;\n",
                        fmtId(stinfo->dobj.name));

***************
*** 10226,10235 ****
      char       *storage;
      int            j,
                  k;
!
      /* Make sure we are in proper schema */
      selectSourceSchema(tbinfo->dobj.namespace->dobj.name);

      /* Is it a table or a view? */
      if (tbinfo->relkind == RELKIND_VIEW)
      {
--- 10374,10388 ----
      char       *storage;
      int            j,
                  k;
!     bool        toast_set = false;
!
      /* Make sure we are in proper schema */
      selectSourceSchema(tbinfo->dobj.namespace->dobj.name);

+     if (binary_upgrade)
+         toast_set = binary_upgrade_set_type_oids_by_rel_oid(q,
+                                                 tbinfo->dobj.catId.oid);
+
      /* Is it a table or a view? */
      if (tbinfo->relkind == RELKIND_VIEW)
      {
***************
*** 10606,10611 ****
--- 10759,10767 ----
          }
      }

+     if (binary_upgrade && toast_set)
+         binary_upgrade_clear_pg_type_toast_oid(q);
+
      ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
                   tbinfo->dobj.name,
                   tbinfo->dobj.namespace->dobj.name,
***************
*** 10617,10622 ****
--- 10773,10779 ----
                   tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
                   NULL, NULL);

+
      /* Dump Table Comments */
      dumpTableComment(fout, tbinfo, reltypename);

***************
*** 11235,11240 ****
--- 11392,11401 ----
                            fmtId(tbinfo->dobj.name));

          resetPQExpBuffer(query);
+
+         if (binary_upgrade)
+             binary_upgrade_set_type_oids_by_rel_oid(query, tbinfo->dobj.catId.oid);
+
          appendPQExpBuffer(query,
                            "CREATE SEQUENCE %s\n",
                            fmtId(tbinfo->dobj.name));
***************
*** 11270,11275 ****
--- 11431,11438 ----

          appendPQExpBuffer(query, ";\n");

+         /* binary_upgrade:  no need to clear TOAST table oid */
+
          ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
                       tbinfo->dobj.name,
                       tbinfo->dobj.namespace->dobj.name,
Index: src/include/commands/typecmds.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/commands/typecmds.h,v
retrieving revision 1.25
diff -c -c -r1.25 typecmds.h
*** src/include/commands/typecmds.h    1 Jan 2009 17:23:58 -0000    1.25
--- src/include/commands/typecmds.h    23 Dec 2009 18:48:12 -0000
***************
*** 25,30 ****
--- 25,31 ----
  extern void DefineDomain(CreateDomainStmt *stmt);
  extern void DefineEnum(CreateEnumStmt *stmt);
  extern Oid    DefineCompositeType(const RangeVar *typevar, List *coldeflist);
+ extern Oid    AssignTypeArrayOid(void);

  extern void AlterDomainDefault(List *names, Node *defaultRaw);
  extern void AlterDomainNotNull(List *names, bool notNull);

Re: Removing pg_migrator limitations

From
Tom Lane
Date:
decibel <decibel@decibel.org> writes:
> Is there some reason why OIDs were used for ENUM instead of a general sequence? Were we worried about people screwing
withthe sequence?
 

No, we were worried about being able to do enum_out without outside
information as to which enum type it is.  If you don't mind doubling
the on-disk size of enum values, we could store the enum type OID and
a sequence number instead.

> A sequences would presumably eliminate all these issues. Even if we wanted to disallow user access to the sequence,
havingsomething that's not competing with all the other uses of OID would presumably make this a lot simpler.
 

The fact that it's shared with other uses of OID is 100% not relevant.
A counter shared across all enums would pose the same issues.  The
only way to simplify matters would be to have each enum have its own
value numbering, which would mean you need outside information to
identify the associated label.

Even if there were a really solid argument for changing this decision,
doing so would create on-disk compatibility problems that would be
even harder for pg_migrator to fix than what we're discussing now.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
Bruce Momjian <bruce@momjian.us> writes:
> The remaining issue is pg_enum oids.  Because it will be difficult to
> pass an arbitrary number of oids into the backend, the idea was to
> assign each enum value separately.  If we implement this TODO item:

>     Allow adding/renaming/removing enumerated values to an existing
>     enumerated data type 

The reason that isn't implemented is that it's *hard* --- in fact,
it appears to be entirely impossible in the general case, unless you're
willing to change existing values of the enum on-disk.  I do not agree
that it's a good plan to try to solve that as a prerequisite to making
pg_migrator work.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Greg Stark
Date:
On Wed, Dec 23, 2009 at 7:17 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Bruce Momjian <bruce@momjian.us> writes:
>> The remaining issue is pg_enum oids.  Because it will be difficult to
>> pass an arbitrary number of oids into the backend, the idea was to
>> assign each enum value separately.  If we implement this TODO item:
>
>>       Allow adding/renaming/removing enumerated values to an existing
>>       enumerated data type
>
> The reason that isn't implemented is that it's *hard* --- in fact,
> it appears to be entirely impossible in the general case, unless you're
> willing to change existing values of the enum on-disk.  I do not agree
> that it's a good plan to try to solve that as a prerequisite to making
> pg_migrator work.

Shouldn't adding new ones be easy? As long as we're willing to make it
fail with an error if there's a conflict -- which is sufficient for
pg_dump's needs.

--
greg


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
Greg Stark <gsstark@mit.edu> writes:
> On Wed, Dec 23, 2009 at 7:17 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> The reason that isn't implemented is that it's *hard* --- in fact,
>> it appears to be entirely impossible in the general case, unless you're
>> willing to change existing values of the enum on-disk.

> Shouldn't adding new ones be easy?

No, not if you care about where they end up in the type's sort ordering.

In pg_migrator's case that's not an issue because it's going to force
the OID numbering for each of the elements.  However, an ADD ENUM VALUE
option that *doesn't* use a predetermined OID is going to end up
inserting the new value at a not-very-predictable place.  I do not think
we should expose a half-baked behavior like that as standard SQL syntax.
If we're going to implement something whose ambitions only extend to
satisfying pg_migrator's needs, then it should be a specialized
pg_migrator function.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Greg Stark
Date:
On Wed, Dec 23, 2009 at 8:09 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> If we're going to implement something whose ambitions only extend to
> satisfying pg_migrator's needs, then it should be a specialized
> pg_migrator function.

Fwiw my feeling was the opposite here. It's better to offer even
limited SQL-level support for features pg_migrator needs because the
more abstract and loosely coupled the interface is between pg_migrator
and the internals the better. Even if the interface is somewhat
limited and just good enough for pg_migrator's needs it's still easier
to support a well-defined abstract interface than one that depends on
knowing about the internal implementation.

I can see I'm outvoted here though and you and Bruce are the ones
writing the code so far...

-- 
greg


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
Greg Stark <gsstark@mit.edu> writes:
> On Wed, Dec 23, 2009 at 8:09 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> If we're going to implement something whose ambitions only extend to
>> satisfying pg_migrator's needs, then it should be a specialized
>> pg_migrator function.

> Fwiw my feeling was the opposite here. It's better to offer even
> limited SQL-level support for features pg_migrator needs because the
> more abstract and loosely coupled the interface is between pg_migrator
> and the internals the better. Even if the interface is somewhat
> limited and just good enough for pg_migrator's needs it's still easier
> to support a well-defined abstract interface than one that depends on
> knowing about the internal implementation.

The problem is that we *don't* want a nice abstract interface.  We want
one that lets us specify the exact OIDs to use for the enum values.
Which is about as non-abstract as you can get.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Tom Lane wrote:
> Greg Stark <gsstark@mit.edu> writes:
> > On Wed, Dec 23, 2009 at 7:17 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> >> The reason that isn't implemented is that it's *hard* --- in fact,
> >> it appears to be entirely impossible in the general case, unless you're
> >> willing to change existing values of the enum on-disk.
> 
> > Shouldn't adding new ones be easy?
> 
> No, not if you care about where they end up in the type's sort ordering.
> 
> In pg_migrator's case that's not an issue because it's going to force
> the OID numbering for each of the elements.  However, an ADD ENUM VALUE
> option that *doesn't* use a predetermined OID is going to end up
> inserting the new value at a not-very-predictable place.  I do not think
> we should expose a half-baked behavior like that as standard SQL syntax.
> If we're going to implement something whose ambitions only extend to
> satisfying pg_migrator's needs, then it should be a specialized
> pg_migrator function.

I looked at DefineEnum() and basically adding the ability to add enums
would put the new enum after the existing ones unless the OID counter
has wrapped around and is less than the oid counter at the time the enum
type was created, in which case it will be listed as before the existing
values.  I wasn't aware enum ordering is something we tried to maintain.
One issue is that we are not supporting the addition of enum values even
for people who don't care about the ordering of enums (which I bet might
be the majority.)

I can think of a few approaches for pg_migrator:
1)  Create an oid array in a permanent memory context and have    DefineEnum() read from that.2)  Renumber the enum
entriesafter they are created but before    any of their oids are stored in user tables.
 

Both can be done by pg_dump with proper server-side functions.  The
problem with #2 are cases where the old and new oid ranges overlap,
e.g.:
1 2 3

becomes:
2 3 4

In that case, you can't just renumber because of oid collisions that
would invalidate the oid index on pg_enum.  Even the ordering of
renumbering might not be consistent, e.g.:

old    1 2 3 12 13 14

new    2 3 4 11 12 13

Starting renumbering from the front or back would both fail.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Andrew Dunstan
Date:

Bruce Momjian wrote:
> I wasn't aware enum ordering is something we tried to maintain.
> One issue is that we are not supporting the addition of enum values even
> for people who don't care about the ordering of enums (which I bet might
> be the majority.)
>   

The ordering of enums is defined and to be relied on and I think it's 
absolutely unacceptable not to be able to rely on the ordering.

We should never be in a position where the values returned by 
enum_first(), enum_range() etc. are not completely deterministic.

Part of the original motivation for implementing enums was precisely so 
that they would sort in the defined order rather than in lexicographical 
order. It's a fundamental part of the type and not an optional feature. 
The idea of potentially breaking it makes no more sense than allowing 
for a non-deterministic ordering of integers.

cheers

andrew


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Andrew Dunstan wrote:
> 
> 
> Bruce Momjian wrote:
> > I wasn't aware enum ordering is something we tried to maintain.
> > One issue is that we are not supporting the addition of enum values even
> > for people who don't care about the ordering of enums (which I bet might
> > be the majority.)
> >   
> 
> The ordering of enums is defined and to be relied on and I think it's 
> absolutely unacceptable not to be able to rely on the ordering.
> 
> We should never be in a position where the values returned by 
> enum_first(), enum_range() etc. are not completely deterministic.

I had no idea we exposed that API.

> Part of the original motivation for implementing enums was precisely so 
> that they would sort in the defined order rather than in lexicographical 
> order. It's a fundamental part of the type and not an optional feature. 
> The idea of potentially breaking it makes no more sense than allowing 
> for a non-deterministic ordering of integers.

OK, I get the point.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Bruce Momjian wrote:
> I looked at DefineEnum() and basically adding the ability to add enums
> would put the new enum after the existing ones unless the OID counter
> has wrapped around and is less than the oid counter at the time the enum
> type was created, in which case it will be listed as before the existing
> values.  I wasn't aware enum ordering is something we tried to maintain.
> One issue is that we are not supporting the addition of enum values even
> for people who don't care about the ordering of enums (which I bet might
> be the majority.)
> 
> I can think of a few approaches for pg_migrator:
> 
>     1)  Create an oid array in a permanent memory context and have
>         DefineEnum() read from that.
>     2)  Renumber the enum entries after they are created but before
>         any of their oids are stored in user tables.
> 
> Both can be done by pg_dump with proper server-side functions.  The
> problem with #2 are cases where the old and new oid ranges overlap,
> e.g.:

I now think the easiest solution will be to have pg_dump create the enum
with a single dummy value, delete the pg_enum dummy row, and then call a
modified version of EnumValuesCreate() to insert row by row into
pg_enum, with specified oids.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Bruce Momjian wrote:
> Bruce Momjian wrote:
> > I looked at DefineEnum() and basically adding the ability to add enums
> > would put the new enum after the existing ones unless the OID counter
> > has wrapped around and is less than the oid counter at the time the enum
> > type was created, in which case it will be listed as before the existing
> > values.  I wasn't aware enum ordering is something we tried to maintain.
> > One issue is that we are not supporting the addition of enum values even
> > for people who don't care about the ordering of enums (which I bet might
> > be the majority.)
> > 
> > I can think of a few approaches for pg_migrator:
> > 
> >     1)  Create an oid array in a permanent memory context and have
> >         DefineEnum() read from that.
> >     2)  Renumber the enum entries after they are created but before
> >         any of their oids are stored in user tables.
> > 
> > Both can be done by pg_dump with proper server-side functions.  The
> > problem with #2 are cases where the old and new oid ranges overlap,
> > e.g.:
> 
> I now think the easiest solution will be to have pg_dump create the enum
> with a single dummy value, delete the pg_enum dummy row, and then call a
> modified version of EnumValuesCreate() to insert row by row into
> pg_enum, with specified oids.

I thought of a cleaner approach.  CREATE TYPE ENUM will create one enum
with the specified oid, and then a server-side function will call
EnumValuesCreate() be used to add each additional enum with a specified
oid --- no deleting necessary.  I will start working on a patch for
this.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
Bruce Momjian <bruce@momjian.us> writes:
> I thought of a cleaner approach.  CREATE TYPE ENUM will create one enum
> with the specified oid, and then a server-side function will call
> EnumValuesCreate() be used to add each additional enum with a specified
> oid --- no deleting necessary.  I will start working on a patch for
> this.

The approach I originally suggested was to create the enum type with
*no* members, and then add the values one at a time.  It might take a
tweak to the CREATE TYPE AS ENUM grammar to allow zero members, but
I don't see any logical problem with such a thing.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Andrew Dunstan
Date:

Bruce Momjian wrote:
>> I now think the easiest solution will be to have pg_dump create the enum
>> with a single dummy value, delete the pg_enum dummy row, and then call a
>> modified version of EnumValuesCreate() to insert row by row into
>> pg_enum, with specified oids.
>>     
>
> I thought of a cleaner approach.  CREATE TYPE ENUM will create one enum
> with the specified oid, and then a server-side function will call
> EnumValuesCreate() be used to add each additional enum with a specified
> oid --- no deleting necessary.  I will start working on a patch for
> this.
>
>   

Either that or Tom's suggested approach of being able to create an empty 
enum type would be much cleaner than the dummy row suggestion.

cheers

andrew


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Tom Lane wrote:
> Bruce Momjian <bruce@momjian.us> writes:
> > I thought of a cleaner approach.  CREATE TYPE ENUM will create one enum
> > with the specified oid, and then a server-side function will call
> > EnumValuesCreate() be used to add each additional enum with a specified
> > oid --- no deleting necessary.  I will start working on a patch for
> > this.
> 
> The approach I originally suggested was to create the enum type with
> *no* members, and then add the values one at a time.  It might take a
> tweak to the CREATE TYPE AS ENUM grammar to allow zero members, but
> I don't see any logical problem with such a thing.

Well, I was hesitant to modify the grammar, unless we want the ability
to create enums with zero values.  Doing enum with only one value will
not be too complex for me and I don't think binary upgrade should affect
the grammar unless there are other reasons we want to change.  I think
it will look like:
-- For binary upgrade, must preserve pg_enum oidsSELECT binary_upgrade.set_next_pg_enum_oid('27258'::pg_catalog.oid);
CREATE TYPE empstatus AS ENUM('hired');
SELECT binary_upgrade.set_next_pg_enum_oid('27259'::pg_catalog.oid);
SELECT binary_upgrade.add_pg_enum_value('42143'::pg_catalog.oid,                                        'retired');

We do allow tables with no columns, but we allow the addition of columns
to a table, so it makes more sense there.

As far as the ability to add enum values using ALTER TYPE, it seems we
would need a pg_enum.enumnum column like we do for pg_attribute.attnum
and order on that rather than pg_enum.oid.   (Binary upgrade would still
need to preserve oids.)

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Bruce Momjian wrote:
> I have completed the attached patch which assigns oids for all pg_type
> rows when pg_dump --binary-upgrade is used.  This allows user-defined
> arrays and composite types to be migrated cleanly.  I tested a reload of
> the regression database with --binary-upgrade and all the pg_type oids
> were identical.  The pg_migrator changes required to use this feature
> are trivial.

Applied.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
Bruce Momjian <bruce@momjian.us> writes:
> Tom Lane wrote:
>> The approach I originally suggested was to create the enum type with
>> *no* members, and then add the values one at a time.

> Well, I was hesitant to modify the grammar, unless we want the ability
> to create enums with zero values.  Doing enum with only one value will
> not be too complex for me and I don't think binary upgrade should affect
> the grammar unless there are other reasons we want to change.

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.

> We do allow tables with no columns, but we allow the addition of columns
> to a table, so it makes more sense there.

Well, we might eventually allow addition of values to enums too; the
fact that it's not implemented outside pg_migrator right now doesn't
mean we won't ever think of a solution.  In any case I'm not persuaded
that a zero-element enum is totally without value.  Think of it like a
domain with a "must be null" constraint.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Andrew Dunstan
Date:

Bruce Momjian wrote:
> As far as the ability to add enum values using ALTER TYPE, it seems we
> would need a pg_enum.enumnum column like we do for pg_attribute.attnum
> and order on that rather than pg_enum.oid.   (Binary upgrade would still
> need to preserve oids.)
>
>   

I don't that's necessarily a good way to go - being able to sort by the 
actual stored value is an efficiency point. I think we might need to 
look at implementing a more extensible enum type, which would allow new 
values to be appended to and possibly inserted into the list of labels, 
but anyway that's really a separate subject from pg_migrator.

cheers

andrew


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Tom Lane wrote:
> Bruce Momjian <bruce@momjian.us> writes:
> > Tom Lane wrote:
> >> The approach I originally suggested was to create the enum type with
> >> *no* members, and then add the values one at a time.
>
> > Well, I was hesitant to modify the grammar, unless we want the ability
> > to create enums with zero values.  Doing enum with only one value will
> > not be too complex for me and I don't think binary upgrade should affect
> > the grammar unless there are other reasons we want to change.
>
> 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.  I have actually coded the variable case already
so you can see how it looks; attached.  Most of the patch is just
indenting of the existing oid assignment block.

> > We do allow tables with no columns, but we allow the addition of columns
> > to a table, so it makes more sense there.
>
> Well, we might eventually allow addition of values to enums too; the
> fact that it's not implemented outside pg_migrator right now doesn't
> mean we won't ever think of a solution.  In any case I'm not persuaded
> that a zero-element enum is totally without value.  Think of it like a
> domain with a "must be null" constraint.

OK, but that is going to expand the my patch.  I will probably implement
zero-element enums first and then go ahead and do the binary upgrade
part.  Zero-element enums will simplify the pg_dump code.

--
  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    24 Dec 2009 22:29:17 -0000
***************
*** 25,30 ****
--- 25,32 ----

  static int    oid_cmp(const void *p1, const void *p2);

+ Oid binary_upgrade_next_pg_enum_oid = InvalidOid;
+

  /*
   * EnumValuesCreate
***************
*** 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));

--- 60,94 ----
      tupDesc = pg_enum->rd_att;

      /*
!      *    Allocate oids
       */
      oids = (Oid *) palloc(num_elems * sizeof(Oid));
!     if (num_elems == 1 && OidIsValid(binary_upgrade_next_pg_enum_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));


Re: Removing pg_migrator limitations

From
Tom Lane
Date:
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 ofadd_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.
        regards, tom lane


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
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.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
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.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Bruce Momjian wrote:
> > Well, we might eventually allow addition of values to enums too; the
> > fact that it's not implemented outside pg_migrator right now doesn't
> > mean we won't ever think of a solution.  In any case I'm not persuaded
> > that a zero-element enum is totally without value.  Think of it like a
> > domain with a "must be null" constraint.
>
> OK, but that is going to expand the my patch.  I will probably implement
> zero-element enums first and then go ahead and do the binary upgrade
> part.  Zero-element enums will simplify the pg_dump code.

I have implemented the zero-value option to CREATE TYPE ENUM with the
attached patch.

--
  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: doc/src/sgml/ref/create_type.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v
retrieving revision 1.79
diff -c -c -r1.79 create_type.sgml
*** doc/src/sgml/ref/create_type.sgml    30 Nov 2008 19:01:29 -0000    1.79
--- doc/src/sgml/ref/create_type.sgml    25 Dec 2009 06:15:56 -0000
***************
*** 25,31 ****
      ( <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable
class="PARAMETER">data_type</replaceable>[, ... ] ) 

  CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
!     ( '<replaceable class="parameter">label</replaceable>' [, ... ] )

  CREATE TYPE <replaceable class="parameter">name</replaceable> (
      INPUT = <replaceable class="parameter">input_function</replaceable>,
--- 25,31 ----
      ( <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable
class="PARAMETER">data_type</replaceable>[, ... ] ) 

  CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
!     ( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )

  CREATE TYPE <replaceable class="parameter">name</replaceable> (
      INPUT = <replaceable class="parameter">input_function</replaceable>,
Index: src/backend/parser/gram.y
===================================================================
RCS file: /cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.699
diff -c -c -r2.699 gram.y
*** src/backend/parser/gram.y    23 Dec 2009 17:41:43 -0000    2.699
--- src/backend/parser/gram.y    25 Dec 2009 06:15:56 -0000
***************
*** 297,303 ****
                  TableFuncElementList opt_type_modifiers
                  prep_type_clause
                  execute_param_clause using_clause returning_clause
!                 enum_val_list table_func_column_list
                  create_generic_options alter_generic_options
                  relation_expr_list dostmt_opt_list

--- 297,303 ----
                  TableFuncElementList opt_type_modifiers
                  prep_type_clause
                  execute_param_clause using_clause returning_clause
!                 opt_enum_val_list enum_val_list table_func_column_list
                  create_generic_options alter_generic_options
                  relation_expr_list dostmt_opt_list

***************
*** 3623,3629 ****
                      n->coldeflist = $6;
                      $$ = (Node *)n;
                  }
!             | CREATE TYPE_P any_name AS ENUM_P '(' enum_val_list ')'
                  {
                      CreateEnumStmt *n = makeNode(CreateEnumStmt);
                      n->typeName = $3;
--- 3623,3629 ----
                      n->coldeflist = $6;
                      $$ = (Node *)n;
                  }
!             | CREATE TYPE_P any_name AS ENUM_P '(' opt_enum_val_list ')'
                  {
                      CreateEnumStmt *n = makeNode(CreateEnumStmt);
                      n->typeName = $3;
***************
*** 3715,3720 ****
--- 3715,3725 ----
                  }
          ;

+ opt_enum_val_list:
+         enum_val_list                            { $$ = $1; }
+         | /*EMPTY*/                                { $$ = NIL; }
+         ;
+
  enum_val_list:    Sconst
                  { $$ = list_make1(makeString($1)); }
              | enum_val_list ',' Sconst

Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Bruce Momjian wrote:
> Bruce Momjian wrote:
> > > Well, we might eventually allow addition of values to enums too; the
> > > fact that it's not implemented outside pg_migrator right now doesn't
> > > mean we won't ever think of a solution.  In any case I'm not persuaded
> > > that a zero-element enum is totally without value.  Think of it like a
> > > domain with a "must be null" constraint.
> > 
> > OK, but that is going to expand the my patch.  I will probably implement
> > zero-element enums first and then go ahead and do the binary upgrade
> > part.  Zero-element enums will simplify the pg_dump code.
> 
> I have implemented the zero-value option to CREATE TYPE ENUM with the
> attached patch.

pg_dump also needs a minor edit for this, which will appear in the oid
assignment patch.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Bruce Momjian wrote:
> Bruce Momjian wrote:
> > > Well, we might eventually allow addition of values to enums too; the
> > > fact that it's not implemented outside pg_migrator right now doesn't
> > > mean we won't ever think of a solution.  In any case I'm not persuaded
> > > that a zero-element enum is totally without value.  Think of it like a
> > > domain with a "must be null" constraint.
> >
> > OK, but that is going to expand the my patch.  I will probably implement
> > zero-element enums first and then go ahead and do the binary upgrade
> > part.  Zero-element enums will simplify the pg_dump code.
>
> I have implemented the zero-value option to CREATE TYPE ENUM with the
> attached patch.

Applied, with pg_dump support too; updated patch attached.

--
  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: doc/src/sgml/ref/create_type.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v
retrieving revision 1.79
diff -c -c -r1.79 create_type.sgml
*** doc/src/sgml/ref/create_type.sgml    30 Nov 2008 19:01:29 -0000    1.79
--- doc/src/sgml/ref/create_type.sgml    26 Dec 2009 16:50:35 -0000
***************
*** 25,31 ****
      ( <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable
class="PARAMETER">data_type</replaceable>[, ... ] ) 

  CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
!     ( '<replaceable class="parameter">label</replaceable>' [, ... ] )

  CREATE TYPE <replaceable class="parameter">name</replaceable> (
      INPUT = <replaceable class="parameter">input_function</replaceable>,
--- 25,31 ----
      ( <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable
class="PARAMETER">data_type</replaceable>[, ... ] ) 

  CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
!     ( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )

  CREATE TYPE <replaceable class="parameter">name</replaceable> (
      INPUT = <replaceable class="parameter">input_function</replaceable>,
Index: src/backend/parser/gram.y
===================================================================
RCS file: /cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.699
diff -c -c -r2.699 gram.y
*** src/backend/parser/gram.y    23 Dec 2009 17:41:43 -0000    2.699
--- src/backend/parser/gram.y    26 Dec 2009 16:50:35 -0000
***************
*** 297,303 ****
                  TableFuncElementList opt_type_modifiers
                  prep_type_clause
                  execute_param_clause using_clause returning_clause
!                 enum_val_list table_func_column_list
                  create_generic_options alter_generic_options
                  relation_expr_list dostmt_opt_list

--- 297,303 ----
                  TableFuncElementList opt_type_modifiers
                  prep_type_clause
                  execute_param_clause using_clause returning_clause
!                 opt_enum_val_list enum_val_list table_func_column_list
                  create_generic_options alter_generic_options
                  relation_expr_list dostmt_opt_list

***************
*** 3623,3629 ****
                      n->coldeflist = $6;
                      $$ = (Node *)n;
                  }
!             | CREATE TYPE_P any_name AS ENUM_P '(' enum_val_list ')'
                  {
                      CreateEnumStmt *n = makeNode(CreateEnumStmt);
                      n->typeName = $3;
--- 3623,3629 ----
                      n->coldeflist = $6;
                      $$ = (Node *)n;
                  }
!             | CREATE TYPE_P any_name AS ENUM_P '(' opt_enum_val_list ')'
                  {
                      CreateEnumStmt *n = makeNode(CreateEnumStmt);
                      n->typeName = $3;
***************
*** 3715,3720 ****
--- 3715,3725 ----
                  }
          ;

+ opt_enum_val_list:
+         enum_val_list                            { $$ = $1; }
+         | /*EMPTY*/                                { $$ = NIL; }
+         ;
+
  enum_val_list:    Sconst
                  { $$ = list_make1(makeString($1)); }
              | enum_val_list ',' Sconst
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.561
diff -c -c -r1.561 pg_dump.c
*** src/bin/pg_dump/pg_dump.c    24 Dec 2009 22:09:23 -0000    1.561
--- src/bin/pg_dump/pg_dump.c    26 Dec 2009 16:50:35 -0000
***************
*** 6542,6553 ****
      check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);

      num = PQntuples(res);
-     /* should be at least 1 value */
-     if (num == 0)
-     {
-         write_msg(NULL, "no label definitions found for enum ID %u\n", tyinfo->dobj.catId.oid);
-         exit_nicely();
-     }

      /*
       * DROP must be fully qualified in case same name appears in pg_catalog.
--- 6542,6547 ----

Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
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 */

Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Bruce Momjian wrote:
> 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.

Applied.  I also bumped the catalog version so pg_migrator can detect
the new backend API by looking at pg_control.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Bruce Momjian wrote:
> There are several pg_migrator limitations that appeared late in the 8.4
> development cycle and were impossible to fix at that point.  I would
> like to fix them for Postgres 8.5:
> 
>         o  a user-defined composite data type
>         o  a user-defined array data type
>         o  a user-defined enum data type

FYI, these pg_migrator restrictions are now gone when migrating to PG
8.5, even _from_ PG 8.3.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Greg Stark
Date:
I'm kind of curious about the heap page conversion plan. I think we have a plan for how to do page checksums now if
someonesubmits it now will we have time to do the page wok to handle page conversions? Or if not, are we better off
waitingtill 8.6 to get checksums? 

"Bruce Momjian" <bruce@momjian.us> wrote:

>Bruce Momjian wrote:
>> 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.
>
>Applied.  I also bumped the catalog version so pg_migrator can detect
>the new backend API by looking at pg_control.
>
>-- 
>  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
>  EnterpriseDB                             http://enterprisedb.com
>
>  + If your life is a hard drive, Christ can be your backup. +

--
Sent from my Android phone with K-9. Please excuse my brevity.

Re: Removing pg_migrator limitations

From
Robert Haas
Date:
On Sun, Dec 27, 2009 at 9:53 AM, Bruce Momjian <bruce@momjian.us> wrote:
> Bruce Momjian wrote:
>> There are several pg_migrator limitations that appeared late in the 8.4
>> development cycle and were impossible to fix at that point.  I would
>> like to fix them for Postgres 8.5:
>>
>>         o  a user-defined composite data type
>>         o  a user-defined array data type
>>         o  a user-defined enum data type
>
> FYI, these pg_migrator restrictions are now gone when migrating to PG
> 8.5, even _from_ PG 8.3.

Wow, cool.  That seems like a good step forward.

...Robert


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Greg Stark wrote:
> I'm kind of curious about the heap page conversion plan. I think
> we have a plan for how to do page checksums now if someone
> submits it now will we have time to do the page wok to handle
> page conversions? Or if not, are we better off waiting till 8.6
> to get checksums?

Well, I think the checksums are going in the item pointers, so there
isn't any new storage space --- my guess is that the page version number
will control how the backend stores the checksum.  Basically the backend
will need to read old and new page versions.  I don't think this is
something pg_migrator can handle cleanly.


-- Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Greg Stark
Date:
On Sun, Dec 27, 2009 at 8:13 PM, Bruce Momjian <bruce@momjian.us> wrote:
> Well, I think the checksums are going in the item pointers, so there
> isn't any new storage space --- my guess is that the page version number
> will control how the backend stores the checksum.  Basically the backend
> will need to read old and new page versions.  I don't think this is
> something pg_migrator can handle cleanly.

I thought our plan was to only read old page versions and
automatically rewrite them to new page versions. We'll have to add the
hooks and the page rewrite code  to do that, no?

Is that something we're comfortable adding in the final commitfest?


--
greg


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Greg Stark wrote:
> On Sun, Dec 27, 2009 at 8:13 PM, Bruce Momjian <bruce@momjian.us> wrote:
> > Well, I think the checksums are going in the item pointers, so there
> > isn't any new storage space --- my guess is that the page version number
> > will control how the backend stores the checksum. ?Basically the backend
> > will need to read old and new page versions. ?I don't think this is
> > something pg_migrator can handle cleanly.
> 
> I thought our plan was to only read old page versions and
> automatically rewrite them to new page versions. We'll have to add the
> hooks and the page rewrite code  to do that, no?

Well, the idea of only reading the old version is so we didn't have to
carry around a lot of type-specific information in the backend, but I am
not sure if that applies to a hint bit change.

> Is that something we're comfortable adding in the final commitfest?

Uh, no idea.  It would be nice, of course.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Robert Haas
Date:
On Sun, Dec 27, 2009 at 5:15 PM, Bruce Momjian <bruce@momjian.us> wrote:
>> Is that something we're comfortable adding in the final commitfest?
>
> Uh, no idea.  It would be nice, of course.

Do we know if there's active development in progress on page CRCs?  If
so, when can we expect to see a working patch?

With respect to adding it in the final CommitFest, I am concerned that
this might be a big enough feature that it would be destabilizing, and
I'm pretty disinclined to do anything that will destabilize the tree
at this point in the release cycle.  Part of my concern is that we
just committed a really big feature (Hot Standby) that has already had
a few bug reports and also has a known issue with VACUUM FULL that
needs to be addressed.  It seems likely there is going to be a good
deal more work that has to be done there.  I'm worried that adding
more big features in the relatively small amount of time that remains
before we are ostensibly going to beta is going to result in a very
buggy beta and/or a buggy release (I am also concerned about Streaming
Replication in this regard).

On the other hand, since we have yet to see an actual patch to
implement page CRCs, it may be premature to draw conclusions about how
destabilizing and/or invasive it will be.  If it's not that bad, maybe
it's OK.  Another option, if it turns out that we have several major
patches that we don't feel comfortable committing for 8.5, is to
branch the tree prior to the release - for example, at the start of
beta.  Then we could commit those features for 8.6 and just apply any
remaining changes for 8.5 to both branches.  This is a little more
work for the committers, but it has the advantage of getting the big
patches into our tree early, versus leaving them elsewhere where they
may bitrot or fall through the cracks, so I think it might be worth
it.

...Robert


Re: Removing pg_migrator limitations

From
Robert Haas
Date:
On Sun, Dec 27, 2009 at 2:16 PM, Robert Haas <robertmhaas@gmail.com> wrote:
> On Sun, Dec 27, 2009 at 9:53 AM, Bruce Momjian <bruce@momjian.us> wrote:
>> Bruce Momjian wrote:
>>> There are several pg_migrator limitations that appeared late in the 8.4
>>> development cycle and were impossible to fix at that point.  I would
>>> like to fix them for Postgres 8.5:
>>>
>>>         o  a user-defined composite data type
>>>         o  a user-defined array data type
>>>         o  a user-defined enum data type
>>
>> FYI, these pg_migrator restrictions are now gone when migrating to PG
>> 8.5, even _from_ PG 8.3.
>
> Wow, cool.  That seems like a good step forward.

It appears that the pg_migrator README needs a bit of revision to make
it more clear which limitations apply to migration between which
versions.  In particular, the current wording suggests that NONE of
the limitations apply to 8.3 -> 8.5 migrations, which is not the case
- e.g. we haven't done anything about the need to rebuild certain
types of indices.

...Robert


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Robert Haas wrote:
> On Sun, Dec 27, 2009 at 2:16 PM, Robert Haas <robertmhaas@gmail.com> wrote:
> > On Sun, Dec 27, 2009 at 9:53 AM, Bruce Momjian <bruce@momjian.us> wrote:
> >> Bruce Momjian wrote:
> >>> There are several pg_migrator limitations that appeared late in the 8.4
> >>> development cycle and were impossible to fix at that point. ?I would
> >>> like to fix them for Postgres 8.5:
> >>>
> >>> ? ? ? ? o ?a user-defined composite data type
> >>> ? ? ? ? o ?a user-defined array data type
> >>> ? ? ? ? o ?a user-defined enum data type
> >>
> >> FYI, these pg_migrator restrictions are now gone when migrating to PG
> >> 8.5, even _from_ PG 8.3.
> >
> > Wow, cool. ?That seems like a good step forward.
> 
> It appears that the pg_migrator README needs a bit of revision to make
> it more clear which limitations apply to migration between which
> versions.  In particular, the current wording suggests that NONE of
> the limitations apply to 8.3 -> 8.5 migrations, which is not the case
> - e.g. we haven't done anything about the need to rebuild certain
> types of indices.

Very true. I have just made a new pg_migrator release with an updated
README file.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Removing pg_migrator limitations

From
Robert Haas
Date:
On Mon, Dec 28, 2009 at 10:48 AM, Bruce Momjian <bruce@momjian.us> wrote:
> Robert Haas wrote:
>> On Sun, Dec 27, 2009 at 2:16 PM, Robert Haas <robertmhaas@gmail.com> wrote:
>> > On Sun, Dec 27, 2009 at 9:53 AM, Bruce Momjian <bruce@momjian.us> wrote:
>> >> Bruce Momjian wrote:
>> >>> There are several pg_migrator limitations that appeared late in the 8.4
>> >>> development cycle and were impossible to fix at that point. ?I would
>> >>> like to fix them for Postgres 8.5:
>> >>>
>> >>> ? ? ? ? o ?a user-defined composite data type
>> >>> ? ? ? ? o ?a user-defined array data type
>> >>> ? ? ? ? o ?a user-defined enum data type
>> >>
>> >> FYI, these pg_migrator restrictions are now gone when migrating to PG
>> >> 8.5, even _from_ PG 8.3.
>> >
>> > Wow, cool. ?That seems like a good step forward.
>>
>> It appears that the pg_migrator README needs a bit of revision to make
>> it more clear which limitations apply to migration between which
>> versions.  In particular, the current wording suggests that NONE of
>> the limitations apply to 8.3 -> 8.5 migrations, which is not the case
>> - e.g. we haven't done anything about the need to rebuild certain
>> types of indices.
>
> Very true. I have just made a new pg_migrator release with an updated
> README file.

Ah, cool.  So this seems to imply that a migration from 8.4 to 8.5
should be clear sailing.  Is that correct?

...Robert


Re: Removing pg_migrator limitations

From
Bruce Momjian
Date:
Robert Haas wrote:
> On Mon, Dec 28, 2009 at 10:48 AM, Bruce Momjian <bruce@momjian.us> wrote:
> > Robert Haas wrote:
> >> On Sun, Dec 27, 2009 at 2:16 PM, Robert Haas <robertmhaas@gmail.com> wrote:
> >> > On Sun, Dec 27, 2009 at 9:53 AM, Bruce Momjian <bruce@momjian.us> wrote:
> >> >> Bruce Momjian wrote:
> >> >>> There are several pg_migrator limitations that appeared late in the 8.4
> >> >>> development cycle and were impossible to fix at that point. ?I would
> >> >>> like to fix them for Postgres 8.5:
> >> >>>
> >> >>> ? ? ? ? o ?a user-defined composite data type
> >> >>> ? ? ? ? o ?a user-defined array data type
> >> >>> ? ? ? ? o ?a user-defined enum data type
> >> >>
> >> >> FYI, these pg_migrator restrictions are now gone when migrating to PG
> >> >> 8.5, even _from_ PG 8.3.
> >> >
> >> > Wow, cool. ?That seems like a good step forward.
> >>
> >> It appears that the pg_migrator README needs a bit of revision to make
> >> it more clear which limitations apply to migration between which
> >> versions. ?In particular, the current wording suggests that NONE of
> >> the limitations apply to 8.3 -> 8.5 migrations, which is not the case
> >> - e.g. we haven't done anything about the need to rebuild certain
> >> types of indices.
> >
> > Very true. I have just made a new pg_migrator release with an updated
> > README file.
> 
> Ah, cool.  So this seems to imply that a migration from 8.4 to 8.5
> should be clear sailing.  Is that correct?

Yes, so far.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +