aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2008-10-07 11:15:54 +0000
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2008-10-07 11:15:54 +0000
commit433ba2dd560141dd3415ab7e2ddedb23b48c2024 (patch)
tree5ad57b54e81201486a03bace2c4f8c8a8d87dc3f
parent05da8a6430739e99ea93d77053dae054b5cc030a (diff)
downloadpostgresql-433ba2dd560141dd3415ab7e2ddedb23b48c2024.tar.gz
postgresql-433ba2dd560141dd3415ab7e2ddedb23b48c2024.zip
When a relation is moved to another tablespace, we can't assume that we can
use the old relfilenode in the new tablespace. There might be another relation in the new tablespace with the same relfilenode, so we must generate a fresh relfilenode in the new tablespace. The 8.3 patch to let deleted relation files linger as zero-length files until the next checkpoint made this more obvious: moving a relation from one table space another, and then back again, caused a collision with the lingering file. Back-patch to 8.1. The issue is present in 8.0 as well, but it doesn't seem worth fixing there, because we didn't have protection from OID collisions after OID wraparound before 8.1. Report by Guillaume Lelarge.
-rw-r--r--src/backend/commands/tablecmds.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3006f0a3627..36f802eb1e6 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.206.2.6 2008/05/27 21:13:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.206.2.7 2008/10/07 11:15:54 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -5971,6 +5971,7 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace)
Oid oldTableSpace;
Oid reltoastrelid;
Oid reltoastidxid;
+ Oid newrelfilenode;
RelFileNode newrnode;
SMgrRelation dstrel;
Relation pg_class;
@@ -6025,9 +6026,18 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace)
elog(ERROR, "cache lookup failed for relation %u", tableOid);
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
+ /*
+ * Relfilenodes are not unique across tablespaces, so we need to allocate
+ * a new one in the new tablespace.
+ */
+ newrelfilenode = GetNewRelFileNode(newTableSpace,
+ rel->rd_rel->relisshared,
+ NULL);
+
/* create another storage file. Is it a little ugly ? */
/* NOTE: any conflict in relfilenode value will be caught here */
newrnode = rel->rd_node;
+ newrnode.relNode = newrelfilenode;
newrnode.spcNode = newTableSpace;
dstrel = smgropen(newrnode);
@@ -6048,6 +6058,7 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace)
/* update the pg_class row */
rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace;
+ rd_rel->relfilenode = newrelfilenode;
simple_heap_update(pg_class, &tuple->t_self, tuple);
CatalogUpdateIndexes(pg_class, tuple);