# 2010 January 7
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements utility functions for SQLite library.
#
# This file attempts to restore the header of a journal.
# This may be useful for rolling-back the last committed
# transaction from a recovered journal.
#
# $Id: restore_jrnl.tcl,v 1.14 2009/07/11 06:55:34 danielk1977 Exp $
package require sqlite3
if { $argc != 2 } {
puts "USAGE: restore_jrnl.tcl db_name jrnl_name"
puts "Example: restore_jrnl.tcl foo.sqlite foo.sqlite-journal"
return
} else {
set db_name [lindex $argv 0]
set jrnl_name [lindex $argv 1]
}
# is there a way to determine this?
set sectsz 512
# Copy file $from into $to
#
proc copy_file {from to} {
file copy -force $from $to
}
# Execute some SQL
#
proc catchsql {sql} {
set rc [catch {uplevel [list db eval $sql]} msg]
list $rc $msg
}
# Perform a test
#
proc do_test {name cmd expected} {
puts -nonewline "$name ..."
set res [uplevel $cmd]
if {$res eq $expected} {
puts Ok
} else {
puts Error
puts " Got: $res"
puts " Expected: $expected"
}
}
# Setup for the tests. Make a backup copy of the files.
#
if [file exist $db_name.org] {
puts "ERROR: during back-up: $db_name.org exists already."
return;
}
if [file exist $jrnl_name.org] {
puts "ERROR: during back-up: $jrnl_name.org exists already."
return
}
copy_file $db_name $db_name.org
copy_file $jrnl_name $jrnl_name.org
set db_fsize [file size $db_name]
sqlite3 db $db_name
set db_pgsz [db eval {PRAGMA page_size}]
db close
set db_npage [expr {$db_fsize / $db_pgsz}]
# restore in case get the page_size above changed things
copy_file $db_name.org $db_name
copy_file $jrnl_name.org $jrnl_name
# calculate checksum nonce
set pgno 0
set pg_offset [expr $sectsz+((4+$db_pgsz+4)*$pgno)]
set nonce [hexio_get_int [hexio_read $jrnl_name [expr $pg_offset+4+$db_pgsz] 4]]
for {set i [expr $db_pgsz-200]} {$i>0} {set i [expr $i-200]} {
set byte [hexio_get_int [hexio_read $jrnl_name [expr $pg_offset+4+$i] 1]]
set nonce [expr $nonce-$byte]
}
# write the 8 byte magic string
hexio_write $jrnl_name 0 d9d505f920a163d7
# write -1 for number of records
hexio_write $jrnl_name 8 ffffffff
# write 00 for checksum nonce
hexio_write $jrnl_name 12 [format %08x $nonce]
# write page count
hexio_write $jrnl_name 16 [format %08x $db_npage]
# write sector size
hexio_write $jrnl_name 20 [format %08x $sectsz]
# write page size
hexio_write $jrnl_name 24 [format %08x $db_pgsz]
# check the integrity of the database.
sqlite3 db $db_name
do_test restore_jrnl-1.0 {
catchsql {PRAGMA integrity_check}
} {0 ok}
db close