mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-30 00:04:49 -04:00 
			
		
		
		
	pg_upgrade: prevent oid conflicts with new-cluster TOAST tables
Previously, TOAST tables only required in the new cluster could cause oid conflicts if they were auto-numbered and a later conflicting oid had to be assigned. Backpatch through 9.3
This commit is contained in:
		
							parent
							
								
									ec903d20e3
								
							
						
					
					
						commit
						4c6780fd17
					
				| @ -12,6 +12,8 @@ | ||||
| #include "pg_upgrade.h" | ||||
| 
 | ||||
| #include <sys/types.h> | ||||
| #include "catalog/binary_upgrade.h" | ||||
| 
 | ||||
| 
 | ||||
| void | ||||
| generate_old_dump(void) | ||||
| @ -67,3 +69,71 @@ generate_old_dump(void) | ||||
| 	end_progress_output(); | ||||
| 	check_ok(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * It is possible for there to be a mismatch in the need for TOAST tables | ||||
|  * between the old and new servers, e.g. some pre-9.1 tables didn't need | ||||
|  * TOAST tables but will need them in 9.1+.  (There are also opposite cases, | ||||
|  * but these are handled by setting binary_upgrade_next_toast_pg_class_oid.) | ||||
|  * | ||||
|  * We can't allow the TOAST table to be created by pg_dump with a | ||||
|  * pg_dump-assigned oid because it might conflict with a later table that | ||||
|  * uses that oid, causing a "file exists" error for pg_class conflicts, and | ||||
|  * a "duplicate oid" error for pg_type conflicts.  (TOAST tables need pg_type | ||||
|  * entries.) | ||||
|  * | ||||
|  * Therefore, a backend in binary-upgrade mode will not create a TOAST | ||||
|  * table unless an OID as passed in via pg_upgrade_support functions. | ||||
|  * This function is called after the restore and uses ALTER TABLE to | ||||
|  * auto-create any needed TOAST tables which will not conflict with | ||||
|  * restored oids. | ||||
|  */ | ||||
| void | ||||
| optionally_create_toast_tables(void) | ||||
| { | ||||
| 	int			dbnum; | ||||
| 
 | ||||
| 	prep_status("Creating newly-required TOAST tables"); | ||||
| 
 | ||||
| 	for (dbnum = 0; dbnum < new_cluster.dbarr.ndbs; dbnum++) | ||||
| 	{ | ||||
| 		PGresult   *res; | ||||
| 		int			ntups; | ||||
| 		int			rowno; | ||||
| 		int			i_nspname, | ||||
| 					i_relname; | ||||
| 		DbInfo	   *active_db = &new_cluster.dbarr.dbs[dbnum]; | ||||
| 		PGconn	   *conn = connectToServer(&new_cluster, active_db->db_name); | ||||
| 
 | ||||
| 		res = executeQueryOrDie(conn, | ||||
| 								"SELECT n.nspname, c.relname " | ||||
| 								"FROM	pg_catalog.pg_class c, " | ||||
| 								"		pg_catalog.pg_namespace n " | ||||
| 								"WHERE	c.relnamespace = n.oid AND " | ||||
| 							  "		n.nspname NOT IN ('pg_catalog', 'information_schema') AND " | ||||
| 								"c.relkind IN ('r', 'm') AND " | ||||
| 								"c.reltoastrelid = 0"); | ||||
| 
 | ||||
| 		ntups = PQntuples(res); | ||||
| 		i_nspname = PQfnumber(res, "nspname"); | ||||
| 		i_relname = PQfnumber(res, "relname"); | ||||
| 		for (rowno = 0; rowno < ntups; rowno++) | ||||
| 		{ | ||||
| 			/* enable auto-oid-numbered TOAST creation if needed */ | ||||
| 			PQclear(executeQueryOrDie(conn, "SELECT binary_upgrade.set_next_toast_pg_class_oid('%d'::pg_catalog.oid);", | ||||
| 					OPTIONALLY_CREATE_TOAST_OID)); | ||||
| 
 | ||||
| 			/* dummy command that also triggers check for required TOAST table */ | ||||
| 			PQclear(executeQueryOrDie(conn, "ALTER TABLE %s.%s RESET (binary_upgrade_dummy_option);", | ||||
| 					quote_identifier(PQgetvalue(res, rowno, i_nspname)), | ||||
| 					quote_identifier(PQgetvalue(res, rowno, i_relname)))); | ||||
| 		} | ||||
| 
 | ||||
| 		PQclear(res); | ||||
| 
 | ||||
| 		PQfinish(conn); | ||||
| 	} | ||||
| 
 | ||||
| 	check_ok(); | ||||
| } | ||||
|  | ||||
| @ -363,6 +363,8 @@ create_new_objects(void) | ||||
| 	if (GET_MAJOR_VERSION(old_cluster.major_version) < 903) | ||||
| 		set_frozenxids(true); | ||||
| 
 | ||||
| 	optionally_create_toast_tables(); | ||||
| 
 | ||||
| 	/* regenerate now that we have objects in the databases */ | ||||
| 	get_db_and_rel_infos(&new_cluster); | ||||
| 
 | ||||
|  | ||||
| @ -336,6 +336,7 @@ void		disable_old_cluster(void); | ||||
| /* dump.c */ | ||||
| 
 | ||||
| void		generate_old_dump(void); | ||||
| void		optionally_create_toast_tables(void); | ||||
| 
 | ||||
| 
 | ||||
| /* exec.c */ | ||||
|  | ||||
| @ -165,16 +165,51 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, | ||||
| 	if (rel->rd_rel->reltoastrelid != InvalidOid) | ||||
| 		return false; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Check to see whether the table actually needs a TOAST table. | ||||
| 	 * | ||||
| 	 * If an update-in-place toast relfilenode is specified, force toast file | ||||
| 	 * creation even if it seems not to need one. | ||||
| 	 */ | ||||
| 	if (!needs_toast_table(rel) && | ||||
| 		(!IsBinaryUpgrade || | ||||
| 		 !OidIsValid(binary_upgrade_next_toast_pg_class_oid))) | ||||
| 	if (!IsBinaryUpgrade) | ||||
| 	{ | ||||
| 		if (!needs_toast_table(rel)) | ||||
| 			return false; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		/*
 | ||||
| 		 * Check to see whether the table needs a TOAST table. | ||||
| 		 * | ||||
| 		 * If an update-in-place TOAST relfilenode is specified, force TOAST file | ||||
| 		 * creation even if it seems not to need one.  This handles the case | ||||
| 		 * where the old cluster needed a TOAST table but the new cluster | ||||
| 		 * would not normally create one. | ||||
| 		 */ | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * If a TOAST oid is not specified, skip TOAST creation as we will do | ||||
| 		 * it later so we don't create a TOAST table whose OID later conflicts | ||||
| 		 * with a user-supplied OID.  This handles cases where the old cluster | ||||
| 		 * didn't need a TOAST table, but the new cluster does. | ||||
| 		 */ | ||||
| 		if (!OidIsValid(binary_upgrade_next_toast_pg_class_oid)) | ||||
| 			return false; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * If a special TOAST value has been passed in, it means we are in | ||||
| 		 * cleanup mode --- we are creating needed TOAST tables after all user | ||||
| 		 * tables with specified OIDs have been created.  We let the system | ||||
| 		 * assign a TOAST oid for us.  The tables are empty so the missing | ||||
| 		 * TOAST tables were not a problem. | ||||
| 		 */ | ||||
| 		if (binary_upgrade_next_toast_pg_class_oid == OPTIONALLY_CREATE_TOAST_OID) | ||||
| 		{ | ||||
| 			/* clear as it is not to be used; it is just a flag */ | ||||
| 			binary_upgrade_next_toast_pg_class_oid = InvalidOid; | ||||
| 
 | ||||
| 			if (!needs_toast_table(rel)) | ||||
| 				return false; | ||||
| 		} | ||||
| 
 | ||||
| 		/* both should be set, or not set */ | ||||
| 		Assert(OidIsValid(binary_upgrade_next_toast_pg_class_oid) == | ||||
| 			   OidIsValid(binary_upgrade_next_toast_pg_type_oid)); | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If requested check lockmode is sufficient. This is a cross check in | ||||
|  | ||||
| @ -14,6 +14,11 @@ | ||||
| #ifndef BINARY_UPGRADE_H | ||||
| #define BINARY_UPGRADE_H | ||||
| 
 | ||||
| #include "catalog/pg_authid.h" | ||||
| 
 | ||||
| /* pick a OID that will never be used for TOAST tables */ | ||||
| #define OPTIONALLY_CREATE_TOAST_OID	BOOTSTRAP_SUPERUSERID | ||||
| 
 | ||||
| extern PGDLLIMPORT Oid binary_upgrade_next_pg_type_oid; | ||||
| extern PGDLLIMPORT Oid binary_upgrade_next_array_pg_type_oid; | ||||
| extern PGDLLIMPORT Oid binary_upgrade_next_toast_pg_type_oid; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user