d61fa23290
FossilOrigin-Name: b97aca1200d959a1e7c08dd4e9dbce4724342119
117 lines
2.9 KiB
Tcl
117 lines
2.9 KiB
Tcl
# 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
|