]> granicus.if.org Git - postgresql/commitdiff
Fix checksums for CLUSTER, VACUUM FULL etc.
authorSimon Riggs <simon@2ndQuadrant.com>
Sun, 7 Apr 2013 21:16:51 +0000 (22:16 +0100)
committerSimon Riggs <simon@2ndQuadrant.com>
Sun, 7 Apr 2013 21:16:51 +0000 (22:16 +0100)
In CLUSTER, VACUUM FULL and ALTER TABLE SET TABLESPACE
I erroneously set checksum before log_newpage, which
sets the LSN and invalidates the checksum. So set
checksum immediately *after* log_newpage.

Bug report Fujii Masao, Fix and patch by Jeff Davis

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

index 8a22eccf87aa9fbae8b7126907d1d67873c6c9c1..a3aad3adf915a9a28a53a694998f0e1e90ffbd53 100644 (file)
@@ -273,14 +273,15 @@ end_heap_rewrite(RewriteState state)
        /* Write the last page, if any */
        if (state->rs_buffer_valid)
        {
-               PageSetChecksumInplace(state->rs_buffer, state->rs_blockno);
-
                if (state->rs_use_wal)
                        log_newpage(&state->rs_new_rel->rd_node,
                                                MAIN_FORKNUM,
                                                state->rs_blockno,
                                                state->rs_buffer);
                RelationOpenSmgr(state->rs_new_rel);
+
+               PageSetChecksumInplace(state->rs_buffer, state->rs_blockno);
+
                smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM, state->rs_blockno,
                                   (char *) state->rs_buffer, true);
        }
@@ -616,8 +617,6 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
                {
                        /* Doesn't fit, so write out the existing page */
 
-                       PageSetChecksumInplace(page, state->rs_blockno);
-
                        /* XLOG stuff */
                        if (state->rs_use_wal)
                                log_newpage(&state->rs_new_rel->rd_node,
@@ -632,6 +631,9 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
                         * end_heap_rewrite.
                         */
                        RelationOpenSmgr(state->rs_new_rel);
+
+                       PageSetChecksumInplace(page, state->rs_blockno);
+
                        smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM,
                                           state->rs_blockno, (char *) page, true);
 
index 536d232dd41e26299a9be3641ebbbfdba858cf5f..81c119974291d5333e1a72c7575aead98349efff 100644 (file)
@@ -51,6 +51,7 @@
 #include "commands/tablespace.h"
 #include "commands/trigger.h"
 #include "commands/typecmds.h"
+#include "common/relpath.h"
 #include "executor/executor.h"
 #include "foreign/foreign.h"
 #include "miscadmin.h"
@@ -8902,12 +8903,21 @@ copy_relation_data(SMgrRelation src, SMgrRelation dst,
 
                smgrread(src, forkNum, blkno, buf);
 
-               PageSetChecksumInplace(page, blkno);
+               if (!PageIsVerified(page, blkno))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_DATA_CORRUPTED),
+                                        errmsg("invalid page in block %u of relation %s",
+                                                       blkno,
+                                                       relpathbackend(src->smgr_rnode.node,
+                                                                                  src->smgr_rnode.backend,
+                                                                                  forkNum))));
 
                /* XLOG stuff */
                if (use_wal)
                        log_newpage(&dst->smgr_rnode.node, forkNum, blkno, page);
 
+               PageSetChecksumInplace(page, blkno);
+
                /*
                 * Now write the page.  We say isTemp = true even if it's not a temp
                 * rel, because there's no need for smgr to schedule an fsync for this