Index: third_party/sqlite/src/tool/spaceanal.tcl |
diff --git a/third_party/sqlite/src/tool/spaceanal.tcl b/third_party/sqlite/src/tool/spaceanal.tcl |
index 38d954162e438f86b9505dd602ad478e41549a4b..e7ce846f865b780d57dc79502674f9e45a289ce7 100644 |
--- a/third_party/sqlite/src/tool/spaceanal.tcl |
+++ b/third_party/sqlite/src/tool/spaceanal.tcl |
@@ -22,6 +22,33 @@ proc is_without_rowid {tname} { |
return 0 |
} |
+# Read and run TCL commands from standard input. Used to implement |
+# the --tclsh option. |
+# |
+proc tclsh {} { |
+ set line {} |
+ while {![eof stdin]} { |
+ if {$line!=""} { |
+ puts -nonewline "> " |
+ } else { |
+ puts -nonewline "% " |
+ } |
+ flush stdout |
+ append line [gets stdin] |
+ if {[info complete $line]} { |
+ if {[catch {uplevel #0 $line} result]} { |
+ puts stderr "Error: $result" |
+ } elseif {$result!=""} { |
+ puts $result |
+ } |
+ set line {} |
+ } else { |
+ append line \n |
+ } |
+ } |
+} |
+ |
+ |
# Get the name of the database to analyze |
# |
proc usage {} { |
@@ -34,22 +61,37 @@ information for the database and its constituent tables and indexes. |
Options: |
- --stats Output SQL text that creates a new database containing |
- statistics about the database that was analyzed |
+ --pageinfo Show how each page of the database-file is used |
+ |
+ --stats Output SQL text that creates a new database containing |
+ statistics about the database that was analyzed |
+ |
+ --tclsh Run the built-in TCL interpreter interactively (for debugging) |
- --pageinfo Show how each page of the database-file is used |
+ --version Show the version number of SQLite |
} |
exit 1 |
} |
set file_to_analyze {} |
set flags(-pageinfo) 0 |
set flags(-stats) 0 |
+set flags(-debug) 0 |
append argv {} |
foreach arg $argv { |
if {[regexp {^-+pageinfo$} $arg]} { |
set flags(-pageinfo) 1 |
} elseif {[regexp {^-+stats$} $arg]} { |
set flags(-stats) 1 |
+ } elseif {[regexp {^-+debug$} $arg]} { |
+ set flags(-debug) 1 |
+ } elseif {[regexp {^-+tclsh$} $arg]} { |
+ tclsh |
+ exit 0 |
+ } elseif {[regexp {^-+version$} $arg]} { |
+ sqlite3 mem :memory: |
+ puts [mem one {SELECT sqlite_version()||' '||sqlite_source_id()}] |
+ mem close |
+ exit 0 |
} elseif {[regexp {^-} $arg]} { |
puts stderr "Unknown option: $arg" |
usage |
@@ -100,6 +142,10 @@ if {[catch {sqlite3 db $file_to_analyze -uri 1} msg]} { |
puts stderr "error trying to open $file_to_analyze: $msg" |
exit 1 |
} |
+if {$flags(-debug)} { |
+ proc dbtrace {txt} {puts $txt; flush stdout;} |
+ db trace ::dbtrace |
+} |
db eval {SELECT count(*) FROM sqlite_master} |
set pageSize [expr {wide([db one {PRAGMA page_size}])}] |
@@ -142,16 +188,22 @@ if {$flags(-stats)} { |
exit 0 |
} |
+ |
# In-memory database for collecting statistics. This script loops through |
# the tables and indices in the database being analyzed, adding a row for each |
# to an in-memory database (for which the schema is shown below). It then |
# queries the in-memory db to produce the space-analysis report. |
# |
sqlite3 mem :memory: |
+if {$flags(-debug)} { |
+ proc dbtrace {txt} {puts $txt; flush stdout;} |
+ mem trace ::dbtrace |
+} |
set tabledef {CREATE TABLE space_used( |
name clob, -- Name of a table or index in the database file |
tblname clob, -- Name of associated table |
is_index boolean, -- TRUE if it is an index, false for a table |
+ is_without_rowid boolean, -- TRUE if WITHOUT ROWID table |
nentry int, -- Number of entries in the BTree |
leaf_entries int, -- Number of leaf entries |
depth int, -- Depth of the b-tree |
@@ -184,7 +236,7 @@ set sql { SELECT name, tbl_name FROM sqlite_master WHERE rootpage>0 } |
foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] { |
set is_index [expr {$name!=$tblname}] |
- set idx_btree [expr {$is_index || [is_without_rowid $name]}] |
+ set is_without_rowid [is_without_rowid $name] |
db eval { |
SELECT |
sum(ncell) AS nentry, |
@@ -235,6 +287,7 @@ foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] { |
$name, |
$tblname, |
$is_index, |
+ $is_without_rowid, |
$nentry, |
$leaf_entries, |
$depth, |
@@ -330,12 +383,15 @@ proc subreport {title where showFrag} { |
# following query returns exactly one row (because it is an aggregate). |
# |
# The results of the query are stored directly by SQLite into local |
- # variables (i.e. $nentry, $nleaf etc.). |
+ # variables (i.e. $nentry, $payload etc.). |
# |
mem eval " |
SELECT |
- int(sum(nentry)) AS nentry, |
- int(sum(leaf_entries)) AS nleaf, |
+ int(sum( |
+ CASE WHEN (is_without_rowid OR is_index) THEN nentry |
+ ELSE leaf_entries |
+ END |
+ )) AS nentry, |
int(sum(payload)) AS payload, |
int(sum(ovfl_payload)) AS ovfl_payload, |
max(mx_payload) AS mx_payload, |
@@ -375,8 +431,8 @@ proc subreport {title where showFrag} { |
set storage [expr {$total_pages*$pageSize}] |
set payload_percent [percent $payload $storage {of storage consumed}] |
set total_unused [expr {$ovfl_unused+$int_unused+$leaf_unused}] |
- set avg_payload [divide $payload $nleaf] |
- set avg_unused [divide $total_unused $nleaf] |
+ set avg_payload [divide $payload $nentry] |
+ set avg_unused [divide $total_unused $nentry] |
if {$int_pages>0} { |
# TODO: Is this formula correct? |
set nTab [mem eval " |
@@ -390,12 +446,12 @@ proc subreport {title where showFrag} { |
"] |
set avg_fanout [format %.2f $avg_fanout] |
} |
- set ovfl_cnt_percent [percent $ovfl_cnt $nleaf {of all entries}] |
+ set ovfl_cnt_percent [percent $ovfl_cnt $nentry {of all entries}] |
# Print out the sub-report statistics. |
# |
statline {Percentage of total database} $total_pages_percent |
- statline {Number of entries} $nleaf |
+ statline {Number of entries} $nentry |
statline {Bytes of storage consumed} $storage |
if {$compressed_size!=$storage} { |
set compressed_size [expr {$compressed_size+$compressOverhead*$total_pages}] |