summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2010-07-29 16:15:05 +0000
committerRobert Haas <rhaas@postgresql.org>2010-07-29 16:15:05 +0000
commit0378e4e73de6019353caff1cca43562d0c0e49d6 (patch)
tree671292ef2c1780351b6717ab28a6e38458fb56df
parent581fe9331daab6bf65219fb842a75a90a438b605 (diff)
Fix possible page corruption by ALTER TABLE .. SET TABLESPACE.
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.
-rw-r--r--src/backend/access/heap/heapam.c25
1 files changed, 20 insertions, 5 deletions
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 566e431cca9..10644c7d8f1 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.249.2.5 2009/06/10 18:54:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.249.2.6 2010/07/29 16:15:05 rhaas Exp $
*
*
* INTERFACE ROUTINES
@@ -3962,8 +3962,15 @@ log_newpage(RelFileNode *rnode, BlockNumber blkno, Page page)
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();
@@ -4099,8 +4106,16 @@ heap_xlog_newpage(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);
+ }
+
MarkBufferDirty(buffer);
UnlockReleaseBuffer(buffer);
}