Add the sqlite3_rtree_query_callback() API to the RTree virtual table.
(Cherrypick from the sessions branch.) FossilOrigin-Name: af2cbe64adab5f9e3b0f3da00d06428088589d7f
This commit is contained in:
parent
1f8bb4b0a8
commit
65e6b0dd12
1496
ext/rtree/rtree.c
1496
ext/rtree/rtree.c
File diff suppressed because it is too large
Load Diff
@ -120,12 +120,13 @@ proc execsql_intout {sql} {
|
||||
# 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_execsql_test rtree-1.4.1a {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2);
|
||||
INSERT INTO t1 VALUES(1, 5.0, 10.0);
|
||||
SELECT substr(hex(data),1,40) FROM t1_node;
|
||||
} {00000001000000000000000140A0000041200000}
|
||||
do_execsql_test rtree-1.4.1b {
|
||||
INSERT INTO t1 VALUES(2, 15.0, 20.0);
|
||||
} {}
|
||||
do_test rtree-1.4.2 {
|
||||
db close
|
||||
@ -435,16 +436,18 @@ do_test rtree-11.2 {
|
||||
# Test on-conflict clause handling.
|
||||
#
|
||||
db_delete_and_reopen
|
||||
do_execsql_test 12.0 {
|
||||
do_execsql_test 12.0.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree_i32(idx, x1, x2, y1, y2);
|
||||
INSERT INTO t1 VALUES(1, 1, 2, 3, 4);
|
||||
SELECT substr(hex(data),1,56) FROM t1_node;
|
||||
} {00000001000000000000000100000001000000020000000300000004}
|
||||
do_execsql_test 12.0.2 {
|
||||
INSERT INTO t1 VALUES(2, 2, 3, 4, 5);
|
||||
INSERT INTO t1 VALUES(3, 3, 4, 5, 6);
|
||||
|
||||
CREATE TABLE source(idx, x1, x2, y1, y2);
|
||||
INSERT INTO source VALUES(5, 8, 8, 8, 8);
|
||||
INSERT INTO source VALUES(2, 7, 7, 7, 7);
|
||||
|
||||
}
|
||||
db_save_and_close
|
||||
foreach {tn sql_template testdata} {
|
||||
|
@ -57,31 +57,31 @@ do_test rtree6-1.1 {
|
||||
|
||||
do_test rtree6-1.2 {
|
||||
rtree_strategy {SELECT * FROM t1 WHERE x1>10}
|
||||
} {Ea}
|
||||
} {E0}
|
||||
|
||||
do_test rtree6-1.3 {
|
||||
rtree_strategy {SELECT * FROM t1 WHERE x1<10}
|
||||
} {Ca}
|
||||
} {C0}
|
||||
|
||||
do_test rtree6-1.4 {
|
||||
rtree_strategy {SELECT * FROM t1,t2 WHERE k=ii AND x1<10}
|
||||
} {Ca}
|
||||
} {C0}
|
||||
|
||||
do_test rtree6-1.5 {
|
||||
rtree_strategy {SELECT * FROM t1,t2 WHERE k=+ii AND x1<10}
|
||||
} {Ca}
|
||||
} {C0}
|
||||
|
||||
do_eqp_test rtree6.2.1 {
|
||||
SELECT * FROM t1,t2 WHERE k=+ii AND x1<10
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca}
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0}
|
||||
0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
|
||||
do_eqp_test rtree6.2.2 {
|
||||
SELECT * FROM t1,t2 WHERE k=ii AND x1<10
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca}
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0}
|
||||
0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
|
||||
@ -95,7 +95,7 @@ do_eqp_test rtree6.2.3 {
|
||||
do_eqp_test rtree6.2.4 {
|
||||
SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:CaEb}
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1}
|
||||
0 1 1 {SEARCH TABLE t2 USING AUTOMATIC COVERING INDEX (v=?)}
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ do_test rtree6.3.2 {
|
||||
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND
|
||||
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5
|
||||
}
|
||||
} {EaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEa}
|
||||
} {E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0}
|
||||
do_test rtree6.3.3 {
|
||||
rtree_strategy {
|
||||
SELECT * FROM t3 WHERE
|
||||
@ -137,7 +137,7 @@ do_test rtree6.3.3 {
|
||||
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND
|
||||
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5
|
||||
}
|
||||
} {EaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEa}
|
||||
} {E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0}
|
||||
|
||||
do_execsql_test rtree6-3.4 {
|
||||
SELECT * FROM t3 WHERE x1>0.5 AND x1>0.8 AND x1>1.1
|
||||
|
@ -41,7 +41,7 @@ ifcapable rtree_int_only {
|
||||
INSERT INTO t1 VALUES(9223372036854775807, 150, 150, 400, 400);
|
||||
SELECT rtreenode(2, data) FROM t1_node;
|
||||
}
|
||||
} {{{1073741824 0.000000 0.000000 100.000000 100.000000} {2147483646 0.000000 0.000000 200.000000 200.000000} {4294967296 0.000000 0.000000 300.000000 300.000000} {8589934592 20.000000 20.000000 150.000000 150.000000} {9223372036854775807 150.000000 150.000000 400.000000 400.000000}}}
|
||||
} {{{1073741824 0 0 100 100} {2147483646 0 0 200 200} {4294967296 0 0 300 300} {8589934592 20 20 150 150} {9223372036854775807 150 150 400 400}}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
@ -29,7 +29,7 @@ do_eqp_test 1.1 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
|
||||
} {
|
||||
0 0 1 {SCAN TABLE t}
|
||||
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 1.2 {
|
||||
@ -37,7 +37,7 @@ do_eqp_test 1.2 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 1.3 {
|
||||
@ -45,7 +45,7 @@ do_eqp_test 1.3 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 1.5 {
|
||||
@ -82,7 +82,7 @@ do_eqp_test 2.1 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
|
||||
} {
|
||||
0 0 1 {SCAN TABLE t}
|
||||
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 2.2 {
|
||||
@ -90,7 +90,7 @@ do_eqp_test 2.2 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 2.3 {
|
||||
@ -98,7 +98,7 @@ do_eqp_test 2.3 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 2.5 {
|
||||
@ -271,4 +271,3 @@ ifcapable rtree {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
129
ext/rtree/rtreeE.test
Normal file
129
ext/rtree/rtreeE.test
Normal file
@ -0,0 +1,129 @@
|
||||
# 2010 August 28
|
||||
#
|
||||
# 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 tests for the r-tree module. Specifically, it tests
|
||||
# that new-style custom r-tree queries (geometry callbacks) work.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !rtree { finish_test ; return }
|
||||
ifcapable rtree_int_only { finish_test; return }
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the example 2d "circle" geometry callback.
|
||||
#
|
||||
register_circle_geom db
|
||||
|
||||
do_execsql_test rtreeE-1.1 {
|
||||
PRAGMA page_size=512;
|
||||
CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1);
|
||||
|
||||
/* A tight pattern of small boxes near 0,0 */
|
||||
WITH RECURSIVE
|
||||
x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4),
|
||||
y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4)
|
||||
INSERT INTO rt1 SELECT x+5*y, x, x+2, y, y+2 FROM x, y;
|
||||
|
||||
/* A looser pattern of small boxes near 100, 0 */
|
||||
WITH RECURSIVE
|
||||
x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4),
|
||||
y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4)
|
||||
INSERT INTO rt1 SELECT 100+x+5*y, x*3+100, x*3+102, y*3, y*3+2 FROM x, y;
|
||||
|
||||
/* A looser pattern of larger boxes near 0, 200 */
|
||||
WITH RECURSIVE
|
||||
x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4),
|
||||
y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4)
|
||||
INSERT INTO rt1 SELECT 200+x+5*y, x*7, x*7+15, y*7+200, y*7+215 FROM x, y;
|
||||
} {}
|
||||
|
||||
# Queries against each of the three clusters */
|
||||
do_execsql_test rtreeE-1.1 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0.0, 0.0, 50.0, 3) ORDER BY id;
|
||||
} {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24}
|
||||
do_execsql_test rtreeE-1.2 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(100.0, 0.0, 50.0, 3) ORDER BY id;
|
||||
} {100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124}
|
||||
do_execsql_test rtreeE-1.3 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0.0, 200.0, 50.0, 3) ORDER BY id;
|
||||
} {200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224}
|
||||
|
||||
# The Qcircle geometry function gives a lower score to larger leaf-nodes.
|
||||
# This causes the 200s to sort before the 100s and the 0s to sort before
|
||||
# last.
|
||||
#
|
||||
do_execsql_test rtreeE-1.4 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,3) AND id%100==0
|
||||
} {200 100 0}
|
||||
|
||||
# Exclude odd rowids on a depth-first search
|
||||
do_execsql_test rtreeE-1.5 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,4) ORDER BY +id
|
||||
} {0 2 4 6 8 10 12 14 16 18 20 22 24 100 102 104 106 108 110 112 114 116 118 120 122 124 200 202 204 206 208 210 212 214 216 218 220 222 224}
|
||||
|
||||
# Exclude odd rowids on a breadth-first search.
|
||||
do_execsql_test rtreeE-1.6 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,5) ORDER BY +id
|
||||
} {0 2 4 6 8 10 12 14 16 18 20 22 24 100 102 104 106 108 110 112 114 116 118 120 122 124 200 202 204 206 208 210 212 214 216 218 220 222 224}
|
||||
|
||||
# Construct a large 2-D RTree with thousands of random entries.
|
||||
#
|
||||
do_test rtreeE-2.1 {
|
||||
db eval {
|
||||
CREATE TABLE t2(id,x0,x1,y0,y1);
|
||||
CREATE VIRTUAL TABLE rt2 USING rtree(id,x0,x1,y0,y1);
|
||||
BEGIN;
|
||||
}
|
||||
expr srand(0)
|
||||
for {set i 1} {$i<=10000} {incr i} {
|
||||
set dx [expr {int(rand()*40)+1}]
|
||||
set dy [expr {int(rand()*40)+1}]
|
||||
set x0 [expr {int(rand()*(10000 - $dx))}]
|
||||
set x1 [expr {$x0+$dx}]
|
||||
set y0 [expr {int(rand()*(10000 - $dy))}]
|
||||
set y1 [expr {$y0+$dy}]
|
||||
set id [expr {$i+10000}]
|
||||
db eval {INSERT INTO t2 VALUES($id,$x0,$x1,$y0,$y1)}
|
||||
}
|
||||
db eval {
|
||||
INSERT INTO rt2 SELECT * FROM t2;
|
||||
COMMIT;
|
||||
}
|
||||
} {}
|
||||
|
||||
for {set i 1} {$i<=200} {incr i} {
|
||||
set dx [expr {int(rand()*100)}]
|
||||
set dy [expr {int(rand()*100)}]
|
||||
set x0 [expr {int(rand()*(10000 - $dx))}]
|
||||
set x1 [expr {$x0+$dx}]
|
||||
set y0 [expr {int(rand()*(10000 - $dy))}]
|
||||
set y1 [expr {$y0+$dy}]
|
||||
set ans [db eval {SELECT id FROM t2 WHERE x1>=$x0 AND x0<=$x1 AND y1>=$y0 AND y0<=$y1 ORDER BY id}]
|
||||
do_execsql_test rtreeE-2.2.$i {
|
||||
SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch($x0,$x1,$y0,$y1) ORDER BY id
|
||||
} $ans
|
||||
}
|
||||
|
||||
# Run query that have very deep priority queues
|
||||
#
|
||||
set ans [db eval {SELECT id FROM t2 WHERE x1>=0 AND x0<=5000 AND y1>=0 AND y0<=5000 ORDER BY id}]
|
||||
do_execsql_test rtreeE-2.3 {
|
||||
SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch(0,5000,0,5000) ORDER BY id
|
||||
} $ans
|
||||
set ans [db eval {SELECT id FROM t2 WHERE x1>=0 AND x0<=10000 AND y1>=0 AND y0<=10000 ORDER BY id}]
|
||||
do_execsql_test rtreeE-2.4 {
|
||||
SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch(0,10000,0,10000) ORDER BY id
|
||||
} $ans
|
||||
|
||||
finish_test
|
@ -21,6 +21,16 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
|
||||
typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
|
||||
|
||||
/* The double-precision datatype used by RTree depends on the
|
||||
** SQLITE_RTREE_INT_ONLY compile-time option.
|
||||
*/
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
typedef sqlite3_int64 sqlite3_rtree_dbl;
|
||||
#else
|
||||
typedef double sqlite3_rtree_dbl;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Register a geometry callback named zGeom that can be used as part of an
|
||||
@ -31,11 +41,7 @@ typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
|
||||
int sqlite3_rtree_geometry_callback(
|
||||
sqlite3 *db,
|
||||
const char *zGeom,
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes),
|
||||
#else
|
||||
int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes),
|
||||
#endif
|
||||
int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
|
||||
void *pContext
|
||||
);
|
||||
|
||||
@ -47,11 +53,60 @@ int sqlite3_rtree_geometry_callback(
|
||||
struct sqlite3_rtree_geometry {
|
||||
void *pContext; /* Copy of pContext passed to s_r_g_c() */
|
||||
int nParam; /* Size of array aParam[] */
|
||||
double *aParam; /* Parameters passed to SQL geom function */
|
||||
sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */
|
||||
void *pUser; /* Callback implementation user data */
|
||||
void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */
|
||||
};
|
||||
|
||||
/*
|
||||
** Register a 2nd-generation geometry callback named zScore that can be
|
||||
** used as part of an R-Tree geometry query as follows:
|
||||
**
|
||||
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
|
||||
*/
|
||||
int sqlite3_rtree_query_callback(
|
||||
sqlite3 *db,
|
||||
const char *zQueryFunc,
|
||||
int (*xQueryFunc)(sqlite3_rtree_query_info*),
|
||||
void *pContext,
|
||||
void (*xDestructor)(void*)
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
** A pointer to a structure of the following type is passed as the
|
||||
** argument to scored geometry callback registered using
|
||||
** sqlite3_rtree_query_callback().
|
||||
**
|
||||
** Note that the first 5 fields of this structure are identical to
|
||||
** sqlite3_rtree_geometry. This structure is a subclass of
|
||||
** sqlite3_rtree_geometry.
|
||||
*/
|
||||
struct sqlite3_rtree_query_info {
|
||||
void *pContext; /* pContext from when function registered */
|
||||
int nParam; /* Number of function parameters */
|
||||
sqlite3_rtree_dbl *aParam; /* value of function parameters */
|
||||
void *pUser; /* callback can use this, if desired */
|
||||
void (*xDelUser)(void*); /* function to free pUser */
|
||||
sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */
|
||||
unsigned int *anQueue; /* Number of pending entries in the queue */
|
||||
int nCoord; /* Number of coordinates */
|
||||
int iLevel; /* Level of current node or entry */
|
||||
int mxLevel; /* The largest iLevel value in the tree */
|
||||
sqlite3_int64 iRowid; /* Rowid for current entry */
|
||||
sqlite3_rtree_dbl rParentScore; /* Score of parent node */
|
||||
int eParentWithin; /* Visibility of parent node */
|
||||
int eWithin; /* OUT: Visiblity */
|
||||
sqlite3_rtree_dbl rScore; /* OUT: Write the score here */
|
||||
};
|
||||
|
||||
/*
|
||||
** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin.
|
||||
*/
|
||||
#define NOT_WITHIN 0 /* Object completely outside of query region */
|
||||
#define PARTLY_WITHIN 1 /* Object partially overlaps query region */
|
||||
#define FULLY_WITHIN 2 /* Object fully contained within query region */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of the 'extern "C"' block */
|
||||
|
2
main.mk
2
main.mk
@ -476,7 +476,7 @@ parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk
|
||||
mv parse.h parse.h.temp
|
||||
$(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
|
||||
|
||||
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION
|
||||
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION $(TOP)/ext/rtree/sqlite3rtree.h
|
||||
tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
|
||||
|
||||
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
|
||||
|
33
manifest
33
manifest
@ -1,5 +1,5 @@
|
||||
C Update\srequirements\smarks\sto\sfix\stypos\sin\sthe\srequirements\stext.\nNo\schanges\sto\scode.
|
||||
D 2014-04-26T19:23:14.120
|
||||
C Add\sthe\ssqlite3_rtree_query_callback()\sAPI\sto\sthe\sRTree\svirtual\stable.\n(Cherrypick\sfrom\sthe\ssessions\sbranch.)
|
||||
D 2014-04-28T17:56:19.891
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -120,30 +120,31 @@ F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
|
||||
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 2d9f95da404d850474e628c720c5ce15d29b47de
|
||||
F ext/rtree/rtree.c 6f70db93e0e42c369325c5cddcf2024c5a87ca43
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test cf679265ecafff494a768ac9c2f43a70915a6290
|
||||
F ext/rtree/rtree1.test e2da4aaa426918d27122d1a1066c6ecf8409a514
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc
|
||||
F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0
|
||||
F ext/rtree/rtree5.test 6a510494f12454bf57ef28f45bc7764ea279431e
|
||||
F ext/rtree/rtree6.test fe0bd377a21c68ce2826129d14354c884cb1f354
|
||||
F ext/rtree/rtree6.test 756585abc51727fec97c77852476445c10c0ee95
|
||||
F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971
|
||||
F ext/rtree/rtree8.test db79c812f9e4a11f9b1f3f9934007884610a713a
|
||||
F ext/rtree/rtree9.test d86ebf08ff6328895613ed577dd8a2a37c472c34
|
||||
F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf
|
||||
F ext/rtree/rtreeB.test 983e567b49b5dca165940f66b87e161aa30e82b2
|
||||
F ext/rtree/rtreeC.test 16d7aa86ecb6a876d2a38cf590a1471a41b3a46d
|
||||
F ext/rtree/rtreeB.test c85f9ce78766c4e68b8b89fbf2979ee9cfa82b4e
|
||||
F ext/rtree/rtreeC.test df158dcc81f1a43ce7eef361af03c48ec91f1e06
|
||||
F ext/rtree/rtreeD.test 636630357638f5983701550b37f0f5867130d2ca
|
||||
F ext/rtree/rtreeE.test 388c1c8602c3ce55c15f03b509e9cf545fb7c41f
|
||||
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
|
||||
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
||||
F ext/rtree/sqlite3rtree.h c34c1e41d1ab80bb8ad09aae402c9c956871a765
|
||||
F ext/rtree/sqlite3rtree.h 83349d519fe5f518b3ea025d18dd1fe51b1684bd
|
||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt f439556c5ce01ced70987e5ee86549a45165d9ff
|
||||
F main.mk 3ae543fa446525c1dec55f58de67f41b78651812
|
||||
F main.mk 9546867b42992c554e7af8672549ba13afaadade
|
||||
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
|
||||
F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
@ -260,7 +261,7 @@ F src/test_osinst.c 90a845c8183013d80eccb1f29e8805608516edba
|
||||
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
|
||||
F src/test_quota.c 30c64f0ef84734f2231a686df41ed882b0c59bc0
|
||||
F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb
|
||||
F src/test_rtree.c f3d1d12538dccb75fd916e3fa58f250edbdd3b47
|
||||
F src/test_rtree.c fdd8d29ca5165c7857987a2ba263fac5c69e231f
|
||||
F src/test_schema.c cd12a2223c3a394f4d07bb93bdf6d344c5c121b6
|
||||
F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
|
||||
F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e
|
||||
@ -270,7 +271,7 @@ F src/test_syscall.c 2e21ca7f7dc54a028f1967b63f1e76155c356f9b
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb
|
||||
F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9
|
||||
F src/test_vfstrace.c 3a0ab304682fecbceb689e7d9b904211fde11d78
|
||||
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 6da2de6e12218ccb0aea5184b56727d011f4bee7
|
||||
F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb
|
||||
@ -811,6 +812,7 @@ F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29
|
||||
F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9
|
||||
F test/shell5.test bb755ea9144b8078a752fc56223582627070b5f1
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868
|
||||
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
|
||||
F test/skipscan1.test bed8cbe9d554c8c27afb6c88500f704c86a9196f
|
||||
@ -826,7 +828,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
|
||||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/speedtest1.c 90446861e566a9965a8d005381a3c964ff333646
|
||||
F test/speedtest1.c d29c8048beb7ea9254191f3fde9414709166a920
|
||||
F test/spellfix.test 61309f5efbec53603b3f86457d34a504f80abafe
|
||||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de
|
||||
@ -1163,7 +1165,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P 349f483499dd685a8da94923b6bd810a52e5e236
|
||||
R 310b081215d2804c69537a1d1f588735
|
||||
P f5a263658187250044afc1a74000e6f6962733ca
|
||||
Q +3dca2809352c6c6d56db74447a814f77011c6220
|
||||
R 70a04a84bf76743284b12f147604df6e
|
||||
U drh
|
||||
Z 3788b514428a54594de7c9ac65d6befd
|
||||
Z 8441eee0dd2b010346629b18a46aad71
|
||||
|
@ -1 +1 @@
|
||||
f5a263658187250044afc1a74000e6f6962733ca
|
||||
af2cbe64adab5f9e3b0f3da00d06428088589d7f
|
200
src/test_rtree.c
200
src/test_rtree.c
@ -35,6 +35,8 @@ struct Circle {
|
||||
double centerx;
|
||||
double centery;
|
||||
double radius;
|
||||
double mxArea;
|
||||
int eScoreType;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -50,11 +52,7 @@ static void circle_del(void *p){
|
||||
static int circle_geom(
|
||||
sqlite3_rtree_geometry *p,
|
||||
int nCoord,
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
sqlite3_int64 *aCoord,
|
||||
#else
|
||||
double *aCoord,
|
||||
#endif
|
||||
sqlite3_rtree_dbl *aCoord,
|
||||
int *pRes
|
||||
){
|
||||
int i; /* Iterator variable */
|
||||
@ -62,7 +60,12 @@ static int circle_geom(
|
||||
double xmin, xmax; /* X dimensions of box being tested */
|
||||
double ymin, ymax; /* X dimensions of box being tested */
|
||||
|
||||
if( p->pUser==0 ){
|
||||
xmin = aCoord[0];
|
||||
xmax = aCoord[1];
|
||||
ymin = aCoord[2];
|
||||
ymax = aCoord[3];
|
||||
pCircle = (Circle *)p->pUser;
|
||||
if( pCircle==0 ){
|
||||
/* If pUser is still 0, then the parameter values have not been tested
|
||||
** for correctness or stored into a Circle structure yet. Do this now. */
|
||||
|
||||
@ -108,14 +111,9 @@ static int circle_geom(
|
||||
pCircle->aBox[1].xmax = pCircle->centerx - pCircle->radius;
|
||||
pCircle->aBox[1].ymin = pCircle->centery;
|
||||
pCircle->aBox[1].ymax = pCircle->centery;
|
||||
pCircle->mxArea = (xmax - xmin)*(ymax - ymin) + 1.0;
|
||||
}
|
||||
|
||||
pCircle = (Circle *)p->pUser;
|
||||
xmin = aCoord[0];
|
||||
xmax = aCoord[1];
|
||||
ymin = aCoord[2];
|
||||
ymax = aCoord[3];
|
||||
|
||||
/* Check if any of the 4 corners of the bounding-box being tested lie
|
||||
** inside the circular region. If they do, then the bounding-box does
|
||||
** intersect the region of interest. Set the output variable to true and
|
||||
@ -154,6 +152,170 @@ static int circle_geom(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of "circle" r-tree geometry callback using the
|
||||
** 2nd-generation interface that allows scoring.
|
||||
*/
|
||||
static int circle_query_func(sqlite3_rtree_query_info *p){
|
||||
int i; /* Iterator variable */
|
||||
Circle *pCircle; /* Structure defining circular region */
|
||||
double xmin, xmax; /* X dimensions of box being tested */
|
||||
double ymin, ymax; /* X dimensions of box being tested */
|
||||
int nWithin = 0; /* Number of corners inside the circle */
|
||||
|
||||
xmin = p->aCoord[0];
|
||||
xmax = p->aCoord[1];
|
||||
ymin = p->aCoord[2];
|
||||
ymax = p->aCoord[3];
|
||||
pCircle = (Circle *)p->pUser;
|
||||
if( pCircle==0 ){
|
||||
/* If pUser is still 0, then the parameter values have not been tested
|
||||
** for correctness or stored into a Circle structure yet. Do this now. */
|
||||
|
||||
/* This geometry callback is for use with a 2-dimensional r-tree table.
|
||||
** Return an error if the table does not have exactly 2 dimensions. */
|
||||
if( p->nCoord!=4 ) return SQLITE_ERROR;
|
||||
|
||||
/* Test that the correct number of parameters (4) have been supplied,
|
||||
** and that the parameters are in range (that the radius of the circle
|
||||
** radius is greater than zero). */
|
||||
if( p->nParam!=4 || p->aParam[2]<0.0 ) return SQLITE_ERROR;
|
||||
|
||||
/* Allocate a structure to cache parameter data in. Return SQLITE_NOMEM
|
||||
** if the allocation fails. */
|
||||
pCircle = (Circle *)(p->pUser = sqlite3_malloc(sizeof(Circle)));
|
||||
if( !pCircle ) return SQLITE_NOMEM;
|
||||
p->xDelUser = circle_del;
|
||||
|
||||
/* Record the center and radius of the circular region. One way that
|
||||
** tested bounding boxes that intersect the circular region are detected
|
||||
** is by testing if each corner of the bounding box lies within radius
|
||||
** units of the center of the circle. */
|
||||
pCircle->centerx = p->aParam[0];
|
||||
pCircle->centery = p->aParam[1];
|
||||
pCircle->radius = p->aParam[2];
|
||||
pCircle->eScoreType = (int)p->aParam[3];
|
||||
|
||||
/* Define two bounding box regions. The first, aBox[0], extends to
|
||||
** infinity in the X dimension. It covers the same range of the Y dimension
|
||||
** as the circular region. The second, aBox[1], extends to infinity in
|
||||
** the Y dimension and is constrained to the range of the circle in the
|
||||
** X dimension.
|
||||
**
|
||||
** Then imagine each box is split in half along its short axis by a line
|
||||
** that intersects the center of the circular region. A bounding box
|
||||
** being tested can be said to intersect the circular region if it contains
|
||||
** points from each half of either of the two infinite bounding boxes.
|
||||
*/
|
||||
pCircle->aBox[0].xmin = pCircle->centerx;
|
||||
pCircle->aBox[0].xmax = pCircle->centerx;
|
||||
pCircle->aBox[0].ymin = pCircle->centery + pCircle->radius;
|
||||
pCircle->aBox[0].ymax = pCircle->centery - pCircle->radius;
|
||||
pCircle->aBox[1].xmin = pCircle->centerx + pCircle->radius;
|
||||
pCircle->aBox[1].xmax = pCircle->centerx - pCircle->radius;
|
||||
pCircle->aBox[1].ymin = pCircle->centery;
|
||||
pCircle->aBox[1].ymax = pCircle->centery;
|
||||
pCircle->mxArea = 200.0*200.0;
|
||||
}
|
||||
|
||||
/* Check if any of the 4 corners of the bounding-box being tested lie
|
||||
** inside the circular region. If they do, then the bounding-box does
|
||||
** intersect the region of interest. Set the output variable to true and
|
||||
** return SQLITE_OK in this case. */
|
||||
for(i=0; i<4; i++){
|
||||
double x = (i&0x01) ? xmax : xmin;
|
||||
double y = (i&0x02) ? ymax : ymin;
|
||||
double d2;
|
||||
|
||||
d2 = (x-pCircle->centerx)*(x-pCircle->centerx);
|
||||
d2 += (y-pCircle->centery)*(y-pCircle->centery);
|
||||
if( d2<(pCircle->radius*pCircle->radius) ) nWithin++;
|
||||
}
|
||||
|
||||
/* Check if the bounding box covers any other part of the circular region.
|
||||
** See comments above for a description of how this test works. If it does
|
||||
** cover part of the circular region, set the output variable to true
|
||||
** and return SQLITE_OK. */
|
||||
if( nWithin==0 ){
|
||||
for(i=0; i<2; i++){
|
||||
if( xmin<=pCircle->aBox[i].xmin
|
||||
&& xmax>=pCircle->aBox[i].xmax
|
||||
&& ymin<=pCircle->aBox[i].ymin
|
||||
&& ymax>=pCircle->aBox[i].ymax
|
||||
){
|
||||
nWithin = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( pCircle->eScoreType==1 ){
|
||||
/* Depth first search */
|
||||
p->rScore = p->iLevel;
|
||||
}else if( pCircle->eScoreType==2 ){
|
||||
/* Breadth first search */
|
||||
p->rScore = 100 - p->iLevel;
|
||||
}else if( pCircle->eScoreType==3 ){
|
||||
/* Depth-first search, except sort the leaf nodes by area with
|
||||
** the largest area first */
|
||||
if( p->iLevel==1 ){
|
||||
p->rScore = 1.0 - (xmax-xmin)*(ymax-ymin)/pCircle->mxArea;
|
||||
if( p->rScore<0.01 ) p->rScore = 0.01;
|
||||
}else{
|
||||
p->rScore = 0.0;
|
||||
}
|
||||
}else if( pCircle->eScoreType==4 ){
|
||||
/* Depth-first search, except exclude odd rowids */
|
||||
p->rScore = p->iLevel;
|
||||
if( p->iRowid&1 ) nWithin = 0;
|
||||
}else{
|
||||
/* Breadth-first search, except exclude odd rowids */
|
||||
p->rScore = 100 - p->iLevel;
|
||||
if( p->iRowid&1 ) nWithin = 0;
|
||||
}
|
||||
if( nWithin==0 ){
|
||||
p->eWithin = NOT_WITHIN;
|
||||
}else if( nWithin>=4 ){
|
||||
p->eWithin = FULLY_WITHIN;
|
||||
}else{
|
||||
p->eWithin = PARTLY_WITHIN;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
/*
|
||||
** Implementation of "breadthfirstsearch" r-tree geometry callback using the
|
||||
** 2nd-generation interface that allows scoring.
|
||||
**
|
||||
** ... WHERE id MATCH breadthfirstsearch($x0,$x1,$y0,$y1) ...
|
||||
**
|
||||
** It returns all entries whose bounding boxes overlap with $x0,$x1,$y0,$y1.
|
||||
*/
|
||||
static int bfs_query_func(sqlite3_rtree_query_info *p){
|
||||
double x0,x1,y0,y1; /* Dimensions of box being tested */
|
||||
double bx0,bx1,by0,by1; /* Boundary of the query function */
|
||||
|
||||
if( p->nParam!=4 ) return SQLITE_ERROR;
|
||||
x0 = p->aCoord[0];
|
||||
x1 = p->aCoord[1];
|
||||
y0 = p->aCoord[2];
|
||||
y1 = p->aCoord[3];
|
||||
bx0 = p->aParam[0];
|
||||
bx1 = p->aParam[1];
|
||||
by0 = p->aParam[2];
|
||||
by1 = p->aParam[3];
|
||||
p->rScore = 100 - p->iLevel;
|
||||
if( p->eParentWithin==FULLY_WITHIN ){
|
||||
p->eWithin = FULLY_WITHIN;
|
||||
}else if( x0>=bx0 && x1<=bx1 && y0>=by0 && y1<=by1 ){
|
||||
p->eWithin = FULLY_WITHIN;
|
||||
}else if( x1>=bx0 && x0<=bx1 && y1>=by0 && y0<=by1 ){
|
||||
p->eWithin = PARTLY_WITHIN;
|
||||
}else{
|
||||
p->eWithin = NOT_WITHIN;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* END of implementation of "circle" geometry callback.
|
||||
**************************************************************************
|
||||
*************************************************************************/
|
||||
@ -194,11 +356,7 @@ static int gHere = 42;
|
||||
static int cube_geom(
|
||||
sqlite3_rtree_geometry *p,
|
||||
int nCoord,
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
sqlite3_int64 *aCoord,
|
||||
#else
|
||||
double *aCoord,
|
||||
#endif
|
||||
sqlite3_rtree_dbl *aCoord,
|
||||
int *piRes
|
||||
){
|
||||
Cube *pCube = (Cube *)p->pUser;
|
||||
@ -293,6 +451,14 @@ static int register_circle_geom(
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
rc = sqlite3_rtree_geometry_callback(db, "circle", circle_geom, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_rtree_query_callback(db, "Qcircle",
|
||||
circle_query_func, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_rtree_query_callback(db, "breadthfirstsearch",
|
||||
bfs_query_func, 0, 0);
|
||||
}
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
|
||||
#endif
|
||||
return TCL_OK;
|
||||
|
@ -678,7 +678,7 @@ static int vfstraceAccess(
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xDelete(\"%s\",%d)",
|
||||
vfstrace_printf(pInfo, "%s.xAccess(\"%s\",%d)",
|
||||
pInfo->zVfsName, zPath, flags);
|
||||
rc = pRoot->xAccess(pRoot, zPath, flags, pResOut);
|
||||
vfstrace_print_errcode(pInfo, " -> %s", rc);
|
||||
|
57
test/show_speedtest1_rtree.tcl
Normal file
57
test/show_speedtest1_rtree.tcl
Normal file
@ -0,0 +1,57 @@
|
||||
#!/usr/bin/tclsh
|
||||
#
|
||||
# This script displays the field of rectangles used by --testset rtree
|
||||
# of speedtest1. Run this script as follows:
|
||||
#
|
||||
# rm test.db
|
||||
# ./speedtest1 --testset rtree --size 25 test.db
|
||||
# sqlite3 --separator ' ' test.db 'SELECT * FROM rt1' >data.txt
|
||||
# wish show_speedtest1_rtree.tcl
|
||||
#
|
||||
# The filename "data.txt" is hard coded into this script and so that name
|
||||
# must be used on lines 3 and 4 above. Elsewhere, different filenames can
|
||||
# be used. The --size N parameter can be adjusted as desired.
|
||||
#
|
||||
package require Tk
|
||||
set f [open data.txt rb]
|
||||
set data [read $f]
|
||||
close $f
|
||||
canvas .c
|
||||
frame .b
|
||||
button .b.b1 -text X-Y -command refill-xy
|
||||
button .b.b2 -text X-Z -command refill-xz
|
||||
button .b.b3 -text Y-Z -command refill-yz
|
||||
pack .b.b1 .b.b2 .b.b3 -side left
|
||||
pack .c -side top -fill both -expand 1
|
||||
pack .b -side top
|
||||
proc resize_canvas_to_fit {} {
|
||||
foreach {x0 y0 x1 y1} [.c bbox all] break
|
||||
set w [expr {$x1-$x0}]
|
||||
set h [expr {$y1-$y0}]
|
||||
.c config -width $w -height $h
|
||||
}
|
||||
proc refill-xy {} {
|
||||
.c delete all
|
||||
foreach {id x0 x1 y0 y1 z0 z1} $::data {
|
||||
.c create rectangle $x0 $y0 $x1 $y1
|
||||
}
|
||||
.c scale all 0 0 0.05 0.05
|
||||
resize_canvas_to_fit
|
||||
}
|
||||
proc refill-xz {} {
|
||||
.c delete all
|
||||
foreach {id x0 x1 y0 y1 z0 z1} $::data {
|
||||
.c create rectangle $x0 $z0 $x1 $z1
|
||||
}
|
||||
.c scale all 0 0 0.05 0.05
|
||||
resize_canvas_to_fit
|
||||
}
|
||||
proc refill-yz {} {
|
||||
.c delete all
|
||||
foreach {id x0 x1 y0 y1 z0 z1} $::data {
|
||||
.c create rectangle $y0 $z0 $y1 $z1
|
||||
}
|
||||
.c scale all 0 0 0.05 0.05
|
||||
resize_canvas_to_fit
|
||||
}
|
||||
refill-xy
|
@ -29,6 +29,7 @@ static const char zHelp[] =
|
||||
" --trace Turn on SQL tracing\n"
|
||||
" --utf16be Set text encoding to UTF-16BE\n"
|
||||
" --utf16le Set text encoding to UTF-16LE\n"
|
||||
" --verify Run additional verification steps.\n"
|
||||
" --without-rowid Use WITHOUT ROWID where appropriate\n"
|
||||
;
|
||||
|
||||
@ -51,6 +52,7 @@ static struct Global {
|
||||
int bReprepare; /* True to reprepare the SQL on each rerun */
|
||||
int bSqlOnly; /* True to print the SQL once only */
|
||||
int bExplain; /* Print SQL with EXPLAIN prefix */
|
||||
int bVerify; /* Try to verify that results are correct */
|
||||
int szTest; /* Scale factor for test iterations */
|
||||
const char *zWR; /* Might be WITHOUT ROWID */
|
||||
const char *zNN; /* Might be NOT NULL */
|
||||
@ -931,6 +933,183 @@ void testset_cte(void){
|
||||
|
||||
}
|
||||
|
||||
/* Generate two numbers between 1 and mx. The first number is less than
|
||||
** the second. Usually the numbers are near each other but can sometimes
|
||||
** be far apart.
|
||||
*/
|
||||
static void twoCoords(
|
||||
int p1, int p2, /* Parameters adjusting sizes */
|
||||
unsigned mx, /* Range of 1..mx */
|
||||
unsigned *pX0, unsigned *pX1 /* OUT: write results here */
|
||||
){
|
||||
unsigned d, x0, x1, span;
|
||||
|
||||
span = mx/100 + 1;
|
||||
if( speedtest1_random()%3==0 ) span *= p1;
|
||||
if( speedtest1_random()%p2==0 ) span = mx/2;
|
||||
d = speedtest1_random()%span + 1;
|
||||
x0 = speedtest1_random()%(mx-d) + 1;
|
||||
x1 = x0 + d;
|
||||
*pX0 = x0;
|
||||
*pX1 = x1;
|
||||
}
|
||||
|
||||
/* The following routine is an R-Tree geometry callback. It returns
|
||||
** true if the object overlaps a slice on the Y coordinate between the
|
||||
** two values given as arguments. In other words
|
||||
**
|
||||
** SELECT count(*) FROM rt1 WHERE id MATCH xslice(10,20);
|
||||
**
|
||||
** Is the same as saying:
|
||||
**
|
||||
** SELECT count(*) FROM rt1 WHERE y1>=10 AND y0<=20;
|
||||
*/
|
||||
static int xsliceGeometryCallback(
|
||||
sqlite3_rtree_geometry *p,
|
||||
int nCoord,
|
||||
double *aCoord,
|
||||
int *pRes
|
||||
){
|
||||
*pRes = aCoord[3]>=p->aParam[0] && aCoord[2]<=p->aParam[1];
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** A testset for the R-Tree virtual table
|
||||
*/
|
||||
void testset_rtree(int p1, int p2){
|
||||
unsigned i, n;
|
||||
unsigned mxCoord;
|
||||
unsigned x0, x1, y0, y1, z0, z1;
|
||||
unsigned iStep;
|
||||
int *aCheck = sqlite3_malloc( sizeof(int)*g.szTest*100 );
|
||||
|
||||
mxCoord = 15000;
|
||||
n = g.szTest*100;
|
||||
speedtest1_begin_test(100, "%d INSERTs into an r-tree", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_exec("CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1,z0,z1)");
|
||||
speedtest1_prepare("INSERT INTO rt1(id,x0,x1,y0,y1,z0,z1)"
|
||||
"VALUES(?1,?2,?3,?4,?5,?6,?7)");
|
||||
for(i=1; i<=n; i++){
|
||||
twoCoords(p1, p2, mxCoord, &x0, &x1);
|
||||
twoCoords(p1, p2, mxCoord, &y0, &y1);
|
||||
twoCoords(p1, p2, mxCoord, &z0, &z1);
|
||||
sqlite3_bind_int(g.pStmt, 1, i);
|
||||
sqlite3_bind_int(g.pStmt, 2, x0);
|
||||
sqlite3_bind_int(g.pStmt, 3, x1);
|
||||
sqlite3_bind_int(g.pStmt, 4, y0);
|
||||
sqlite3_bind_int(g.pStmt, 5, y1);
|
||||
sqlite3_bind_int(g.pStmt, 6, z0);
|
||||
sqlite3_bind_int(g.pStmt, 7, z1);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_begin_test(101, "Copy from rtree to a regular table");
|
||||
speedtest1_exec("CREATE TABLE t1(id INTEGER PRIMARY KEY,x0,x1,y0,y1,z0,z1)");
|
||||
speedtest1_exec("INSERT INTO t1 SELECT * FROM rt1");
|
||||
speedtest1_end_test();
|
||||
|
||||
n = g.szTest*20;
|
||||
speedtest1_begin_test(110, "%d one-dimensional intersect slice queries", n);
|
||||
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x0>=?1 AND x1<=?2");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
|
||||
speedtest1_run();
|
||||
aCheck[i] = atoi(g.zResult);
|
||||
}
|
||||
speedtest1_end_test();
|
||||
|
||||
if( g.bVerify ){
|
||||
n = g.szTest*20;
|
||||
speedtest1_begin_test(111, "Verify result from 1-D intersect slice queries");
|
||||
speedtest1_prepare("SELECT count(*) FROM t1 WHERE x0>=?1 AND x1<=?2");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
|
||||
speedtest1_run();
|
||||
if( aCheck[i]!=atoi(g.zResult) ){
|
||||
fatal_error("Count disagree step %d: %d..%d. %d vs %d",
|
||||
i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
|
||||
}
|
||||
}
|
||||
speedtest1_end_test();
|
||||
}
|
||||
|
||||
n = g.szTest*20;
|
||||
speedtest1_begin_test(120, "%d one-dimensional overlap slice queries", n);
|
||||
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE y1>=?1 AND y0<=?2");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
|
||||
speedtest1_run();
|
||||
aCheck[i] = atoi(g.zResult);
|
||||
}
|
||||
speedtest1_end_test();
|
||||
|
||||
if( g.bVerify ){
|
||||
n = g.szTest*20;
|
||||
speedtest1_begin_test(121, "Verify result from 1-D overlap slice queries");
|
||||
speedtest1_prepare("SELECT count(*) FROM t1 WHERE y1>=?1 AND y0<=?2");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
|
||||
speedtest1_run();
|
||||
if( aCheck[i]!=atoi(g.zResult) ){
|
||||
fatal_error("Count disagree step %d: %d..%d. %d vs %d",
|
||||
i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
|
||||
}
|
||||
}
|
||||
speedtest1_end_test();
|
||||
}
|
||||
|
||||
|
||||
n = g.szTest*20;
|
||||
speedtest1_begin_test(125, "%d custom geometry callback queries", n);
|
||||
sqlite3_rtree_geometry_callback(g.db, "xslice", xsliceGeometryCallback, 0);
|
||||
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE id MATCH xslice(?1,?2)");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
|
||||
speedtest1_run();
|
||||
if( aCheck[i]!=atoi(g.zResult) ){
|
||||
fatal_error("Count disagree step %d: %d..%d. %d vs %d",
|
||||
i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
|
||||
}
|
||||
}
|
||||
speedtest1_end_test();
|
||||
|
||||
n = g.szTest*80;
|
||||
speedtest1_begin_test(130, "%d three-dimensional intersect box queries", n);
|
||||
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x1>=?1 AND x0<=?2"
|
||||
" AND y1>=?1 AND y0<=?2 AND z1>=?1 AND z0<=?2");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
|
||||
speedtest1_run();
|
||||
aCheck[i] = atoi(g.zResult);
|
||||
}
|
||||
speedtest1_end_test();
|
||||
|
||||
n = g.szTest*100;
|
||||
speedtest1_begin_test(140, "%d rowid queries", n);
|
||||
speedtest1_prepare("SELECT * FROM rt1 WHERE id=?1");
|
||||
for(i=1; i<=n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_end_test();
|
||||
}
|
||||
|
||||
/*
|
||||
** A testset used for debugging speedtest1 itself.
|
||||
*/
|
||||
@ -1050,6 +1229,8 @@ int main(int argc, char **argv){
|
||||
zEncoding = "utf16le";
|
||||
}else if( strcmp(z,"utf16be")==0 ){
|
||||
zEncoding = "utf16be";
|
||||
}else if( strcmp(z,"verify")==0 ){
|
||||
g.bVerify = 1;
|
||||
}else if( strcmp(z,"without-rowid")==0 ){
|
||||
g.zWR = "WITHOUT ROWID";
|
||||
g.zPK = "PRIMARY KEY";
|
||||
@ -1141,8 +1322,11 @@ int main(int argc, char **argv){
|
||||
testset_debug1();
|
||||
}else if( strcmp(zTSet,"cte")==0 ){
|
||||
testset_cte();
|
||||
}else if( strcmp(zTSet,"rtree")==0 ){
|
||||
testset_rtree(6, 147);
|
||||
}else{
|
||||
fatal_error("unknown testset: \"%s\"\n", zTSet);
|
||||
fatal_error("unknown testset: \"%s\"\nChoices: main debug1 cte rtree\n",
|
||||
zTSet);
|
||||
}
|
||||
speedtest1_final();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user