15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Run this TCL script using "testfixture" in order get a report that shows 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# how much disk space is used by a particular data to actually store data 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# versus how much space is unused. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if {[catch { 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Get the name of the database to analyze 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#set argv $argv0 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if {[llength $argv]!=1} { 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts stderr "Usage: $argv0 database-name" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 1 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set file_to_analyze [lindex $argv 0] 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if {![file exists $file_to_analyze]} { 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts stderr "No such file: $file_to_analyze" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 1 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if {![file readable $file_to_analyze]} { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts stderr "File is not readable: $file_to_analyze" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 1 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if {[file size $file_to_analyze]<512} { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts stderr "Empty or malformed database: $file_to_analyze" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 1 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Open the database 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sqlite3 db [lindex $argv 0] 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)register_dbstat_vtab db 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set pageSize [db one {PRAGMA page_size}] 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#set DB [btree_open [lindex $argv 0] 1000 0] 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# In-memory database for collecting statistics. This script loops through 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the tables and indices in the database being analyzed, adding a row for each 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# to an in-memory database (for which the schema is shown below). It then 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# queries the in-memory db to produce the space-analysis report. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sqlite3 mem :memory: 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set tabledef\ 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){CREATE TABLE space_used( 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name clob, -- Name of a table or index in the database file 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tblname clob, -- Name of associated table 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_index boolean, -- TRUE if it is an index, false for a table 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nentry int, -- Number of entries in the BTree 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leaf_entries int, -- Number of leaf entries 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) payload int, -- Total amount of data stored in this table or index 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ovfl_payload int, -- Total amount of data stored on overflow pages 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ovfl_cnt int, -- Number of entries that use overflow 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mx_payload int, -- Maximum payload size 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int_pages int, -- Number of interior pages used 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leaf_pages int, -- Number of leaf pages used 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ovfl_pages int, -- Number of overflow pages used 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int_unused int, -- Number of unused bytes on interior pages 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leaf_unused int, -- Number of unused bytes on primary pages 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ovfl_unused int, -- Number of unused bytes on overflow pages 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gap_cnt int -- Number of gaps in the page layout 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles));} 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)mem eval $tabledef 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Create a temporary "dbstat" virtual table. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)db eval { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CREATE VIRTUAL TABLE temp.stat USING dbstat; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CREATE TEMP TABLE dbstat AS SELECT * FROM temp.stat ORDER BY name, path; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DROP TABLE temp.stat; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)proc isleaf {pagetype is_index} { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [expr {$pagetype == "leaf" || ($pagetype == "internal" && $is_index)}] 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)proc isoverflow {pagetype is_index} { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [expr {$pagetype == "overflow"}] 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)proc isinternal {pagetype is_index} { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [expr {$pagetype == "internal" && $is_index==0}] 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)db func isleaf isleaf 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)db func isinternal isinternal 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)db func isoverflow isoverflow 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set sql { SELECT name, tbl_name FROM sqlite_master WHERE rootpage>0 } 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set is_index [expr {$name!=$tblname}] 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db eval { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SELECT 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum(ncell) AS nentry, 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum(isleaf(pagetype, $is_index) * ncell) AS leaf_entries, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum(payload) AS payload, 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum(isoverflow(pagetype, $is_index) * payload) AS ovfl_payload, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum(path LIKE '%+000000') AS ovfl_cnt, 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max(mx_payload) AS mx_payload, 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum(isinternal(pagetype, $is_index)) AS int_pages, 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum(isleaf(pagetype, $is_index)) AS leaf_pages, 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum(isoverflow(pagetype, $is_index)) AS ovfl_pages, 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum(isinternal(pagetype, $is_index) * unused) AS int_unused, 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum(isleaf(pagetype, $is_index) * unused) AS leaf_unused, 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum(isoverflow(pagetype, $is_index) * unused) AS ovfl_unused 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM temp.dbstat WHERE name = $name 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } break 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Column 'gap_cnt' is set to the number of non-contiguous entries in the 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # list of pages visited if the b-tree structure is traversed in a top-down 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # fashion (each node visited before its child-tree is passed). Any overflow 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # chains present are traversed from start to finish before any child-tree 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # is. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set gap_cnt 0 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set pglist [db eval { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SELECT pageno FROM temp.dbstat WHERE name = $name ORDER BY rowid 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }] 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set prev [lindex $pglist 0] 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) foreach pgno [lrange $pglist 1 end] { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {$pgno != $prev+1} {incr gap_cnt} 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set prev $pgno 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mem eval { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSERT INTO space_used VALUES( 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $name, 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $tblname, 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $is_index, 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $nentry, 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $leaf_entries, 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $payload, 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $ovfl_payload, 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $ovfl_cnt, 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $mx_payload, 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $int_pages, 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $leaf_pages, 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $ovfl_pages, 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $int_unused, 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $leaf_unused, 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $ovfl_unused, 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $gap_cnt 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)proc integerify {real} { 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {[string is double -strict $real]} { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [expr {int($real)}] 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)mem function int integerify 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Quote a string for use in an SQL query. Examples: 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# [quote {hello world}] == {'hello world'} 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# [quote {hello world's}] == {'hello world''s'} 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)proc quote {txt} { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) regsub -all ' $txt '' q 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return '$q' 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Generate a single line of output in the statistics section of the 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# report. 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)proc statline {title value {extra {}}} { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set len [string length $title] 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set dots [string range {......................................} $len end] 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set len [string length $value] 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set sp2 [string range { } $len end] 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {$extra ne ""} { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set extra " $extra" 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts "$title$dots $value$sp2$extra" 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Generate a formatted percentage value for $num/$denom 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)proc percent {num denom {of {}}} { 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {$denom==0.0} {return ""} 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set v [expr {$num*100.0/$denom}] 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set of {} 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {$v==100.0 || $v<0.001 || ($v>1.0 && $v<99.0)} { 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [format {%5.1f%% %s} $v $of] 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } elseif {$v<0.1 || $v>99.9} { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [format {%7.3f%% %s} $v $of] 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [format {%6.2f%% %s} $v $of] 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)proc divide {num denom} { 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {$denom==0} {return 0.0} 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [format %.2f [expr double($num)/double($denom)]] 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Generate a subreport that covers some subset of the database. 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the $where clause determines which subset to analyze. 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)proc subreport {title where} { 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) global pageSize file_pgcnt 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Query the in-memory database for the sum of various statistics 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # for the subset of tables/indices identified by the WHERE clause in 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # $where. Note that even if the WHERE clause matches no rows, the 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # following query returns exactly one row (because it is an aggregate). 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The results of the query are stored directly by SQLite into local 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # variables (i.e. $nentry, $nleaf etc.). 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mem eval " 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SELECT 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(sum(nentry)) AS nentry, 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(sum(leaf_entries)) AS nleaf, 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(sum(payload)) AS payload, 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(sum(ovfl_payload)) AS ovfl_payload, 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max(mx_payload) AS mx_payload, 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(sum(ovfl_cnt)) as ovfl_cnt, 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(sum(leaf_pages)) AS leaf_pages, 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(sum(int_pages)) AS int_pages, 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(sum(ovfl_pages)) AS ovfl_pages, 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(sum(leaf_unused)) AS leaf_unused, 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(sum(int_unused)) AS int_unused, 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(sum(ovfl_unused)) AS ovfl_unused, 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(sum(gap_cnt)) AS gap_cnt 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM space_used WHERE $where" {} {} 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Output the sub-report title, nicely decorated with * characters. 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts "" 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set len [string length $title] 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set stars [string repeat * [expr 65-$len]] 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts "*** $title $stars" 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts "" 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Calculate statistics and store the results in TCL variables, as follows: 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # total_pages: Database pages consumed. 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # total_pages_percent: Pages consumed as a percentage of the file. 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # storage: Bytes consumed. 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # payload_percent: Payload bytes used as a percentage of $storage. 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # total_unused: Unused bytes on pages. 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # avg_payload: Average payload per btree entry. 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # avg_fanout: Average fanout for internal pages. 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # avg_unused: Average unused bytes per btree entry. 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # ovfl_cnt_percent: Percentage of btree entries that use overflow pages. 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set total_pages [expr {$leaf_pages+$int_pages+$ovfl_pages}] 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set total_pages_percent [percent $total_pages $file_pgcnt] 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set storage [expr {$total_pages*$pageSize}] 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set payload_percent [percent $payload $storage {of storage consumed}] 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set total_unused [expr {$ovfl_unused+$int_unused+$leaf_unused}] 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set avg_payload [divide $payload $nleaf] 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set avg_unused [divide $total_unused $nleaf] 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {$int_pages>0} { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # TODO: Is this formula correct? 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set nTab [mem eval " 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SELECT count(*) FROM ( 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SELECT DISTINCT tblname FROM space_used WHERE $where AND is_index=0 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "] 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set avg_fanout [mem eval " 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SELECT (sum(leaf_pages+int_pages)-$nTab)/sum(int_pages) FROM space_used 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WHERE $where AND is_index = 0 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "] 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set avg_fanout [format %.2f $avg_fanout] 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set ovfl_cnt_percent [percent $ovfl_cnt $nleaf {of all entries}] 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Print out the sub-report statistics. 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Percentage of total database} $total_pages_percent 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Number of entries} $nleaf 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Bytes of storage consumed} $storage 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Bytes of payload} $payload $payload_percent 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Average payload per entry} $avg_payload 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Average unused bytes per entry} $avg_unused 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {[info exists avg_fanout]} { 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Average fanout} $avg_fanout 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {$total_pages>1} { 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set fragmentation [percent $gap_cnt [expr {$total_pages-1}] {fragmentation}] 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Fragmentation} $fragmentation 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Maximum payload per entry} $mx_payload 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Entries that use overflow} $ovfl_cnt $ovfl_cnt_percent 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {$int_pages>0} { 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Index pages used} $int_pages 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Primary pages used} $leaf_pages 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Overflow pages used} $ovfl_pages 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline {Total pages used} $total_pages 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {$int_unused>0} { 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set int_unused_percent \ 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) [percent $int_unused [expr {$int_pages*$pageSize}] {of index space}] 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline "Unused bytes on index pages" $int_unused $int_unused_percent 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline "Unused bytes on primary pages" $leaf_unused \ 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) [percent $leaf_unused [expr {$leaf_pages*$pageSize}] {of primary space}] 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline "Unused bytes on overflow pages" $ovfl_unused \ 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) [percent $ovfl_unused [expr {$ovfl_pages*$pageSize}] {of overflow space}] 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline "Unused bytes on all pages" $total_unused \ 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) [percent $total_unused $storage {of all space}] 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Calculate the overhead in pages caused by auto-vacuum. 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This procedure calculates and returns the number of pages used by the 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# auto-vacuum 'pointer-map'. If the database does not support auto-vacuum, 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# then 0 is returned. The two arguments are the size of the database file in 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# pages and the page size used by the database (in bytes). 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)proc autovacuum_overhead {filePages pageSize} { 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Set $autovacuum to non-zero for databases that support auto-vacuum. 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set autovacuum [db one {PRAGMA auto_vacuum}] 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If the database is not an auto-vacuum database or the file consists 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # of one page only then there is no overhead for auto-vacuum. Return zero. 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {0==$autovacuum || $filePages==1} { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The number of entries on each pointer map page. The layout of the 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # database file is one pointer-map page, followed by $ptrsPerPage other 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # pages, followed by a pointer-map page etc. The first pointer-map page 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # is the second page of the file overall. 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set ptrsPerPage [expr double($pageSize/5)] 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Return the number of pointer map pages in the database. 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [expr int(ceil( ($filePages-1.0)/($ptrsPerPage+1.0) ))] 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Calculate the summary statistics for the database and store the results 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# in TCL variables. They are output below. Variables are as follows: 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# pageSize: Size of each page in bytes. 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# file_bytes: File size in bytes. 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# file_pgcnt: Number of pages in the file. 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# file_pgcnt2: Number of pages in the file (calculated). 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# av_pgcnt: Pages consumed by the auto-vacuum pointer-map. 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# av_percent: Percentage of the file consumed by auto-vacuum pointer-map. 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# inuse_pgcnt: Data pages in the file. 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# inuse_percent: Percentage of pages used to store data. 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# free_pgcnt: Free pages calculated as (<total pages> - <in-use pages>) 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# free_pgcnt2: Free pages in the file according to the file header. 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# free_percent: Percentage of file consumed by free pages (calculated). 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# free_percent2: Percentage of file consumed by free pages (header). 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# ntable: Number of tables in the db. 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# nindex: Number of indices in the db. 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# nautoindex: Number of indices created automatically. 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# nmanindex: Number of indices created manually. 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# user_payload: Number of bytes of payload in table btrees 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# (not including sqlite_master) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# user_percent: $user_payload as a percentage of total file size. 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set file_bytes [file size $file_to_analyze] 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set file_pgcnt [expr {$file_bytes/$pageSize}] 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set av_pgcnt [autovacuum_overhead $file_pgcnt $pageSize] 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set av_percent [percent $av_pgcnt $file_pgcnt] 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set sql {SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM space_used} 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set inuse_pgcnt [expr int([mem eval $sql])] 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set inuse_percent [percent $inuse_pgcnt $file_pgcnt] 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set free_pgcnt [expr $file_pgcnt-$inuse_pgcnt-$av_pgcnt] 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set free_percent [percent $free_pgcnt $file_pgcnt] 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set free_pgcnt2 [db one {PRAGMA freelist_count}] 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set free_percent2 [percent $free_pgcnt2 $file_pgcnt] 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set file_pgcnt2 [expr {$inuse_pgcnt+$free_pgcnt2+$av_pgcnt}] 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set ntable [db eval {SELECT count(*)+1 FROM sqlite_master WHERE type='table'}] 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set nindex [db eval {SELECT count(*) FROM sqlite_master WHERE type='index'}] 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set sql {SELECT count(*) FROM sqlite_master WHERE name LIKE 'sqlite_autoindex%'} 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set nautoindex [db eval $sql] 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set nmanindex [expr {$nindex-$nautoindex}] 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# set total_payload [mem eval "SELECT sum(payload) FROM space_used"] 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set user_payload [mem one {SELECT int(sum(payload)) FROM space_used 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WHERE NOT is_index AND name NOT LIKE 'sqlite_master'}] 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set user_percent [percent $user_payload $file_bytes] 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Output the summary statistics calculated above. 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts "/** Disk-Space Utilization Report For $file_to_analyze" 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)catch { 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts "*** As of [clock format [clock seconds] -format {%Y-%b-%d %H:%M:%S}]" 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts "" 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)statline {Page size in bytes} $pageSize 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)statline {Pages in the whole file (measured)} $file_pgcnt 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)statline {Pages in the whole file (calculated)} $file_pgcnt2 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)statline {Pages that store data} $inuse_pgcnt $inuse_percent 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)statline {Pages on the freelist (per header)} $free_pgcnt2 $free_percent2 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)statline {Pages on the freelist (calculated)} $free_pgcnt $free_percent 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)statline {Pages of auto-vacuum overhead} $av_pgcnt $av_percent 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)statline {Number of tables in the database} $ntable 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)statline {Number of indices} $nindex 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)statline {Number of named indices} $nmanindex 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)statline {Automatically generated indices} $nautoindex 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)statline {Size of the file in bytes} $file_bytes 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)statline {Bytes of user payload stored} $user_payload $user_percent 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Output table rankings 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts "" 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts "*** Page counts for all tables with their indices ********************" 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts "" 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)mem eval {SELECT tblname, count(*) AS cnt, 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(sum(int_pages+leaf_pages+ovfl_pages)) AS size 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM space_used GROUP BY tblname ORDER BY size+0 DESC, tblname} {} { 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statline [string toupper $tblname] $size [percent $size $file_pgcnt] 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Output subreports 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if {$nindex>0} { 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subreport {All tables and indices} 1 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)subreport {All tables} {NOT is_index} 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if {$nindex>0} { 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subreport {All indices} {is_index} 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)foreach tbl [mem eval {SELECT name FROM space_used WHERE NOT is_index 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ORDER BY name}] { 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) regsub ' $tbl '' qn 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set name [string toupper $tbl] 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set n [mem eval "SELECT count(*) FROM space_used WHERE tblname='$qn'"] 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {$n>1} { 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subreport "Table $name and all its indices" "tblname='$qn'" 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subreport "Table $name w/o any indices" "name='$qn'" 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subreport "Indices of table $name" "tblname='$qn' AND is_index" 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subreport "Table $name" "name='$qn'" 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Output instructions on what the numbers above mean. 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts { 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*** Definitions ****************************************************** 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Page size in bytes 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The number of bytes in a single page of the database file. 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Usually 1024. 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Number of pages in the whole file 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts \ 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)" The number of $pageSize-byte pages that go into forming the complete 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) database" 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts \ 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Pages that store data 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The number of pages that store data, either as primary B*Tree pages or 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) as overflow pages. The number at the right is the data pages divided by 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the total number of pages in the file. 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Pages on the freelist 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The number of pages that are not currently in use but are reserved for 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) future use. The percentage at the right is the number of freelist pages 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) divided by the total number of pages in the file. 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Pages of auto-vacuum overhead 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The number of pages that store data used by the database to facilitate 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auto-vacuum. This is zero for databases that do not support auto-vacuum. 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Number of tables in the database 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The number of tables in the database, including the SQLITE_MASTER table 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) used to store schema information. 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Number of indices 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The total number of indices in the database. 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Number of named indices 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The number of indices created using an explicit CREATE INDEX statement. 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Automatically generated indices 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The number of indices used to implement PRIMARY KEY or UNIQUE constraints 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) on tables. 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Size of the file in bytes 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The total amount of disk space used by the entire database files. 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Bytes of user payload stored 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The total number of bytes of user payload stored in the database. The 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) schema information in the SQLITE_MASTER table is not counted when 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) computing this number. The percentage at the right shows the payload 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) divided by the total file size. 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Percentage of total database 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The amount of the complete database file that is devoted to storing 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) information described by this category. 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Number of entries 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The total number of B-Tree key/value pairs stored under this category. 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Bytes of storage consumed 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The total amount of disk space required to store all B-Tree entries 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) under this category. The is the total number of pages used times 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the pages size. 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Bytes of payload 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The amount of payload stored under this category. Payload is the data 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) part of table entries and the key part of index entries. The percentage 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) at the right is the bytes of payload divided by the bytes of storage 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) consumed. 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Average payload per entry 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The average amount of payload on each entry. This is just the bytes of 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) payload divided by the number of entries. 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Average unused bytes per entry 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The average amount of free space remaining on all pages under this 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) category on a per-entry basis. This is the number of unused bytes on 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all pages divided by the number of entries. 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Fragmentation 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The percentage of pages in the table or index that are not 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) consecutive in the disk file. Many filesystems are optimized 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for sequential file access so smaller fragmentation numbers 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sometimes result in faster queries, especially for larger 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) database files that do not fit in the disk cache. 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Maximum payload per entry 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The largest payload size of any entry. 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Entries that use overflow 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The number of entries that user one or more overflow pages. 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Total pages used 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This is the number of pages used to hold all information in the current 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) category. This is the sum of index, primary, and overflow pages. 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Index pages used 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This is the number of pages in a table B-tree that hold only key (rowid) 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) information and no data. 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Primary pages used 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This is the number of B-tree pages that hold both key and data. 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Overflow pages used 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The total number of overflow pages used for this category. 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Unused bytes on index pages 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The total number of bytes of unused space on all index pages. The 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) percentage at the right is the number of unused bytes divided by the 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) total number of bytes on index pages. 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Unused bytes on primary pages 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The total number of bytes of unused space on all primary pages. The 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) percentage at the right is the number of unused bytes divided by the 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) total number of bytes on primary pages. 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Unused bytes on overflow pages 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The total number of bytes of unused space on all overflow pages. The 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) percentage at the right is the number of unused bytes divided by the 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) total number of bytes on overflow pages. 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Unused bytes on all pages 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The total number of bytes of unused space on all primary and overflow 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pages. The percentage at the right is the number of unused bytes 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) divided by the total number of bytes. 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Output a dump of the in-memory database. This can be used for more 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# complex offline analysis. 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts "**********************************************************************" 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts "The entire text of this report can be sourced into any SQL database" 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts "engine for further analysis. All of the text above is an SQL comment." 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts "The data used to generate this report follows:" 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts "*/" 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts "BEGIN;" 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts $tabledef 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unset -nocomplain x 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)mem eval {SELECT * FROM space_used} x { 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts -nonewline "INSERT INTO space_used VALUES" 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set sep ( 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) foreach col $x(*) { 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set v $x($col) 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if {$v=="" || ![string is double $v]} {set v [quote $v]} 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts -nonewline $sep$v 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set sep , 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts ");" 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)puts "COMMIT;" 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} err]} { 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts "ERROR: $err" 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) puts $errorInfo 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 1 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 627