Import 'rtree' extension. (CVS 5159)
FossilOrigin-Name: b104dcd6adadbd3fe15a348fe9d4d290119e139e
This commit is contained in:
parent
02a50b709c
commit
ebaecc148f
123
ext/rtree/README
Normal file
123
ext/rtree/README
Normal file
@ -0,0 +1,123 @@
|
||||
|
||||
This directory contains an SQLite extension that implements a virtual
|
||||
table type that allows users to create, query and manipulate r-tree[1]
|
||||
data structures inside of SQLite databases. Users create, populate
|
||||
and query r-tree structures using ordinary SQL statements.
|
||||
|
||||
1. SQL Interface
|
||||
|
||||
1.1 Table Creation
|
||||
1.2 Data Manipulation
|
||||
1.3 Data Querying
|
||||
1.4 Introspection and Analysis
|
||||
|
||||
2. Compilation and Deployment
|
||||
|
||||
3. References
|
||||
|
||||
|
||||
1. SQL INTERFACE
|
||||
|
||||
1.1 Table Creation.
|
||||
|
||||
All r-tree virtual tables have an odd number of columns between
|
||||
3 and 11. Unlike regular SQLite tables, r-tree tables are strongly
|
||||
typed.
|
||||
|
||||
The leftmost column is always the pimary key and contains 64-bit
|
||||
integer values. Each subsequent column contains a 32-bit real
|
||||
value. For each pair of real values, the first (leftmost) must be
|
||||
less than or greater than the second. R-tree tables may be
|
||||
constructed using the following syntax:
|
||||
|
||||
CREATE VIRTUAL TABLE <name> USING rtree(<column-names>)
|
||||
|
||||
For example:
|
||||
|
||||
CREATE VIRTUAL TABLE boxes USING rtree(boxno, xmin, xmax, ymin, ymax);
|
||||
CREATE VIRTUAL TABLE boxes USING rtree(1, 1.0, 3.0, 2.0, 4.0);
|
||||
|
||||
Constructing a virtual r-tree table <name> creates the following three
|
||||
real tables in the database to store the data structure:
|
||||
|
||||
<name>_node
|
||||
<name>_rowid
|
||||
<name>_parent
|
||||
|
||||
Dropping or modifying the contents of these tables directly will
|
||||
corrupt the r-tree structure. To delete an r-tree from a database,
|
||||
use a regular DROP TABLE statement:
|
||||
|
||||
DROP TABLE <name>;
|
||||
|
||||
Dropping the main r-tree table automatically drops the automatically
|
||||
created tables.
|
||||
|
||||
1.2 Data Manipulation (INSERT, UPDATE, DELETE).
|
||||
|
||||
The usual INSERT, UPDATE or DELETE syntax is used to manipulate data
|
||||
stored in an r-tree table. Please note the following:
|
||||
|
||||
* Inserting a NULL value into the primary key column has the
|
||||
same effect as inserting a NULL into an INTEGER PRIMARY KEY
|
||||
column of a regular table. The system automatically assigns
|
||||
an unused integer key value to the new record. Usually, this
|
||||
is one greater than the largest primary key value currently
|
||||
present in the table.
|
||||
|
||||
* Attempting to insert a duplicate primary key value fails with
|
||||
an SQLITE_CONSTRAINT error.
|
||||
|
||||
* Attempting to insert or modify a record such that the value
|
||||
stored in the (N*2)th column is greater than that stored in
|
||||
the (N*2+1)th column fails with an SQLITE_CONSTRAINT error.
|
||||
|
||||
* When a record is inserted, values are always converted to
|
||||
the required type (64-bit integer or 32-bit real) as if they
|
||||
were part of an SQL CAST expression. Non-numeric strings are
|
||||
converted to zero.
|
||||
|
||||
1.3 Queries.
|
||||
|
||||
R-tree tables may be queried using all of the same SQL syntax supported
|
||||
by regular tables. However, some query patterns are more efficient faster
|
||||
than others.
|
||||
|
||||
R-trees support fast lookup by primary key value (O(logN), like
|
||||
regular tables).
|
||||
|
||||
Any combination of equality and range (<, <=, >, >=) constraints
|
||||
on spatial data columns may be used to optimize other queries. This
|
||||
is the key advantage to using r-tree tables instead of creating
|
||||
indices on regular tables.
|
||||
|
||||
1.4 Introspection and Analysis.
|
||||
|
||||
TODO: Describe rtreenode() and rtreedepth() functions.
|
||||
|
||||
|
||||
2. COMPILATION AND USAGE
|
||||
|
||||
The easiest way to compile and use the ICU extension is to build
|
||||
and use it as a dynamically loadable SQLite extension. To do this
|
||||
using gcc on *nix:
|
||||
|
||||
gcc -shared rtree.c -o libSqliteRtree.so
|
||||
|
||||
You may need to add "-I" flags so that gcc can find sqlite3ext.h
|
||||
and sqlite3.h. The resulting shared lib, libSqliteIcu.so, may be
|
||||
loaded into sqlite in the same way as any other dynamicly loadable
|
||||
extension.
|
||||
|
||||
|
||||
3. REFERENCES
|
||||
|
||||
[1] Atonin Guttman, "R-trees - A Dynamic Index Structure For Spatial
|
||||
Searching", University of California Berkeley, 1984.
|
||||
|
||||
[2] Norbert Beckmann, Hans-Peter Kriegel, Ralf Schneider, Bernhard Seeger,
|
||||
"The R*-tree: An Efficient and Robust Access Method for Points and
|
||||
Rectangles", Universitaet Bremen, 1990.
|
||||
|
||||
|
||||
|
2753
ext/rtree/rtree.c
Normal file
2753
ext/rtree/rtree.c
Normal file
File diff suppressed because it is too large
Load Diff
43
ext/rtree/rtree.test
Normal file
43
ext/rtree/rtree.test
Normal file
@ -0,0 +1,43 @@
|
||||
#
|
||||
# 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 runs all rtree related tests.
|
||||
#
|
||||
# $Id: rtree.test,v 1.1 2008/05/26 18:41:54 danielk1977 Exp $
|
||||
|
||||
set testdir [file join [file dirname $argv0] .. .. test]
|
||||
source $testdir/tester.tcl
|
||||
rename finish_test really_finish_test
|
||||
proc finish_test {} {}
|
||||
set ISQUICK 1
|
||||
|
||||
set EXCLUDE {
|
||||
rtree.test
|
||||
}
|
||||
|
||||
# Files to include in the test. If this list is empty then everything
|
||||
# that is not in the EXCLUDE list is run.
|
||||
#
|
||||
set INCLUDE {
|
||||
}
|
||||
|
||||
foreach testfile [lsort -dictionary [glob [file dirname $argv0]/*.test]] {
|
||||
set tail [file tail $testfile]
|
||||
if {[lsearch -exact $EXCLUDE $tail]>=0} continue
|
||||
if {[llength $INCLUDE]>0 && [lsearch -exact $INCLUDE $tail]<0} continue
|
||||
source $testfile
|
||||
catch {db close}
|
||||
if {$sqlite_open_file_count>0} {
|
||||
puts "$tail did not close all files: $sqlite_open_file_count"
|
||||
incr nErr
|
||||
lappend ::failList $tail
|
||||
set sqlite_open_file_count 0
|
||||
}
|
||||
}
|
||||
|
||||
set sqlite_open_file_count 0
|
||||
really_finish_test
|
||||
|
361
ext/rtree/rtree1.test
Normal file
361
ext/rtree/rtree1.test
Normal file
@ -0,0 +1,361 @@
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# The focus of this file is testing the r-tree extension.
|
||||
#
|
||||
# $Id: rtree1.test,v 1.1 2008/05/26 18:41:54 danielk1977 Exp $
|
||||
#
|
||||
|
||||
set testdir [file join [file dirname $argv0] .. .. test]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Test plan:
|
||||
#
|
||||
# rtree-1.*: Creating/destroying r-tree tables.
|
||||
# rtree-2.*: Test the implicit constraints - unique rowid and
|
||||
# (coord[N]<=coord[N+1]) for even values of N. Also
|
||||
# automatic assigning of rowid values.
|
||||
# rtree-3.*: Linear scans of r-tree data.
|
||||
# rtree-4.*: Test INSERT
|
||||
# rtree-5.*: Test DELETE
|
||||
# rtree-6.*: Test UPDATE
|
||||
# rtree-7.*: Test renaming an r-tree table.
|
||||
# rtree-8.*: Test constrained scans of r-tree data.
|
||||
#
|
||||
|
||||
ifcapable !rtree {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Test cases rtree-1.* test CREATE and DROP table statements.
|
||||
#
|
||||
|
||||
# Test creating and dropping an rtree table.
|
||||
#
|
||||
do_test rtree-1.1.1 {
|
||||
execsql { CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2, y1, y2) }
|
||||
} {}
|
||||
do_test rtree-1.1.2 {
|
||||
execsql { SELECT name FROM sqlite_master ORDER BY name }
|
||||
} {t1 t1_node t1_parent t1_rowid}
|
||||
do_test rtree-1.1.3 {
|
||||
execsql {
|
||||
DROP TABLE t1;
|
||||
SELECT name FROM sqlite_master ORDER BY name;
|
||||
}
|
||||
} {}
|
||||
|
||||
# Test creating and dropping an rtree table with an odd name in
|
||||
# an attached database.
|
||||
#
|
||||
do_test rtree-1.2.1 {
|
||||
execsql {
|
||||
ATTACH 'test2.db' AS aux;
|
||||
CREATE VIRTUAL TABLE aux.'a" "b' USING rtree(ii, x1, x2, y1, y2);
|
||||
}
|
||||
} {}
|
||||
do_test rtree-1.2.2 {
|
||||
execsql { SELECT name FROM sqlite_master ORDER BY name }
|
||||
} {}
|
||||
do_test rtree-1.2.3 {
|
||||
execsql { SELECT name FROM aux.sqlite_master ORDER BY name }
|
||||
} {{a" "b} {a" "b_node} {a" "b_parent} {a" "b_rowid}}
|
||||
do_test rtree-1.2.4 {
|
||||
execsql {
|
||||
DROP TABLE aux.'a" "b';
|
||||
SELECT name FROM aux.sqlite_master ORDER BY name;
|
||||
}
|
||||
} {}
|
||||
|
||||
# Test that the logic for checking the number of columns specified
|
||||
# for an rtree table. Acceptable values are odd numbers between 3 and
|
||||
# 11, inclusive.
|
||||
#
|
||||
set cols [list i1 i2 i3 i4 i5 i6 i7 i8 i9 iA iB iC iD iE iF iG iH iI iJ iK]
|
||||
for {set nCol 1} {$nCol<[llength $cols]} {incr nCol} {
|
||||
|
||||
set columns [join [lrange $cols 0 [expr {$nCol-1}]] ,]
|
||||
|
||||
set X {0 {}}
|
||||
if {$nCol%2 == 0} { set X {1 {Wrong number of columns for an rtree table}} }
|
||||
if {$nCol < 3} { set X {1 {Too few columns for an rtree table}} }
|
||||
if {$nCol > 11} { set X {1 {Too many columns for an rtree table}} }
|
||||
|
||||
do_test rtree-1.3.$nCol {
|
||||
catchsql "
|
||||
CREATE VIRTUAL TABLE t1 USING rtree($columns);
|
||||
"
|
||||
} $X
|
||||
|
||||
catchsql { DROP TABLE t1 }
|
||||
}
|
||||
|
||||
# Test that it is possible to open an existing database that contains
|
||||
# r-tree tables.
|
||||
#
|
||||
do_test rtree-1.4.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2);
|
||||
INSERT INTO t1 VALUES(1, 5.0, 10.0);
|
||||
INSERT INTO t1 VALUES(2, 15.0, 20.0);
|
||||
}
|
||||
} {}
|
||||
do_test rtree-1.4.2 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { SELECT * FROM t1 ORDER BY ii }
|
||||
} {1 5.0 10.0 2 15.0 20.0}
|
||||
do_test rtree-1.4.3 {
|
||||
execsql { DROP TABLE t1 }
|
||||
} {}
|
||||
|
||||
# Test that it is possible to create an r-tree table with ridiculous
|
||||
# column names.
|
||||
#
|
||||
do_test rtree-1.5.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree("the key", "x dim.", "x2'dim");
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
SELECT "the key", "x dim.", "x2'dim" FROM t1;
|
||||
}
|
||||
} {1 2.0 3.0}
|
||||
do_test rtree-1.5.1 {
|
||||
execsql { DROP TABLE t1 }
|
||||
} {}
|
||||
|
||||
# Force the r-tree constructor to fail.
|
||||
#
|
||||
do_test rtree-1.6.1 {
|
||||
execsql { CREATE TABLE t1_rowid(a); }
|
||||
catchsql {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree("the key", "x dim.", "x2'dim");
|
||||
}
|
||||
} {1 {table 't1_rowid' already exists}}
|
||||
do_test rtree-1.6.1 {
|
||||
execsql { DROP TABLE t1_rowid }
|
||||
} {}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Test cases rtree-2.*
|
||||
#
|
||||
do_test rtree-2.1.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2, y1, y2);
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test rtree-2.1.2 {
|
||||
execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) }
|
||||
execsql { SELECT * FROM t1 }
|
||||
} {1 1.0 3.0 2.0 4.0}
|
||||
do_test rtree-2.1.3 {
|
||||
execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) }
|
||||
execsql { SELECT rowid FROM t1 ORDER BY rowid }
|
||||
} {1 2}
|
||||
do_test rtree-2.1.3 {
|
||||
execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) }
|
||||
execsql { SELECT ii FROM t1 ORDER BY ii }
|
||||
} {1 2 3}
|
||||
|
||||
do_test rtree-2.2.1 {
|
||||
catchsql { INSERT INTO t1 VALUES(2, 1, 3, 2, 4) }
|
||||
} {1 {constraint failed}}
|
||||
do_test rtree-2.2.2 {
|
||||
catchsql { INSERT INTO t1 VALUES(4, 1, 3, 4, 2) }
|
||||
} {1 {constraint failed}}
|
||||
do_test rtree-2.2.3 {
|
||||
catchsql { INSERT INTO t1 VALUES(4, 3, 1, 2, 4) }
|
||||
} {1 {constraint failed}}
|
||||
do_test rtree-2.2.4 {
|
||||
execsql { SELECT ii FROM t1 ORDER BY ii }
|
||||
} {1 2 3}
|
||||
|
||||
do_test rtree-2.X {
|
||||
execsql { DROP TABLE t1 }
|
||||
} {}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Test cases rtree-3.* test linear scans of r-tree table data. To test
|
||||
# this we have to insert some data into an r-tree, but that is not the
|
||||
# focus of these tests.
|
||||
#
|
||||
do_test rtree-3.1.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2, y1, y2);
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {}
|
||||
do_test rtree-3.1.2 {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(5, 1, 3, 2, 4);
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {5 1.0 3.0 2.0 4.0}
|
||||
do_test rtree-3.1.3 {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(6, 2, 6, 4, 8);
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {5 1.0 3.0 2.0 4.0 6 2.0 6.0 4.0 8.0}
|
||||
|
||||
# Test the constraint on the coordinates (c[i]<=c[i+1] where (i%2==0)):
|
||||
do_test rtree-3.2.1 {
|
||||
catchsql { INSERT INTO t1 VALUES(7, 2, 6, 4, 3) }
|
||||
} {1 {constraint failed}}
|
||||
do_test rtree-3.2.2 {
|
||||
catchsql { INSERT INTO t1 VALUES(8, 2, 6, 3, 3) }
|
||||
} {0 {}}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Test cases rtree-5.* test DELETE operations.
|
||||
#
|
||||
do_test rtree-5.1.1 {
|
||||
execsql { CREATE VIRTUAL TABLE t2 USING rtree(ii, x1, x2) }
|
||||
} {}
|
||||
do_test rtree-5.1.2 {
|
||||
execsql {
|
||||
INSERT INTO t2 VALUES(1, 10, 20);
|
||||
INSERT INTO t2 VALUES(2, 30, 40);
|
||||
INSERT INTO t2 VALUES(3, 50, 60);
|
||||
SELECT * FROM t2 ORDER BY ii;
|
||||
}
|
||||
} {1 10.0 20.0 2 30.0 40.0 3 50.0 60.0}
|
||||
do_test rtree-5.1.3 {
|
||||
execsql {
|
||||
DELETE FROM t2 WHERE ii=2;
|
||||
SELECT * FROM t2 ORDER BY ii;
|
||||
}
|
||||
} {1 10.0 20.0 3 50.0 60.0}
|
||||
do_test rtree-5.1.4 {
|
||||
execsql {
|
||||
DELETE FROM t2 WHERE ii=1;
|
||||
SELECT * FROM t2 ORDER BY ii;
|
||||
}
|
||||
} {3 50.0 60.0}
|
||||
do_test rtree-5.1.5 {
|
||||
execsql {
|
||||
DELETE FROM t2 WHERE ii=3;
|
||||
SELECT * FROM t2 ORDER BY ii;
|
||||
}
|
||||
} {}
|
||||
do_test rtree-5.1.6 {
|
||||
execsql { SELECT * FROM t2_rowid }
|
||||
} {}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Test cases rtree-5.* test UPDATE operations.
|
||||
#
|
||||
do_test rtree-6.1.1 {
|
||||
execsql { CREATE VIRTUAL TABLE t3 USING rtree(ii, x1, x2, y1, y2) }
|
||||
} {}
|
||||
do_test rtree-6.1.2 {
|
||||
execsql {
|
||||
INSERT INTO t3 VALUES(1, 2, 3, 4, 5);
|
||||
UPDATE t3 SET x2=5;
|
||||
SELECT * FROM t3;
|
||||
}
|
||||
} {1 2.0 5.0 4.0 5.0}
|
||||
do_test rtree-6.1.3 {
|
||||
execsql { UPDATE t3 SET ii = 2 }
|
||||
execsql { SELECT * FROM t3 }
|
||||
} {2 2.0 5.0 4.0 5.0}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Test cases rtree-7.* test rename operations.
|
||||
#
|
||||
do_test rtree-7.1.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t4 USING rtree(ii, x1, x2, y1, y2, z1, z2);
|
||||
INSERT INTO t4 VALUES(1, 2, 3, 4, 5, 6, 7);
|
||||
}
|
||||
} {}
|
||||
do_test rtree-7.1.2 {
|
||||
execsql { ALTER TABLE t4 RENAME TO t5 }
|
||||
execsql { SELECT * FROM t5 }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
do_test rtree-7.1.3 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { SELECT * FROM t5 }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
do_test rtree-7.1.4 {
|
||||
execsql { ALTER TABLE t5 RENAME TO 'raisara "one"'''}
|
||||
execsql { SELECT * FROM "raisara ""one""'" }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
do_test rtree-7.1.5 {
|
||||
execsql { SELECT * FROM 'raisara "one"''' }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
do_test rtree-7.1.6 {
|
||||
execsql { ALTER TABLE "raisara ""one""'" RENAME TO "abc 123" }
|
||||
execsql { SELECT * FROM "abc 123" }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
do_test rtree-7.1.7 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { SELECT * FROM "abc 123" }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
|
||||
# An error midway through a rename operation.
|
||||
do_test rtree-7.2.1 {
|
||||
execsql {
|
||||
CREATE TABLE t4_node(a);
|
||||
}
|
||||
catchsql { ALTER TABLE "abc 123" RENAME TO t4 }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
do_test rtree-7.2.2 {
|
||||
execsql { SELECT * FROM "abc 123" }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
do_test rtree-7.2.3 {
|
||||
execsql {
|
||||
DROP TABLE t4_node;
|
||||
CREATE TABLE t4_rowid(a);
|
||||
}
|
||||
catchsql { ALTER TABLE "abc 123" RENAME TO t4 }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
do_test rtree-7.2.4 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { SELECT * FROM "abc 123" }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
do_test rtree-7.2.5 {
|
||||
execsql { DROP TABLE t4_rowid }
|
||||
execsql { ALTER TABLE "abc 123" RENAME TO t4 }
|
||||
execsql { SELECT * FROM t4 }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Test cases rtree-8.*
|
||||
#
|
||||
|
||||
# Test that the function to determine if a leaf cell is part of the
|
||||
# result set works.
|
||||
do_test rtree-8.1.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t6 USING rtree(ii, x1, x2);
|
||||
INSERT INTO t6 VALUES(1, 3, 7);
|
||||
INSERT INTO t6 VALUES(2, 4, 6);
|
||||
}
|
||||
} {}
|
||||
do_test rtree-8.1.2 { execsql { SELECT ii FROM t6 WHERE x1>2 } } {1 2}
|
||||
do_test rtree-8.1.3 { execsql { SELECT ii FROM t6 WHERE x1>3 } } {2}
|
||||
do_test rtree-8.1.4 { execsql { SELECT ii FROM t6 WHERE x1>4 } } {}
|
||||
do_test rtree-8.1.5 { execsql { SELECT ii FROM t6 WHERE x1>5 } } {}
|
||||
do_test rtree-8.1.6 { execsql { SELECT ii FROM t6 WHERE x1<3 } } {}
|
||||
do_test rtree-8.1.7 { execsql { SELECT ii FROM t6 WHERE x1<4 } } {1}
|
||||
do_test rtree-8.1.8 { execsql { SELECT ii FROM t6 WHERE x1<5 } } {1 2}
|
||||
|
||||
|
||||
finish_test
|
||||
|
144
ext/rtree/rtree2.test
Normal file
144
ext/rtree/rtree2.test
Normal file
@ -0,0 +1,144 @@
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# The focus of this file is testing the r-tree extension.
|
||||
#
|
||||
# $Id: rtree2.test,v 1.1 2008/05/26 18:41:54 danielk1977 Exp $
|
||||
#
|
||||
|
||||
set testdir [file join [file dirname $argv0] .. .. test]
|
||||
source $testdir/tester.tcl
|
||||
source [file join [file dirname $argv0] rtree_util.tcl]
|
||||
|
||||
ifcapable !rtree {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set ::NROW 1000
|
||||
set ::NDEL 10
|
||||
set ::NSELECT 100
|
||||
|
||||
for {set nDim 1} {$nDim <= 5} {incr nDim} {
|
||||
|
||||
do_test rtree2-$nDim.1 {
|
||||
set cols [list]
|
||||
foreach c [list c0 c1 c2 c3 c4 c5 c6 c7 c8 c9] {
|
||||
lappend cols "$c REAL"
|
||||
}
|
||||
set cols [join [lrange $cols 0 [expr {$nDim*2-1}]] ", "]
|
||||
execsql "
|
||||
CREATE VIRTUAL TABLE t1 USING rtree(ii, $cols);
|
||||
CREATE TABLE t2 (ii, $cols);
|
||||
"
|
||||
} {}
|
||||
|
||||
do_test rtree2-$nDim.2 {
|
||||
db transaction {
|
||||
for {set ii 0} {$ii < $::NROW} {incr ii} {
|
||||
#puts "Row $ii"
|
||||
set values [list]
|
||||
for {set jj 0} {$jj<$nDim*2} {incr jj} {
|
||||
lappend values [expr int(rand()*1000)]
|
||||
}
|
||||
set values [join $values ,]
|
||||
#puts [rtree_treedump db t1]
|
||||
#puts "INSERT INTO t2 VALUES($ii, $values)"
|
||||
set rc [catch {db eval "INSERT INTO t1 VALUES($ii, $values)"}]
|
||||
if {$rc} {
|
||||
incr ii -1
|
||||
} else {
|
||||
db eval "INSERT INTO t2 VALUES($ii, $values)"
|
||||
}
|
||||
#if {[rtree_check db t1]} {
|
||||
#puts [rtree_treedump db t1]
|
||||
#exit
|
||||
#}
|
||||
}
|
||||
}
|
||||
|
||||
set t1 [execsql {SELECT * FROM t1 ORDER BY ii}]
|
||||
set t2 [execsql {SELECT * FROM t2 ORDER BY ii}]
|
||||
set rc [expr {$t1 eq $t2}]
|
||||
if {$rc != 1} {
|
||||
puts $t1
|
||||
puts $t2
|
||||
}
|
||||
set rc
|
||||
} {1}
|
||||
|
||||
do_test rtree2-$nDim.3 {
|
||||
rtree_check db t1
|
||||
} 0
|
||||
|
||||
set OPS [list < > <= >= =]
|
||||
for {set ii 0} {$ii < $::NSELECT} {incr ii} {
|
||||
do_test rtree2-$nDim.4.$ii.1 {
|
||||
set where [list]
|
||||
foreach look_three_dots! {. . .} {
|
||||
set colidx [expr int(rand()*($nDim*2+1))-1]
|
||||
if {$colidx<0} {
|
||||
set col ii
|
||||
} else {
|
||||
set col "c$colidx"
|
||||
}
|
||||
set op [lindex $OPS [expr int(rand()*[llength $OPS])]]
|
||||
set val [expr int(rand()*1000)]
|
||||
lappend where "$col $op $val"
|
||||
}
|
||||
set where [join $where " AND "]
|
||||
|
||||
set t1 [execsql "SELECT * FROM t1 WHERE $where ORDER BY ii"]
|
||||
set t2 [execsql "SELECT * FROM t2 WHERE $where ORDER BY ii"]
|
||||
set rc [expr {$t1 eq $t2}]
|
||||
if {$rc != 1} {
|
||||
puts $where
|
||||
puts $t1
|
||||
puts $t2
|
||||
puts [rtree_treedump db t1]
|
||||
breakpoint
|
||||
set t1 [execsql "SELECT * FROM t1 WHERE $where ORDER BY ii"]
|
||||
exit
|
||||
}
|
||||
set rc
|
||||
} {1}
|
||||
}
|
||||
|
||||
for {set ii 0} {$ii < $::NROW} {incr ii $::NDEL} {
|
||||
#puts [rtree_treedump db t1]
|
||||
do_test rtree2-$nDim.5.$ii.1 {
|
||||
execsql "DELETE FROM t2 WHERE ii <= $::ii"
|
||||
execsql "DELETE FROM t1 WHERE ii <= $::ii"
|
||||
|
||||
set t1 [execsql {SELECT * FROM t1 ORDER BY ii}]
|
||||
set t2 [execsql {SELECT * FROM t2 ORDER BY ii}]
|
||||
set rc [expr {$t1 eq $t2}]
|
||||
if {$rc != 1} {
|
||||
puts $t1
|
||||
puts $t2
|
||||
}
|
||||
set rc
|
||||
} {1}
|
||||
do_test rtree2-$nDim.5.$ii.2 {
|
||||
rtree_check db t1
|
||||
} {0}
|
||||
}
|
||||
|
||||
do_test rtree2-$nDim.6 {
|
||||
execsql {
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t2;
|
||||
}
|
||||
} {}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
72
ext/rtree/rtree3.test
Normal file
72
ext/rtree/rtree3.test
Normal file
@ -0,0 +1,72 @@
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# The focus of this file is testing that the r-tree correctly handles
|
||||
# out-of-memory conditions.
|
||||
#
|
||||
# $Id: rtree3.test,v 1.1 2008/05/26 18:41:54 danielk1977 Exp $
|
||||
#
|
||||
|
||||
set testdir [file join [file dirname $argv0] .. .. test]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !rtree {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Only run these tests if memory debugging is turned on.
|
||||
#
|
||||
source $testdir/malloc_common.tcl
|
||||
if {!$MEMDEBUG} {
|
||||
puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..."
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_malloc_test rtree3-1 -sqlbody {
|
||||
BEGIN TRANSACTION;
|
||||
CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2);
|
||||
INSERT INTO rt VALUES(NULL, 3, 5, 7, 9);
|
||||
INSERT INTO rt VALUES(NULL, 13, 15, 17, 19);
|
||||
DELETE FROM rt WHERE ii = 1;
|
||||
SELECT * FROM rt;
|
||||
SELECT ii FROM rt WHERE ii = 2;
|
||||
COMMIT;
|
||||
}
|
||||
do_malloc_test rtree3-2 -sqlprep {
|
||||
CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2);
|
||||
INSERT INTO rt VALUES(NULL, 3, 5, 7, 9);
|
||||
} -sqlbody {
|
||||
DROP TABLE rt;
|
||||
}
|
||||
|
||||
|
||||
do_malloc_test rtree3-3 -sqlprep {
|
||||
CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2);
|
||||
INSERT INTO rt VALUES(NULL, 3, 5, 7, 9);
|
||||
} -tclbody {
|
||||
db eval BEGIN
|
||||
for {set ii 0} {$ii < 100} {incr ii} {
|
||||
set f [expr rand()]
|
||||
db eval {INSERT INTO rt VALUES(NULL, $f*10.0, $f*10.0, $f*15.0, $f*15.0)}
|
||||
}
|
||||
db eval COMMIT
|
||||
db eval BEGIN
|
||||
for {set ii 0} {$ii < 100} {incr ii} {
|
||||
set f [expr rand()]
|
||||
db eval { DELETE FROM rt WHERE x1<($f*10.0) AND x1>($f*10.5) }
|
||||
}
|
||||
db eval COMMIT
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
76
ext/rtree/rtree_perf.tcl
Normal file
76
ext/rtree/rtree_perf.tcl
Normal file
@ -0,0 +1,76 @@
|
||||
|
||||
set testdir [file join [file dirname $argv0] .. .. test]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !rtree {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set NROW 10000
|
||||
set NQUERY 500
|
||||
|
||||
puts "Generating $NROW rows of data..."
|
||||
set data [list]
|
||||
for {set ii 0} {$ii < $NROW} {incr ii} {
|
||||
set x1 [expr {rand()*1000}]
|
||||
set x2 [expr {$x1+rand()*50}]
|
||||
set y1 [expr {rand()*1000}]
|
||||
set y2 [expr {$y1+rand()*50}]
|
||||
lappend data $x1 $x2 $y1 $y2
|
||||
}
|
||||
puts "Finished generating data"
|
||||
|
||||
|
||||
set sql1 {CREATE TABLE btree(ii INTEGER PRIMARY KEY, x1, x2, y1, y2)}
|
||||
set sql2 {CREATE VIRTUAL TABLE rtree USING rtree(ii, x1, x2, y1, y2)}
|
||||
puts "Creating tables:"
|
||||
puts " $sql1"
|
||||
puts " $sql2"
|
||||
db eval $sql1
|
||||
db eval $sql2
|
||||
|
||||
db eval "pragma cache_size=100"
|
||||
|
||||
puts -nonewline "Inserting into btree... "
|
||||
flush stdout
|
||||
set btree_time [time {db transaction {
|
||||
set ii 1
|
||||
foreach {x1 x2 y1 y2} $data {
|
||||
db eval {INSERT INTO btree VALUES($ii, $x1, $x2, $y1, $y2)}
|
||||
incr ii
|
||||
}
|
||||
}}]
|
||||
puts "$btree_time"
|
||||
|
||||
puts -nonewline "Inserting into rtree... "
|
||||
flush stdout
|
||||
set rtree_time [time {db transaction {
|
||||
set ii 1
|
||||
foreach {x1 x2 y1 y2} $data {
|
||||
incr ii
|
||||
db eval {INSERT INTO rtree VALUES($ii, $x1, $x2, $y1, $y2)}
|
||||
}
|
||||
}}]
|
||||
puts "$rtree_time"
|
||||
|
||||
|
||||
puts -nonewline "Selecting from btree... "
|
||||
flush stdout
|
||||
set btree_select_time [time {
|
||||
foreach {x1 x2 y1 y2} [lrange $data 0 [expr $NQUERY*4-1]] {
|
||||
db eval {SELECT * FROM btree WHERE x1<$x1 AND x2>$x2 AND y1<$y1 AND y2>$y2}
|
||||
}
|
||||
}]
|
||||
puts "$btree_select_time"
|
||||
|
||||
puts -nonewline "Selecting from rtree... "
|
||||
flush stdout
|
||||
set rtree_select_time [time {
|
||||
foreach {x1 x2 y1 y2} [lrange $data 0 [expr $NQUERY*4-1]] {
|
||||
db eval {SELECT * FROM rtree WHERE x1<$x1 AND x2>$x2 AND y1<$y1 AND y2>$y2}
|
||||
}
|
||||
}]
|
||||
puts "$rtree_select_time"
|
||||
|
||||
|
195
ext/rtree/rtree_util.tcl
Normal file
195
ext/rtree/rtree_util.tcl
Normal file
@ -0,0 +1,195 @@
|
||||
# 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.
|
||||
#
|
||||
# $Id: rtree_util.tcl,v 1.1 2008/05/26 18:41:54 danielk1977 Exp $
|
||||
#
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# PUBLIC API:
|
||||
#
|
||||
# rtree_depth
|
||||
# rtree_ndim
|
||||
# rtree_node
|
||||
# rtree_mincells
|
||||
# rtree_check
|
||||
# rtree_dump
|
||||
# rtree_treedump
|
||||
#
|
||||
|
||||
proc rtree_depth {db zTab} {
|
||||
$db one "SELECT rtreedepth(data) FROM ${zTab}_node WHERE nodeno=1"
|
||||
}
|
||||
|
||||
proc rtree_nodedepth {db zTab iNode} {
|
||||
set iDepth [rtree_depth $db $zTab]
|
||||
|
||||
set ii $iNode
|
||||
while {$ii != 1} {
|
||||
set sql "SELECT parentnode FROM ${zTab}_parent WHERE nodeno = $ii"
|
||||
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 "pragma table_info($zTab)"]]/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 "%.${iPrec}f" [lindex $node $ii $jj]]
|
||||
lset node $ii $jj $newval
|
||||
}
|
||||
}
|
||||
set node
|
||||
}
|
||||
|
||||
proc rtree_mincells {db zTab} {
|
||||
set n [$db one "select length(data) FROM ${zTab}_node LIMIT 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 "SELECT count(*) FROM ${zTab}_node"]
|
||||
set nRow [$db one "SELECT count(*) FROM ${zTab}"]
|
||||
set nRowid [$db one "SELECT count(*) FROM ${zTab}_rowid"]
|
||||
set nParent [$db one "SELECT count(*) FROM ${zTab}_parent"]
|
||||
|
||||
if {$nNode != ($nParent+1)} {
|
||||
error "Wrong number of entries in ${zTab}_parent"
|
||||
}
|
||||
if {$nRow != $nRowid} {
|
||||
error "Wrong number of entries in ${zTab}_rowid"
|
||||
}
|
||||
|
||||
return $rc
|
||||
}
|
||||
|
||||
proc rtree_node_check {db zTab iNode iDepth} {
|
||||
if {[info exists ::checked($iNode)]} { error "Second ref to $iNode" }
|
||||
set ::checked($iNode) 1
|
||||
|
||||
set node [rtree_node $db $zTab $iNode]
|
||||
if {$iNode!=1 && [llength $node]==0} { error "No such node: $iNode" }
|
||||
|
||||
if {$iNode != 1 && [llength $node]<[rtree_mincells $db $zTab]} {
|
||||
puts "Node $iNode: Has only [llength $node] cells"
|
||||
error ""
|
||||
}
|
||||
if {$iNode == 1 && [llength $node]==1 && [rtree_depth $db $zTab]>0} {
|
||||
set depth [rtree_depth $db $zTab]
|
||||
puts "Node $iNode: Has only 1 child (tree depth is $depth)"
|
||||
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 "Node $iNode: Cell is: {$cell}, should be {$shouldbe}"
|
||||
error ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set mapping_table "${zTab}_parent"
|
||||
set mapping_sql "SELECT parentnode FROM $mapping_table WHERE rowid = \$rowid"
|
||||
if {$iDepth==0} {
|
||||
set mapping_table "${zTab}_rowid"
|
||||
set mapping_sql "SELECT nodeno FROM $mapping_table WHERE rowid = \$rowid"
|
||||
}
|
||||
foreach cell $node {
|
||||
set rowid [lindex $cell 0]
|
||||
set mapping [db one $mapping_sql]
|
||||
if {$mapping != $iNode} {
|
||||
puts "Node $iNode: $mapping_table entry for cell $rowid is $mapping"
|
||||
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 "pragma table_info($zTab)"]]/6)-1)/2}]
|
||||
set sql "SELECT nodeno, rtreenode($nDim, data) AS node FROM ${zTab}_node"
|
||||
$db eval $sql {
|
||||
append zRet [format "% -10s %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 "%-3d %s%s\n" $iNode $zIndent $node]
|
||||
if {$iDepth>0} {
|
||||
foreach cell $node {
|
||||
set i [lindex $cell 0]
|
||||
append ret [rtree_nodetreedump $db $zTab "$zIndent " [expr $iDepth-1] $i]
|
||||
}
|
||||
}
|
||||
set ret
|
||||
}
|
||||
|
||||
proc rtree_treedump {db zTab} {
|
||||
set d [rtree_depth $db $zTab]
|
||||
rtree_nodetreedump $db $zTab "" $d 1
|
||||
}
|
||||
|
189
ext/rtree/viewrtree.tcl
Normal file
189
ext/rtree/viewrtree.tcl
Normal file
@ -0,0 +1,189 @@
|
||||
|
||||
load ./libsqlite3.dylib
|
||||
#package require sqlite3
|
||||
source [file join [file dirname $argv0] rtree_util.tcl]
|
||||
|
||||
wm title . "SQLite r-tree viewer"
|
||||
|
||||
if {[llength $argv]!=1} {
|
||||
puts stderr "Usage: $argv0 <database-file>"
|
||||
puts stderr ""
|
||||
exit
|
||||
}
|
||||
sqlite3 db [lindex $argv 0]
|
||||
|
||||
canvas .c -background white -width 400 -height 300 -highlightthickness 0
|
||||
|
||||
button .b -text "Parent Node" -command {
|
||||
set sql "SELECT parentnode FROM $::O(zTab)_parent WHERE nodeno = $::O(iNode)"
|
||||
set ::O(iNode) [db one $sql]
|
||||
if {$::O(iNode) eq ""} {set ::O(iNode) 1}
|
||||
view_node
|
||||
}
|
||||
|
||||
set O(iNode) 1
|
||||
set O(zTab) ""
|
||||
set O(listbox_captions) [list]
|
||||
set O(listbox_itemmap) [list]
|
||||
set O(listbox_highlight) -1
|
||||
|
||||
listbox .l -listvariable ::O(listbox_captions) -yscrollcommand {.ls set}
|
||||
scrollbar .ls -command {.l yview}
|
||||
label .status -font courier -anchor w
|
||||
label .title -anchor w -text "Node 1:" -background white -borderwidth 0
|
||||
|
||||
|
||||
set rtree_tables [list]
|
||||
db eval {
|
||||
SELECT name
|
||||
FROM sqlite_master
|
||||
WHERE type='table' AND sql LIKE '%virtual%table%using%rtree%'
|
||||
} {
|
||||
set nCol [expr [llength [db eval "pragma table_info($name)"]]/6]
|
||||
if {$nCol != 5} {
|
||||
puts stderr "Not viewing $name - is not 2-dimensional"
|
||||
} else {
|
||||
lappend rtree_tables [list Table $name]
|
||||
}
|
||||
}
|
||||
if {$rtree_tables eq ""} {
|
||||
puts stderr "Cannot find an r-tree table in database [lindex $argv 0]"
|
||||
puts stderr ""
|
||||
exit
|
||||
}
|
||||
eval tk_optionMenu .select option_var $rtree_tables
|
||||
trace add variable option_var write set_option_var
|
||||
proc set_option_var {args} {
|
||||
set ::O(zTab) [lindex $::option_var 1]
|
||||
set ::O(iNode) 1
|
||||
view_node
|
||||
}
|
||||
set ::O(zTab) [lindex $::rtree_tables 0 1]
|
||||
|
||||
bind .l <1> {listbox_click [.l nearest %y]}
|
||||
bind .l <Motion> {listbox_mouseover [.l nearest %y]}
|
||||
bind .l <Leave> {listbox_mouseover -1}
|
||||
|
||||
proc listbox_click {sel} {
|
||||
if {$sel ne ""} {
|
||||
set ::O(iNode) [lindex $::O(listbox_captions) $sel 1]
|
||||
view_node
|
||||
}
|
||||
}
|
||||
proc listbox_mouseover {i} {
|
||||
set oldid [lindex $::O(listbox_itemmap) $::O(listbox_highlight)]
|
||||
.c itemconfigure $oldid -fill ""
|
||||
|
||||
.l selection clear 0 end
|
||||
.status configure -text ""
|
||||
if {$i>=0} {
|
||||
set id [lindex $::O(listbox_itemmap) $i]
|
||||
.c itemconfigure $id -fill grey
|
||||
.c lower $id
|
||||
set ::O(listbox_highlight) $i
|
||||
.l selection set $i
|
||||
.status configure -text [cell_report db $::O(zTab) $::O(iNode) $i]
|
||||
}
|
||||
}
|
||||
|
||||
grid configure .select -row 0 -column 0 -columnspan 2 -sticky nsew
|
||||
grid configure .b -row 1 -column 0 -columnspan 2 -sticky nsew
|
||||
grid configure .l -row 2 -column 0 -sticky nsew
|
||||
grid configure .status -row 3 -column 0 -columnspan 3 -sticky nsew
|
||||
|
||||
grid configure .title -row 0 -column 2 -sticky nsew
|
||||
grid configure .c -row 1 -column 2 -rowspan 2 -sticky nsew
|
||||
grid configure .ls -row 2 -column 1 -sticky nsew
|
||||
|
||||
grid columnconfigure . 2 -weight 1
|
||||
grid rowconfigure . 2 -weight 1
|
||||
|
||||
proc node_bbox {data} {
|
||||
set xmin 0
|
||||
set xmax 0
|
||||
set ymin 0
|
||||
set ymax 0
|
||||
foreach {rowid xmin xmax ymin ymax} [lindex $data 0] break
|
||||
foreach cell [lrange $data 1 end] {
|
||||
foreach {rowid x1 x2 y1 y2} $cell break
|
||||
if {$x1 < $xmin} {set xmin $x1}
|
||||
if {$x2 > $xmax} {set xmax $x2}
|
||||
if {$y1 < $ymin} {set ymin $y1}
|
||||
if {$y2 > $ymax} {set ymax $y2}
|
||||
}
|
||||
list $xmin $xmax $ymin $ymax
|
||||
}
|
||||
|
||||
proc view_node {} {
|
||||
set iNode $::O(iNode)
|
||||
set zTab $::O(zTab)
|
||||
|
||||
set data [rtree_node db $zTab $iNode 12]
|
||||
set depth [rtree_nodedepth db $zTab $iNode]
|
||||
|
||||
.c delete all
|
||||
set ::O(listbox_captions) [list]
|
||||
set ::O(listbox_itemmap) [list]
|
||||
set $::O(listbox_highlight) -1
|
||||
|
||||
.b configure -state normal
|
||||
if {$iNode == 1} {.b configure -state disabled}
|
||||
.title configure -text "Node $iNode: [cell_report db $zTab $iNode -1]"
|
||||
|
||||
foreach {xmin xmax ymin ymax} [node_bbox $data] break
|
||||
set total_area 0.0
|
||||
|
||||
set xscale [expr {double([winfo width .c]-20)/($xmax-$xmin)}]
|
||||
set yscale [expr {double([winfo height .c]-20)/($ymax-$ymin)}]
|
||||
|
||||
set xoff [expr {10.0 - $xmin*$xscale}]
|
||||
set yoff [expr {10.0 - $ymin*$yscale}]
|
||||
|
||||
foreach cell $data {
|
||||
foreach {rowid x1 x2 y1 y2} $cell break
|
||||
set total_area [expr {$total_area + ($x2-$x1)*($y2-$y1)}]
|
||||
set x1 [expr {$x1*$xscale + $xoff}]
|
||||
set x2 [expr {$x2*$xscale + $xoff}]
|
||||
set y1 [expr {$y1*$yscale + $yoff}]
|
||||
set y2 [expr {$y2*$yscale + $yoff}]
|
||||
|
||||
set id [.c create rectangle $x1 $y1 $x2 $y2]
|
||||
if {$depth>0} {
|
||||
lappend ::O(listbox_captions) "Node $rowid"
|
||||
lappend ::O(listbox_itemmap) $id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc cell_report {db zTab iParent iCell} {
|
||||
set data [rtree_node db $zTab $iParent 12]
|
||||
set cell [lindex $data $iCell]
|
||||
|
||||
foreach {xmin xmax ymin ymax} [node_bbox $data] break
|
||||
set total_area [expr ($xmax-$xmin)*($ymax-$ymin)]
|
||||
|
||||
if {$cell eq ""} {
|
||||
set cell_area 0.0
|
||||
foreach cell $data {
|
||||
foreach {rowid x1 x2 y1 y2} $cell break
|
||||
set cell_area [expr $cell_area+($x2-$x1)*($y2-$y1)]
|
||||
}
|
||||
set cell_area [expr $cell_area/[llength $data]]
|
||||
set zReport [format "Size = %.1f x %.1f Average child area = %.1f%%" \
|
||||
[expr $xmax-$xmin] [expr $ymax-$ymin] [expr 100.0*$cell_area/$total_area]\
|
||||
]
|
||||
append zReport " Sub-tree height: [rtree_nodedepth db $zTab $iParent]"
|
||||
} else {
|
||||
foreach {rowid x1 x2 y1 y2} $cell break
|
||||
set cell_area [expr ($x2-$x1)*($y2-$y1)]
|
||||
set zReport [format "Size = %.1f x %.1f Area = %.1f%%" \
|
||||
[expr $x2-$x1] [expr $y2-$y1] [expr 100.0*$cell_area/$total_area]
|
||||
]
|
||||
}
|
||||
|
||||
return $zReport
|
||||
}
|
||||
|
||||
view_node
|
||||
bind .c <Configure> view_node
|
||||
|
5
main.mk
5
main.mk
@ -58,7 +58,7 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o bitvec.o btmutex.o btree.o build.o \
|
||||
select.o table.o $(TCLOBJ) tokenize.o trigger.o \
|
||||
update.o util.o vacuum.o \
|
||||
vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbefifo.o vdbemem.o \
|
||||
where.o utf.o legacy.o vtab.o
|
||||
where.o utf.o legacy.o vtab.o rtree.o
|
||||
|
||||
EXTOBJ = icu.o
|
||||
EXTOBJ += fts1.o \
|
||||
@ -412,6 +412,9 @@ fts3_tokenizer.o: $(TOP)/ext/fts3/fts3_tokenizer.c $(HDR) $(EXTHDR)
|
||||
fts3_tokenizer1.o: $(TOP)/ext/fts3/fts3_tokenizer1.c $(HDR) $(EXTHDR)
|
||||
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer1.c
|
||||
|
||||
rtree.o: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR)
|
||||
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c
|
||||
|
||||
|
||||
# Rules for building test programs and for running tests
|
||||
#
|
||||
|
27
manifest
27
manifest
@ -1,5 +1,5 @@
|
||||
C Fix\sthe\sLIKE\squery\soptimizer\sso\sthat\sit\sworks\swith\sLIKE\spatterns\nending\sin\s'@%'\son\sNOCASE\scolumns.\s\sTicket\s#3139.\s(CVS\s5158)
|
||||
D 2008-05-26T18:33:41
|
||||
C Import\s'rtree'\sextension.\s(CVS\s5159)
|
||||
D 2008-05-26T18:41:54
|
||||
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
||||
F Makefile.in 79aeba12300a54903f1b1257c1e7c190234045dd
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@ -63,9 +63,18 @@ F ext/fts3/fts3_tokenizer1.c 0a5bcc579f35de5d24a9345d7908dc25ae403ee7
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33
|
||||
F ext/icu/icu.c 12e763d288d23b5a49de37caa30737b971a2f1e2
|
||||
F ext/rtree/README decb7976cfacf834074d15028af99344439e30c3
|
||||
F ext/rtree/rtree.c f56f8a5888d3584f5b19112ade2855db5a985690
|
||||
F ext/rtree/rtree.test ec173a9420ff012e4d29b3063add143583a597a7
|
||||
F ext/rtree/rtree1.test 96563843773129eaec544f52768853f06be61d9c
|
||||
F ext/rtree/rtree2.test 98f3c39b03577330566abf3c7e1e0baf8f9aa521
|
||||
F ext/rtree/rtree3.test 46d1959aa651d3df8b64d93762d3061c62b38105
|
||||
F ext/rtree/rtree_perf.tcl 0fabb6d5c48cb8024e042ce5d4bb88998b6ec1cb
|
||||
F ext/rtree/rtree_util.tcl ee0a0311eb12175319d78bfb37302320496cee6e
|
||||
F ext/rtree/viewrtree.tcl 09526398dae87a5a87c5aac2b3854dbaf8376869
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||
F ltmain.sh 09fe5815427dc7d0abb188bbcdf0e34896577210
|
||||
F main.mk 6a916bb5c17cf2a753346b32cc0869ffdc1ed4b3
|
||||
F main.mk 6c01687f355dc8c7dff14a952a7c720b3a4c11a6
|
||||
F mkdll.sh 712e74f3efe08a6ba12b2945d018a29a89d7fe3b
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh 1a866b53637dab137191341cc875575a5ca110fb
|
||||
@ -102,7 +111,7 @@ F src/insert.c 77f0829b3e2edd19e9238195c56b0d56ab000f17
|
||||
F src/journal.c cffd2cd214e58c0e99c3ff632b3bee6c7cbb260e
|
||||
F src/legacy.c 8f5a2b25d9673b4004287cf2bf51dbf7d0738406
|
||||
F src/loadext.c eac6c61810a3b531808774bec7f3d238cfe261f3
|
||||
F src/main.c cf415e0920dc9f66806dd766ad72ba5cda533363
|
||||
F src/main.c 51f02209493572630dfcf4d4c8855f08aae21b9b
|
||||
F src/malloc.c 12c1ae98ef1eff34b13c9eb526e0b7b479e1e820
|
||||
F src/md5.c 008216bbb5d34c6fbab5357aa68575ad8a31516a
|
||||
F src/mem1.c fc716ff521b6dd3e43eaa211967383308800e70a
|
||||
@ -148,7 +157,7 @@ F src/test9.c 4615ef08750245a2d96aaa7cbe2fb4aff2b57acc
|
||||
F src/test_async.c 0d26a72361022f6f732dd1174c6615bad6e587ff
|
||||
F src/test_autoext.c 5e892ab84aece3f0428920bf46923f16ac83962a
|
||||
F src/test_btree.c c1308ba0b88ab577fa56c9e493a09829dfcded9c
|
||||
F src/test_config.c b910754c5ba311abf149457cdbfd66144e715b35
|
||||
F src/test_config.c 982bba6221b854a86427ae64e9c65b313b0f6e03
|
||||
F src/test_devsym.c 76cf28b79c6f01658083ae2a972647b97a362a01
|
||||
F src/test_func.c f4aafa10f17d52c43a64b47717265802e6e552b3
|
||||
F src/test_hexio.c 2f1122aa3f012fa0142ee3c36ce5c902a70cd12f
|
||||
@ -637,7 +646,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||
P 77d5a7aa1c7ea715298228ed2dbd0497cacbd0e4
|
||||
R d32b39a4864ba1e92f958c456cb9d453
|
||||
U drh
|
||||
Z b0b4c859c49b7350ba450c2f85000be9
|
||||
P 33548744369643cc8843b74ad1fc1b7d5988d7a4
|
||||
R 675fcc0cf171d37f901dfc59fa943c1b
|
||||
U danielk1977
|
||||
Z a3cfe87334f3bee1a0f0c75b4054c9e1
|
||||
|
@ -1 +1 @@
|
||||
33548744369643cc8843b74ad1fc1b7d5988d7a4
|
||||
b104dcd6adadbd3fe15a348fe9d4d290119e139e
|
10
src/main.c
10
src/main.c
@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.440 2008/05/22 13:56:17 danielk1977 Exp $
|
||||
** $Id: main.c,v 1.441 2008/05/26 18:41:54 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -1184,6 +1184,14 @@ static int openDatabase(
|
||||
rc = sqlite3IcuInit(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_RTREE
|
||||
if( !db->mallocFailed && rc==SQLITE_OK){
|
||||
extern int sqlite3RtreeInit(sqlite3*);
|
||||
rc = sqlite3RtreeInit(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3Error(db, rc, 0);
|
||||
|
||||
/* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
|
||||
|
@ -16,7 +16,7 @@
|
||||
** The focus of this file is providing the TCL testing layer
|
||||
** access to compile-time constants.
|
||||
**
|
||||
** $Id: test_config.c,v 1.25 2008/04/14 01:00:58 drh Exp $
|
||||
** $Id: test_config.c,v 1.26 2008/05/26 18:41:54 danielk1977 Exp $
|
||||
*/
|
||||
|
||||
#include "sqliteLimit.h"
|
||||
@ -338,6 +338,12 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
|
||||
Tcl_SetVar2(interp, "sqlite_options", "reindex", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_RTREE
|
||||
Tcl_SetVar2(interp, "sqlite_options", "rtree", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "rtree", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
|
||||
Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
Loading…
Reference in New Issue
Block a user