1ebaecc14Sdanielk1977# 2008 Feb 19 2ebaecc14Sdanielk1977# 3ebaecc14Sdanielk1977# The author disclaims copyright to this source code. In place of 4ebaecc14Sdanielk1977# a legal notice, here is a blessing: 5ebaecc14Sdanielk1977# 6ebaecc14Sdanielk1977# May you do good and not evil. 7ebaecc14Sdanielk1977# May you find forgiveness for yourself and forgive others. 8ebaecc14Sdanielk1977# May you share freely, never taking more than you give. 9ebaecc14Sdanielk1977# 10ebaecc14Sdanielk1977#*********************************************************************** 11ebaecc14Sdanielk1977# 12ebaecc14Sdanielk1977# This file contains Tcl code that may be useful for testing or 13ebaecc14Sdanielk1977# analyzing r-tree structures created with this module. It is 14ebaecc14Sdanielk1977# used by both test procedures and the r-tree viewer application. 15ebaecc14Sdanielk1977# 16ebaecc14Sdanielk1977 17ebaecc14Sdanielk1977 18ebaecc14Sdanielk1977#-------------------------------------------------------------------------- 19ebaecc14Sdanielk1977# PUBLIC API: 20ebaecc14Sdanielk1977# 21ebaecc14Sdanielk1977# rtree_depth 22ebaecc14Sdanielk1977# rtree_ndim 23ebaecc14Sdanielk1977# rtree_node 24ebaecc14Sdanielk1977# rtree_mincells 25ebaecc14Sdanielk1977# rtree_check 26ebaecc14Sdanielk1977# rtree_dump 27ebaecc14Sdanielk1977# rtree_treedump 28ebaecc14Sdanielk1977# 29ebaecc14Sdanielk1977 30ebaecc14Sdanielk1977proc rtree_depth {db zTab} { 31ebaecc14Sdanielk1977 $db one "SELECT rtreedepth(data) FROM ${zTab}_node WHERE nodeno=1" 32ebaecc14Sdanielk1977} 33ebaecc14Sdanielk1977 34ebaecc14Sdanielk1977proc rtree_nodedepth {db zTab iNode} { 35ebaecc14Sdanielk1977 set iDepth [rtree_depth $db $zTab] 36ebaecc14Sdanielk1977 37ebaecc14Sdanielk1977 set ii $iNode 38ebaecc14Sdanielk1977 while {$ii != 1} { 39ebaecc14Sdanielk1977 set sql "SELECT parentnode FROM ${zTab}_parent WHERE nodeno = $ii" 40ebaecc14Sdanielk1977 set ii [db one $sql] 41ebaecc14Sdanielk1977 incr iDepth -1 42ebaecc14Sdanielk1977 } 43ebaecc14Sdanielk1977 44ebaecc14Sdanielk1977 return $iDepth 45ebaecc14Sdanielk1977} 46ebaecc14Sdanielk1977 47ebaecc14Sdanielk1977# Return the number of dimensions of the rtree. 48ebaecc14Sdanielk1977# 49ebaecc14Sdanielk1977proc rtree_ndim {db zTab} { 50ebaecc14Sdanielk1977 set nDim [expr {(([llength [$db eval "pragma table_info($zTab)"]]/6)-1)/2}] 51ebaecc14Sdanielk1977} 52ebaecc14Sdanielk1977 53ebaecc14Sdanielk1977# Return the contents of rtree node $iNode. 54ebaecc14Sdanielk1977# 55ebaecc14Sdanielk1977proc rtree_node {db zTab iNode {iPrec 6}} { 56ebaecc14Sdanielk1977 set nDim [rtree_ndim $db $zTab] 57ebaecc14Sdanielk1977 set sql " 58ebaecc14Sdanielk1977 SELECT rtreenode($nDim, data) FROM ${zTab}_node WHERE nodeno = $iNode 59ebaecc14Sdanielk1977 " 60ebaecc14Sdanielk1977 set node [db one $sql] 61ebaecc14Sdanielk1977 62ebaecc14Sdanielk1977 set nCell [llength $node] 63ebaecc14Sdanielk1977 set nCoord [expr $nDim*2] 64ebaecc14Sdanielk1977 for {set ii 0} {$ii < $nCell} {incr ii} { 65ebaecc14Sdanielk1977 for {set jj 1} {$jj <= $nCoord} {incr jj} { 66ebaecc14Sdanielk1977 set newval [format "%.${iPrec}f" [lindex $node $ii $jj]] 67ebaecc14Sdanielk1977 lset node $ii $jj $newval 68ebaecc14Sdanielk1977 } 69ebaecc14Sdanielk1977 } 70ebaecc14Sdanielk1977 set node 71ebaecc14Sdanielk1977} 72ebaecc14Sdanielk1977 73ebaecc14Sdanielk1977proc rtree_mincells {db zTab} { 74ebaecc14Sdanielk1977 set n [$db one "select length(data) FROM ${zTab}_node LIMIT 1"] 75ebaecc14Sdanielk1977 set nMax [expr {int(($n-4)/(8+[rtree_ndim $db $zTab]*2*4))}] 76ebaecc14Sdanielk1977 return [expr {int($nMax/3)}] 77ebaecc14Sdanielk1977} 78ebaecc14Sdanielk1977 79ebaecc14Sdanielk1977# An integrity check for the rtree $zTab accessible via database 80ebaecc14Sdanielk1977# connection $db. 81ebaecc14Sdanielk1977# 82ebaecc14Sdanielk1977proc rtree_check {db zTab} { 83ebaecc14Sdanielk1977 array unset ::checked 84ebaecc14Sdanielk1977 85ebaecc14Sdanielk1977 # Check each r-tree node. 86ebaecc14Sdanielk1977 set rc [catch { 87ebaecc14Sdanielk1977 rtree_node_check $db $zTab 1 [rtree_depth $db $zTab] 88ebaecc14Sdanielk1977 } msg] 89ebaecc14Sdanielk1977 if {$rc && $msg ne ""} { error $msg } 90ebaecc14Sdanielk1977 91ebaecc14Sdanielk1977 # Check that the _rowid and _parent tables have the right 92ebaecc14Sdanielk1977 # number of entries. 93ebaecc14Sdanielk1977 set nNode [$db one "SELECT count(*) FROM ${zTab}_node"] 94ebaecc14Sdanielk1977 set nRow [$db one "SELECT count(*) FROM ${zTab}"] 95ebaecc14Sdanielk1977 set nRowid [$db one "SELECT count(*) FROM ${zTab}_rowid"] 96ebaecc14Sdanielk1977 set nParent [$db one "SELECT count(*) FROM ${zTab}_parent"] 97ebaecc14Sdanielk1977 98ebaecc14Sdanielk1977 if {$nNode != ($nParent+1)} { 99ebaecc14Sdanielk1977 error "Wrong number of entries in ${zTab}_parent" 100ebaecc14Sdanielk1977 } 101ebaecc14Sdanielk1977 if {$nRow != $nRowid} { 102ebaecc14Sdanielk1977 error "Wrong number of entries in ${zTab}_rowid" 103ebaecc14Sdanielk1977 } 104ebaecc14Sdanielk1977 105ebaecc14Sdanielk1977 return $rc 106ebaecc14Sdanielk1977} 107ebaecc14Sdanielk1977 108ebaecc14Sdanielk1977proc rtree_node_check {db zTab iNode iDepth} { 109ebaecc14Sdanielk1977 if {[info exists ::checked($iNode)]} { error "Second ref to $iNode" } 110ebaecc14Sdanielk1977 set ::checked($iNode) 1 111ebaecc14Sdanielk1977 112ebaecc14Sdanielk1977 set node [rtree_node $db $zTab $iNode] 113ebaecc14Sdanielk1977 if {$iNode!=1 && [llength $node]==0} { error "No such node: $iNode" } 114ebaecc14Sdanielk1977 115ebaecc14Sdanielk1977 if {$iNode != 1 && [llength $node]<[rtree_mincells $db $zTab]} { 116ebaecc14Sdanielk1977 puts "Node $iNode: Has only [llength $node] cells" 117ebaecc14Sdanielk1977 error "" 118ebaecc14Sdanielk1977 } 119ebaecc14Sdanielk1977 if {$iNode == 1 && [llength $node]==1 && [rtree_depth $db $zTab]>0} { 120ebaecc14Sdanielk1977 set depth [rtree_depth $db $zTab] 121ebaecc14Sdanielk1977 puts "Node $iNode: Has only 1 child (tree depth is $depth)" 122ebaecc14Sdanielk1977 error "" 123ebaecc14Sdanielk1977 } 124ebaecc14Sdanielk1977 125ebaecc14Sdanielk1977 set nDim [expr {([llength [lindex $node 0]]-1)/2}] 126ebaecc14Sdanielk1977 127ebaecc14Sdanielk1977 if {$iDepth > 0} { 128ebaecc14Sdanielk1977 set d [expr $iDepth-1] 129ebaecc14Sdanielk1977 foreach cell $node { 130ebaecc14Sdanielk1977 set shouldbe [rtree_node_check $db $zTab [lindex $cell 0] $d] 131ebaecc14Sdanielk1977 if {$cell ne $shouldbe} { 132ebaecc14Sdanielk1977 puts "Node $iNode: Cell is: {$cell}, should be {$shouldbe}" 133ebaecc14Sdanielk1977 error "" 134ebaecc14Sdanielk1977 } 135ebaecc14Sdanielk1977 } 136ebaecc14Sdanielk1977 } 137ebaecc14Sdanielk1977 138ebaecc14Sdanielk1977 set mapping_table "${zTab}_parent" 139ebaecc14Sdanielk1977 set mapping_sql "SELECT parentnode FROM $mapping_table WHERE rowid = \$rowid" 140ebaecc14Sdanielk1977 if {$iDepth==0} { 141ebaecc14Sdanielk1977 set mapping_table "${zTab}_rowid" 142ebaecc14Sdanielk1977 set mapping_sql "SELECT nodeno FROM $mapping_table WHERE rowid = \$rowid" 143ebaecc14Sdanielk1977 } 144ebaecc14Sdanielk1977 foreach cell $node { 145ebaecc14Sdanielk1977 set rowid [lindex $cell 0] 146ebaecc14Sdanielk1977 set mapping [db one $mapping_sql] 147ebaecc14Sdanielk1977 if {$mapping != $iNode} { 148ebaecc14Sdanielk1977 puts "Node $iNode: $mapping_table entry for cell $rowid is $mapping" 149ebaecc14Sdanielk1977 error "" 150ebaecc14Sdanielk1977 } 151ebaecc14Sdanielk1977 } 152ebaecc14Sdanielk1977 153ebaecc14Sdanielk1977 set ret [list $iNode] 154ebaecc14Sdanielk1977 for {set ii 1} {$ii <= $nDim*2} {incr ii} { 155ebaecc14Sdanielk1977 set f [lindex $node 0 $ii] 156ebaecc14Sdanielk1977 foreach cell $node { 157ebaecc14Sdanielk1977 set f2 [lindex $cell $ii] 158ebaecc14Sdanielk1977 if {($ii%2)==1 && $f2<$f} {set f $f2} 159ebaecc14Sdanielk1977 if {($ii%2)==0 && $f2>$f} {set f $f2} 160ebaecc14Sdanielk1977 } 161ebaecc14Sdanielk1977 lappend ret $f 162ebaecc14Sdanielk1977 } 163ebaecc14Sdanielk1977 return $ret 164ebaecc14Sdanielk1977} 165ebaecc14Sdanielk1977 166ebaecc14Sdanielk1977proc rtree_dump {db zTab} { 167ebaecc14Sdanielk1977 set zRet "" 168ebaecc14Sdanielk1977 set nDim [expr {(([llength [$db eval "pragma table_info($zTab)"]]/6)-1)/2}] 169ebaecc14Sdanielk1977 set sql "SELECT nodeno, rtreenode($nDim, data) AS node FROM ${zTab}_node" 170ebaecc14Sdanielk1977 $db eval $sql { 171ebaecc14Sdanielk1977 append zRet [format "% -10s %s\n" $nodeno $node] 172ebaecc14Sdanielk1977 } 173ebaecc14Sdanielk1977 set zRet 174ebaecc14Sdanielk1977} 175ebaecc14Sdanielk1977 176ebaecc14Sdanielk1977proc rtree_nodetreedump {db zTab zIndent iDepth iNode} { 177ebaecc14Sdanielk1977 set ret "" 178ebaecc14Sdanielk1977 set node [rtree_node $db $zTab $iNode 1] 179ebaecc14Sdanielk1977 append ret [format "%-3d %s%s\n" $iNode $zIndent $node] 180ebaecc14Sdanielk1977 if {$iDepth>0} { 181ebaecc14Sdanielk1977 foreach cell $node { 182ebaecc14Sdanielk1977 set i [lindex $cell 0] 183ebaecc14Sdanielk1977 append ret [rtree_nodetreedump $db $zTab "$zIndent " [expr $iDepth-1] $i] 184ebaecc14Sdanielk1977 } 185ebaecc14Sdanielk1977 } 186ebaecc14Sdanielk1977 set ret 187ebaecc14Sdanielk1977} 188ebaecc14Sdanielk1977 189ebaecc14Sdanielk1977proc rtree_treedump {db zTab} { 190ebaecc14Sdanielk1977 set d [rtree_depth $db $zTab] 191ebaecc14Sdanielk1977 rtree_nodetreedump $db $zTab "" $d 1 192ebaecc14Sdanielk1977} 193*1917e92fSdan 194*1917e92fSdanproc do_rtree_integrity_test {tn tbl} { 195*1917e92fSdan uplevel [list do_execsql_test $tn "SELECT rtreecheck('$tbl')" ok] 196*1917e92fSdan} 197*1917e92fSdan 198