192e01aafSdan# 2010 February 16 292e01aafSdan# 392e01aafSdan# The author disclaims copyright to this source code. In place of 492e01aafSdan# a legal notice, here is a blessing: 592e01aafSdan# 692e01aafSdan# May you do good and not evil. 792e01aafSdan# May you find forgiveness for yourself and forgive others. 892e01aafSdan# May you share freely, never taking more than you give. 992e01aafSdan# 1092e01aafSdan#*********************************************************************** 1192e01aafSdan# 1292e01aafSdan# 1392e01aafSdan 1492e01aafSdanif {![info exists testdir]} { 15897230ebSdan set testdir [file join [file dirname [info script]] .. .. test] 1692e01aafSdan} 171917e92fSdansource [file join [file dirname [info script]] rtree_util.tcl] 1892e01aafSdansource $testdir/tester.tcl 1992e01aafSdanifcapable !rtree { finish_test ; return } 2092e01aafSdan 2192e01aafSdan#------------------------------------------------------------------------- 2292e01aafSdan# The following block of tests - rtree8-1.* - feature reading and writing 2392e01aafSdan# an r-tree table while there exist open cursors on it. 2492e01aafSdan# 2592e01aafSdanproc populate_t1 {n} { 2692e01aafSdan execsql { DELETE FROM t1 } 2792e01aafSdan for {set i 1} {$i <= $n} {incr i} { 2892e01aafSdan execsql { INSERT INTO t1 VALUES($i, $i, $i+2) } 2992e01aafSdan } 3092e01aafSdan} 3192e01aafSdan 3292e01aafSdan# A DELETE while a cursor is reading the table. 3392e01aafSdan# 3492e01aafSdando_test rtree8-1.1.1 { 3592e01aafSdan execsql { PRAGMA page_size = 512 } 3692e01aafSdan execsql { CREATE VIRTUAL TABLE t1 USING rtree_i32(id, x1, x2) } 3792e01aafSdan populate_t1 5 3892e01aafSdan} {} 3992e01aafSdando_test rtree8-1.1.2 { 4092e01aafSdan set res [list] 41c8c9cdd9Sdrh set rc [catch { 4292e01aafSdan db eval { SELECT * FROM t1 } { 4392e01aafSdan lappend res $x1 $x2 4492e01aafSdan if {$id==3} { db eval { DELETE FROM t1 WHERE id>3 } } 4592e01aafSdan } 46c8c9cdd9Sdrh } msg]; 47c8c9cdd9Sdrh lappend rc $msg 48c8c9cdd9Sdrh set rc 49c8c9cdd9Sdrh} {1 {database table is locked}} 50c8c9cdd9Sdrhdo_test rtree8-1.1.2b { 51c8c9cdd9Sdrh db eval { SELECT * FROM t1 ORDER BY +id } { 52c8c9cdd9Sdrh if {$id==3} { db eval { DELETE FROM t1 WHERE id>3 } } 53c8c9cdd9Sdrh } 54c8c9cdd9Sdrh db eval {SELECT x1, x2 FROM t1} 5592e01aafSdan} {1 3 2 4 3 5} 5692e01aafSdando_test rtree8-1.1.3 { 5792e01aafSdan execsql { SELECT * FROM t1 } 5892e01aafSdan} {1 1 3 2 2 4 3 3 5} 5992e01aafSdan 6092e01aafSdan# Many SELECTs on the same small table. 6192e01aafSdan# 6292e01aafSdanproc nested_select {n} { 6392e01aafSdan set ::max $n 6492e01aafSdan db eval { SELECT * FROM t1 } { 6592e01aafSdan if {$id == $n} { nested_select [expr $n+1] } 6692e01aafSdan } 6792e01aafSdan return $::max 6892e01aafSdan} 6992e01aafSdando_test rtree8-1.2.1 { populate_t1 50 } {} 7092e01aafSdando_test rtree8-1.2.2 { nested_select 1 } {51} 7192e01aafSdan 7292e01aafSdan# This test runs many SELECT queries simultaneously against a large 7392e01aafSdan# table, causing a collision in the hash-table used to store r-tree 7492e01aafSdan# nodes internally. 7592e01aafSdan# 7692e01aafSdanpopulate_t1 1500 771917e92fSdando_rtree_integrity_test rtree8-1.3.0 t1 7892e01aafSdando_execsql_test rtree8-1.3.1 { SELECT max(nodeno) FROM t1_node } {164} 7992e01aafSdando_test rtree8-1.3.2 { 8092e01aafSdan set rowids [execsql {SELECT min(rowid) FROM t1_rowid GROUP BY nodeno}] 8192e01aafSdan set stmt_list [list] 8292e01aafSdan foreach row $rowids { 8392e01aafSdan set stmt [sqlite3_prepare db "SELECT * FROM t1 WHERE id = $row" -1 tail] 8492e01aafSdan sqlite3_step $stmt 8592e01aafSdan lappend res_list [sqlite3_column_int $stmt 0] 8692e01aafSdan lappend stmt_list $stmt 8792e01aafSdan } 8892e01aafSdan} {} 8992e01aafSdando_test rtree8-1.3.3 { set res_list } $rowids 9092e01aafSdando_execsql_test rtree8-1.3.4 { SELECT count(*) FROM t1 } {1500} 9192e01aafSdando_test rtree8-1.3.5 { 9292e01aafSdan foreach stmt $stmt_list { sqlite3_finalize $stmt } 9392e01aafSdan} {} 9492e01aafSdan 9592e01aafSdan 9692e01aafSdan#------------------------------------------------------------------------- 9792e01aafSdan# The following block of tests - rtree8-2.* - test a couple of database 9892e01aafSdan# corruption cases. In this case things are not corrupted at the b-tree 9992e01aafSdan# level, but the contents of the various tables used internally by an 10092e01aafSdan# r-tree table are inconsistent. 10192e01aafSdan# 10292e01aafSdanpopulate_t1 50 10392e01aafSdando_execsql_test rtree8-2.1.1 { SELECT max(nodeno) FROM t1_node } {5} 104*0f0d3ddfSdrhsqlite3_db_config db DEFENSIVE 0 10592e01aafSdando_execsql_test rtree8-2.1.2 { DELETE FROM t1_node } {} 10692e01aafSdanfor {set i 1} {$i <= 50} {incr i} { 10792e01aafSdan do_catchsql_test rtree8-2.1.3.$i { 10892e01aafSdan SELECT * FROM t1 WHERE id = $i 10992e01aafSdan } {1 {database disk image is malformed}} 11092e01aafSdan} 11192e01aafSdando_catchsql_test rtree8-2.1.4 { 11292e01aafSdan SELECT * FROM t1 11392e01aafSdan} {1 {database disk image is malformed}} 11492e01aafSdando_catchsql_test rtree8-2.1.5 { 11592e01aafSdan DELETE FROM t1 11692e01aafSdan} {1 {database disk image is malformed}} 11792e01aafSdan 11892e01aafSdando_execsql_test rtree8-2.1.6 { 11992e01aafSdan DROP TABLE t1; 12092e01aafSdan CREATE VIRTUAL TABLE t1 USING rtree_i32(id, x1, x2); 12192e01aafSdan} {} 12292e01aafSdan 123f836afd4Sdan 124f836afd4Sdanpopulate_t1 50 125*0f0d3ddfSdrhsqlite3_db_config db DEFENSIVE 0 126f836afd4Sdando_execsql_test rtree8-2.2.1 { 127f836afd4Sdan DELETE FROM t1_parent 128f836afd4Sdan} {} 129f836afd4Sdando_catchsql_test rtree8-2.2.2 { 130f836afd4Sdan DELETE FROM t1 WHERE id=25 131f836afd4Sdan} {1 {database disk image is malformed}} 132f836afd4Sdando_execsql_test rtree8-2.2.3 { 133f836afd4Sdan DROP TABLE t1; 134f836afd4Sdan CREATE VIRTUAL TABLE t1 USING rtree_i32(id, x1, x2); 135f836afd4Sdan} {} 136f836afd4Sdan 137f836afd4Sdan 13892e01aafSdan#------------------------------------------------------------------------- 13992e01aafSdan# Test that trying to use the MATCH operator with the r-tree module does 14092e01aafSdan# not confuse it. 14192e01aafSdan# 14292e01aafSdanpopulate_t1 10 14392e01aafSdando_catchsql_test rtree8-3.1 { 14492e01aafSdan SELECT * FROM t1 WHERE x1 MATCH '1234' 145a690ff36Sdrh} {1 {SQL logic error}} 14692e01aafSdan 1472bf19178Sdan#------------------------------------------------------------------------- 1482bf19178Sdan# Test a couple of invalid arguments to rtreedepth(). 1492bf19178Sdan# 1502bf19178Sdando_catchsql_test rtree8-4.1 { 1512bf19178Sdan SELECT rtreedepth('hello world') 1522bf19178Sdan} {1 {Invalid argument to rtreedepth()}} 1532bf19178Sdando_catchsql_test rtree8-4.2 { 1542bf19178Sdan SELECT rtreedepth(X'00') 1552bf19178Sdan} {1 {Invalid argument to rtreedepth()}} 1562bf19178Sdan 1572bf19178Sdan 1582bf19178Sdan#------------------------------------------------------------------------- 1592bf19178Sdan# Delete half of a lopsided tree. 1602bf19178Sdan# 1612bf19178Sdando_execsql_test rtree8-5.1 { 1622bf19178Sdan CREATE VIRTUAL TABLE t2 USING rtree_i32(id, x1, x2) 1632bf19178Sdan} {} 1642bf19178Sdando_test rtree8-5.2 { 1652bf19178Sdan execsql BEGIN 1662bf19178Sdan for {set i 0} {$i < 100} {incr i} { 1672bf19178Sdan execsql { INSERT INTO t2 VALUES($i, 100, 101) } 1682bf19178Sdan } 1692bf19178Sdan for {set i 100} {$i < 200} {incr i} { 1702bf19178Sdan execsql { INSERT INTO t2 VALUES($i, 1000, 1001) } 1712bf19178Sdan } 1722bf19178Sdan execsql COMMIT 1732bf19178Sdan} {} 1741917e92fSdando_rtree_integrity_test rtree8-5.3 t2 1751917e92fSdando_test rtree8-5.4 { 1762bf19178Sdan execsql BEGIN 1772bf19178Sdan for {set i 0} {$i < 200} {incr i} { 1782bf19178Sdan execsql { DELETE FROM t2 WHERE id = $i } 1792bf19178Sdan } 1802bf19178Sdan execsql COMMIT 1812bf19178Sdan} {} 1821917e92fSdando_rtree_integrity_test rtree8-5.5 t2 1832bf19178Sdan 18430fc7f80Sdrh# 2018-05-24 18530fc7f80Sdrh# The following script caused an assertion fault and/or segfault 18630fc7f80Sdrh# prior to the fix that prevents simultaneous reads and writes on 18730fc7f80Sdrh# the same rtree virtual table. 18830fc7f80Sdrh# 18930fc7f80Sdrhdo_test rtree8-6.1 { 19030fc7f80Sdrh db close 19130fc7f80Sdrh sqlite3 db :memory: 19230fc7f80Sdrh db eval { 19330fc7f80Sdrh PRAGMA page_size=512; 19430fc7f80Sdrh CREATE VIRTUAL TABLE t1 USING rtree(id,x1,x2,y1,y2); 19530fc7f80Sdrh WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<49) 19630fc7f80Sdrh INSERT INTO t1 SELECT x, x, x+1, x, x+1 FROM c; 19730fc7f80Sdrh } 19830fc7f80Sdrh set rc [catch { 19930fc7f80Sdrh db eval {SELECT id FROM t1} x { 20030fc7f80Sdrh db eval {DELETE FROM t1 WHERE id=$x(id)} 20130fc7f80Sdrh } 20230fc7f80Sdrh } msg] 20330fc7f80Sdrh lappend rc $msg 20430fc7f80Sdrh} {1 {database table is locked}} 20530fc7f80Sdrh 20630fc7f80Sdrh 20730fc7f80Sdrh 20892e01aafSdan 20992e01aafSdanfinish_test 210