2008-05-26 18:41:54 +00:00
# 2008 Feb 19
#
# 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 contains Tcl code that may be useful for testing or
# analyzing r-tree structures created with this module. It is
# used by both test procedures and the r-tree viewer application.
#
# --------------------------------------------------------------------------
# PUBLIC API:
#
# rtree_depth
# rtree_ndim
# rtree_node
# rtree_mincells
# rtree_check
# rtree_dump
# rtree_treedump
#
proc rtree_depth { db zTab} {
$db one " S E L E C T r t r e e d e p t h ( d a t a ) F R O M $ { z T a b } _ n o d e W H E R E n o d e n o = 1 "
}
proc rtree_nodedepth { db zTab iNode} {
set iDepth [ rtree_depth $db $zTab ]
set ii $iNode
while { $ii != 1 } {
set sql " S E L E C T p a r e n t n o d e F R O M $ { z T a b } _ p a r e n t W H E R E n o d e n o = $ i i "
set ii [ db one $sql ]
incr iDepth - 1
}
return $iDepth
}
# Return the number of dimensions of the rtree.
#
proc rtree_ndim { db zTab} {
set nDim [ expr { ( ( [ llength [ $db eval " p r a g m a t a b l e _ i n f o ( $ z T a b ) " ] ] / 6 ) -1 ) / 2 } ]
}
# Return the contents of rtree node $iNode.
#
proc rtree_node { db zTab iNode { iPrec 6 } } {
set nDim [ rtree_ndim $db $zTab ]
set sql "
SELECT rtreenode( $nDim , data ) FROM $ { zTab } _node WHERE nodeno = $iNode
"
set node [ db one $sql ]
set nCell [ llength $node ]
set nCoord [ expr $nDim * 2 ]
for { set ii 0 } { $ii < $nCell } { incr ii} {
for { set jj 1 } { $jj <= $nCoord } { incr jj} {
set newval [ format " % . $ { i P r e c } f " [ lindex $node $ii $jj ] ]
lset node $ii $jj $newval
}
}
set node
}
proc rtree_mincells { db zTab} {
set n [ $db one " s e l e c t l e n g t h ( d a t a ) F R O M $ { z T a b } _ n o d e L I M I T 1 " ]
set nMax [ expr { int ( ( $n-4 ) / ( 8 + [ rtree_ndim $db $zTab ] * 2 * 4 ) ) } ]
return [ expr { int ( $nMax / 3 ) } ]
}
# An integrity check for the rtree $zTab accessible via database
# connection $db.
#
proc rtree_check { db zTab} {
array unset : : checked
# Check each r-tree node.
set rc [ catch {
rtree_node_check $db $zTab 1 [ rtree_depth $db $zTab ]
} msg ]
if { $rc && $msg ne " " } { error $msg }
# Check that the _rowid and _parent tables have the right
# number of entries.
set nNode [ $db one " S E L E C T c o u n t ( * ) F R O M $ { z T a b } _ n o d e " ]
set nRow [ $db one " S E L E C T c o u n t ( * ) F R O M $ { z T a b } " ]
set nRowid [ $db one " S E L E C T c o u n t ( * ) F R O M $ { z T a b } _ r o w i d " ]
set nParent [ $db one " S E L E C T c o u n t ( * ) F R O M $ { z T a b } _ p a r e n t " ]
if { $nNode != ( $nParent + 1 ) } {
error " W r o n g n u m b e r o f e n t r i e s i n $ { z T a b } _ p a r e n t "
}
if { $nRow != $nRowid } {
error " W r o n g n u m b e r o f e n t r i e s i n $ { z T a b } _ r o w i d "
}
return $rc
}
proc rtree_node_check { db zTab iNode iDepth} {
if { [ info exists : : checked( $iNode ) ] } { error " S e c o n d r e f t o $ i N o d e " }
set : : checked( $iNode ) 1
set node [ rtree_node $db $zTab $iNode ]
if { $iNode != 1 && [ llength $node ] == 0 } { error " N o s u c h n o d e : $ i N o d e " }
if { $iNode != 1 && [ llength $node ] < [ rtree_mincells $db $zTab ] } {
puts " N o d e $ i N o d e : H a s o n l y [ l l e n g t h $ n o d e ] c e l l s "
error " "
}
if { $iNode == 1 && [ llength $node ] == 1 && [ rtree_depth $db $zTab ] > 0 } {
set depth [ rtree_depth $db $zTab ]
puts " N o d e $ i N o d e : H a s o n l y 1 c h i l d ( t r e e d e p t h i s $ d e p t h ) "
error " "
}
set nDim [ expr { ( [ llength [ lindex $node 0 ] ] -1 ) / 2 } ]
if { $iDepth > 0 } {
set d [ expr $iDepth-1 ]
foreach cell $node {
set shouldbe [ rtree_node_check $db $zTab [ lindex $cell 0 ] $d ]
if { $cell ne $shouldbe } {
puts " N o d e $ i N o d e : C e l l i s : { $ c e l l } , s h o u l d b e { $ s h o u l d b e } "
error " "
}
}
}
set mapping_table " $ { z T a b } _ p a r e n t "
set mapping_sql " S E L E C T p a r e n t n o d e F R O M $ m a p p i n g _ t a b l e W H E R E r o w i d = \$ r o w i d "
if { $iDepth == 0 } {
set mapping_table " $ { z T a b } _ r o w i d "
set mapping_sql " S E L E C T n o d e n o F R O M $ m a p p i n g _ t a b l e W H E R E r o w i d = \$ r o w i d "
}
foreach cell $node {
set rowid [ lindex $cell 0 ]
set mapping [ db one $mapping_sql ]
if { $mapping != $iNode } {
puts " N o d e $ i N o d e : $ m a p p i n g _ t a b l e e n t r y f o r c e l l $ r o w i d i s $ m a p p i n g "
error " "
}
}
set ret [ list $iNode ]
for { set ii 1 } { $ii <= $nDim * 2 } { incr ii} {
set f [ lindex $node 0 $ii ]
foreach cell $node {
set f2 [ lindex $cell $ii ]
if { ( $ii % 2 ) == 1 && $f2 < $f } { set f $f2 }
if { ( $ii % 2 ) == 0 && $f2 > $f } { set f $f2 }
}
lappend ret $f
}
return $ret
}
proc rtree_dump { db zTab} {
set zRet " "
set nDim [ expr { ( ( [ llength [ $db eval " p r a g m a t a b l e _ i n f o ( $ z T a b ) " ] ] / 6 ) -1 ) / 2 } ]
set sql " S E L E C T n o d e n o , r t r e e n o d e ( $ n D i m , d a t a ) A S n o d e F R O M $ { z T a b } _ n o d e "
$db eval $sql {
append zRet [ format " % - 1 0 s % s \n " $nodeno $node ]
}
set zRet
}
proc rtree_nodetreedump { db zTab zIndent iDepth iNode} {
set ret " "
set node [ rtree_node $db $zTab $iNode 1 ]
append ret [ format " % - 3 d % s % s \n " $iNode $zIndent $node ]
if { $iDepth > 0 } {
foreach cell $node {
set i [ lindex $cell 0 ]
append ret [ rtree_nodetreedump $db $zTab " $ z I n d e n t " [ expr $iDepth-1 ] $i ]
}
}
set ret
}
proc rtree_treedump { db zTab} {
set d [ rtree_depth $db $zTab ]
rtree_nodetreedump $db $zTab " " $d 1
}
2017-10-25 16:38:34 +00:00
proc do_rtree_integrity_test { tn tbl} {
2023-09-06 12:52:00 +00:00
uplevel [ list do_execsql_test $tn.1 " S E L E C T r t r e e c h e c k ( ' $ t b l ' ) " ok]
uplevel [ list do_execsql_test $tn.2 " P R A G M A i n t e g r i t y _ c h e c k " ok]
2017-10-25 16:38:34 +00:00
}