Fix possible page corruption by ALTER TABLE .. SET TABLESPACE.
authorRobert Haas <[email protected]>
Thu, 29 Jul 2010 16:15:47 +0000 (16:15 +0000)
committerRobert Haas <[email protected]>
Thu, 29 Jul 2010 16:15:47 +0000 (16:15 +0000)
If a zeroed page is present in the heap, ALTER TABLE .. SET TABLESPACE will
set the LSN and TLI while copying it, which is wrong, and heap_xlog_newpage()
will do the same thing during replay, so the corruption propagates to any
standby.  Note, however, that the bug can't be demonstrated unless archiving
is enabled, since in that case we skip WAL logging altogether, and the LSN/TLI
are not set.

Back-patch to 8.0; prior releases do not have tablespaces.

Analysis and patch by Jeff Davis.  Adjustments for back-branches and minor
wordsmithing by me.

src/backend/access/heap/heapam.c
src/backend/commands/tablecmds.c

index 075e4f542056b1cb0c21bdc5168f40fc4e8a6f17..c44bbed3683ebbd1bdb05346d9e9cff32a6df9fd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.182.4.1 2005/08/25 19:44:52 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.182.4.2 2010/07/29 16:15:47 rhaas Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -2304,8 +2304,16 @@ heap_xlog_newpage(bool redo, XLogRecPtr lsn, XLogRecord *record)
        Assert(record->xl_len == SizeOfHeapNewpage + BLCKSZ);
        memcpy(page, (char *) xlrec + SizeOfHeapNewpage, BLCKSZ);
 
-       PageSetLSN(page, lsn);
-       PageSetTLI(page, ThisTimeLineID);
+       /*
+        * The page may be uninitialized. If so, we can't set the LSN
+        * and TLI because that would corrupt the page.
+        */
+       if (!PageIsNew(page))
+       {
+               PageSetLSN(page, lsn);
+               PageSetTLI(page, ThisTimeLineID);
+       }
+
        LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
        WriteBuffer(buffer);
 }
index b6d9d94e0d2cc69f9215821588aa7f6911a46178..f82109bab359e20c6571c51b8e50fe84eb5869ce 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.142.4.12 2010/07/01 14:10:42 rhaas Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.142.4.13 2010/07/29 16:15:47 rhaas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -5786,8 +5786,15 @@ copy_relation_data(Relation rel, SMgrRelation dst)
 
                        recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_NEWPAGE, rdata);
 
-                       PageSetLSN(page, recptr);
-                       PageSetTLI(page, ThisTimeLineID);
+                       /*
+                        * The page may be uninitialized. If so, we can't set the LSN
+                        * and TLI because that would corrupt the page.
+                        */
+                       if (!PageIsNew(page))
+                       {
+                               PageSetLSN(page, recptr);
+                               PageSetTLI(page, ThisTimeLineID);
+                       }
 
                        END_CRIT_SECTION();
                }