1 # This TCL script is the main driver script for the sqlite3_checker utility
7 # sqlite3_checker --test FILENAME ARGS
9 # uses FILENAME in place of this script.
11 if {[lindex $argv 0]=="--test" && [llength $argv]>1} {
12 set ::argv0 [lindex $argv 1]
13 set argv
[lrange $argv 2 end
]
22 while {![eof stdin
]} {
29 append line
[gets stdin
]
30 if {[info complete
$line]} {
31 if {[catch {uplevel #0 $line} result]} {
32 puts stderr
"Error: $result"
33 } elseif
{$result!=""} {
43 # Do an incremental integrity check of a single index
45 proc check_index
{idxname batchsize bTrace
} {
50 set max
[db one
{SELECT nEntry FROM sqlite_btreeinfo
('main'
)
52 puts -nonewline "$idxname: $i of $max rows ($pct%)\r"
55 set sql
{SELECT errmsg
, current_key AS key
,
56 CASE WHEN rowid
=1 THEN scanner_sql END AS traceOut
57 FROM incremental_index_check
($idxname)
61 set sql
{SELECT errmsg
, current_key AS key
, NULL AS traceOut
62 FROM incremental_index_check
($idxname)
72 puts "$idxname: key($key): $errmsg"
73 } elseif
{$traceOut!=""} {
74 puts "$idxname: $traceOut"
79 set x
[format {%.1f
} [expr {($i*100.0)/$max}]]
81 puts -nonewline "$idxname: $i of $max rows ($pct%)\r"
86 puts "$idxname: $nerr errors out of $i entries"
89 # Print a usage message on standard error, then quit.
92 set argv0
[file rootname
[file tail
[info nameofexecutable
]]]
93 puts stderr
"Usage: $argv0 OPTIONS database-filename"
95 Do sanity checking on a live SQLite3 database
file specified by the
96 "database-filename" argument.
100 --batchsize N Number of rows to check per transaction
102 --freelist Perform a freelist check
104 --index NAME Run a check of the index NAME
106 --summary Print summary information about the database
108 --table NAME Run a check of all indexes
for table NAME
110 --tclsh Run the built-in TCL interpreter
(for debugging
)
112 --trace (Debugging only
:) Output
trace information on the
scan
114 --version Show the version number of SQLite
119 set file_to_analyze
{}
128 set argc
[llength $argv]
129 for {set i
0} {$i<$argc} {incr i
} {
130 set arg
[lindex $argv $i]
131 if {[regexp {^
-+tclsh
$} $arg]} {
135 if {[regexp {^
-+version
$} $arg]} {
137 puts [mem one
{SELECT sqlite_version
()||' '||sqlite_source_id
()}]
141 if {[regexp {^
-+freelist
$} $arg]} {
146 if {[regexp {^
-+summary
$} $arg]} {
151 if {[regexp {^
-+trace$} $arg]} {
155 if {[regexp {^
-+batchsize
$} $arg]} {
158 puts stderr
"missing argument on $arg"
161 set batchsize
[lindex $argv $i]
164 if {[regexp {^
-+index
$} $arg]} {
167 puts stderr
"missing argument on $arg"
170 set zIndex
[lindex $argv $i]
174 if {[regexp {^
-+table
$} $arg]} {
177 puts stderr
"missing argument on $arg"
180 set zTable
[lindex $argv $i]
184 if {[regexp {^
-} $arg]} {
185 puts stderr
"Unknown option: $arg"
188 if {$file_to_analyze!=""} {
191 set file_to_analyze
$arg
194 if {$file_to_analyze==""} usage
196 # If a TCL script is specified on the command-line, then run that
199 if {[file extension
$file_to_analyze]==".tcl"} {
200 source $file_to_analyze
204 set root_filename
$file_to_analyze
205 regexp {^
file:(//)?
([^?
]*)} $file_to_analyze all x1 root_filename
206 if {![file exists
$root_filename]} {
207 puts stderr
"No such file: $root_filename"
210 if {![file readable
$root_filename]} {
211 puts stderr
"File is not readable: $root_filename"
215 if {[catch {sqlite3 db
$file_to_analyze} res
]} {
216 puts stderr
"Cannot open datababase $root_filename: $res"
220 if {$bFreelistCheck ||
$bAll} {
221 puts -nonewline "freelist-check: "
224 puts [db one
{SELECT checkfreelist
('main'
)}]
229 set pgsz
[db one
{PRAGMA page_size
}]
230 db
eval {SELECT nPage
*$pgsz AS sz
, name
, tbl_name
231 FROM sqlite_btreeinfo
233 ORDER BY
1 DESC
, name
} {
243 puts [format {%7.1f
%s index
%s of table
%s
} \
244 [expr {$sz/$scale}] $unit $name $tbl_name]
248 check_index
$zIndex $batchsize $bTrace
251 foreach idx
[db
eval {SELECT name FROM sqlite_master
252 WHERE type
='index' AND rootpage
>0
253 AND tbl_name
=$zTable}] {
254 check_index
$idx $batchsize $bTrace
258 set allidx
[db
eval {SELECT name FROM sqlite_btreeinfo
('main'
)
259 WHERE type
='index' AND rootpage
>0
261 foreach idx
$allidx {
262 check_index
$idx $batchsize $bTrace