Re: Removing pg_migrator limitations

Поиск
Список
Период
Сортировка
Искать

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Alvaro Herrera <alvherre@commandprompt.com>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Alvaro Herrera <alvherre@commandprompt.com>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Alvaro Herrera <alvherre@commandprompt.com>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Alvaro Herrera <alvherre@commandprompt.com>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:
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          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

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:
Bruce Momjian wrote:
> Tom Lane wrote:
> > Bruce Momjian  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          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

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:
Tom Lane wrote:
> Bruce Momjian  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          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

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:
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          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 ****
      ( attribute_name data_type [, ... ] )
  
  CREATE TYPE name AS ENUM
!     ( 'label' [, ... ] )
  
  CREATE TYPE name (
      INPUT = input_function,
--- 25,31 ----
      ( attribute_name data_type [, ... ] )
  
  CREATE TYPE name AS ENUM
!     ( [ 'label' [, ... ] ] )
  
  CREATE TYPE name (
      INPUT = input_function,
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

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:
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          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 ****
      ( attribute_name data_type [, ... ] )
  
  CREATE TYPE name AS ENUM
!     ( 'label' [, ... ] )
  
  CREATE TYPE name (
      INPUT = input_function,
--- 25,31 ----
      ( attribute_name data_type [, ... ] )
  
  CREATE TYPE name AS ENUM
!     ( [ 'label' [, ... ] ] )
  
  CREATE TYPE name (
      INPUT = input_function,
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

От:
Bruce Momjian <bruce@momjian.us>
Дата:
Bruce Momjian wrote:
> Bruce Momjian wrote:
> > Tom Lane wrote:
> > > Bruce Momjian  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          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

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Bruce Momjian <bruce@momjian.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
decibel <decibel@decibel.org>
Дата:

Re: Removing pg_migrator limitations

От:
Greg Stark <gsstark@mit.edu>
Дата:

Re: Removing pg_migrator limitations

От:
Greg Stark <gsstark@mit.edu>
Дата:

Re: Removing pg_migrator limitations

От:
Greg Stark <stark@mit.edu>
Дата:

Re: Removing pg_migrator limitations

От:
Andrew Dunstan <andrew@dunslane.net>
Дата:

Re: Removing pg_migrator limitations

От:
Andrew Dunstan <andrew@dunslane.net>
Дата:

Re: Removing pg_migrator limitations

От:
Joe Conway <mail@joeconway.com>
Дата:

Re: Removing pg_migrator limitations

От:
Andrew Dunstan <andrew@dunslane.net>
Дата:

Re: Removing pg_migrator limitations

От:
Andrew Dunstan <andrew@dunslane.net>
Дата:

Re: Removing pg_migrator limitations

От:
Andrew Dunstan <andrew@dunslane.net>
Дата:

Re: Removing pg_migrator limitations

От:
Robert Haas <robertmhaas@gmail.com>
Дата:

Re: Removing pg_migrator limitations

От:
Robert Haas <robertmhaas@gmail.com>
Дата:

Re: Removing pg_migrator limitations

От:
Robert Haas <robertmhaas@gmail.com>
Дата:

Re: Removing pg_migrator limitations

От:
Robert Haas <robertmhaas@gmail.com>
Дата:

Re: Removing pg_migrator limitations

От:
Robert Haas <robertmhaas@gmail.com>
Дата:

Re: Removing pg_migrator limitations

От:
Robert Haas <robertmhaas@gmail.com>
Дата:

Re: Removing pg_migrator limitations

От:
Robert Haas <robertmhaas@gmail.com>
Дата:

Re: Removing pg_migrator limitations

От:
Robert Haas <robertmhaas@gmail.com>
Дата:

Re: Removing pg_migrator limitations

От:
Tom Lane <tgl@sss.pgh.pa.us>
Дата:

Re: Removing pg_migrator limitations

От:
"Marc G. Fournier" <scrappy@hub.org>
Дата:

Re: Removing pg_migrator limitations

От:
Greg Stark <stark@mit.edu>
Дата:
FAQ