Fix for [e9a9fde1f4]. When opening an existing rtree, determine the node size by inspecting the root node of the r-tree structure (instead of assuming it is a function of the page-size).

FossilOrigin-Name: ebc9433fddf78ef7b4237686951d8d79c1c98f03
This commit is contained in:
dan 2010-02-16 10:59:40 +00:00
parent 9a6ffc845b
commit 5dcb3937b6
4 changed files with 149 additions and 73 deletions

View File

@ -423,6 +423,7 @@ nodeAcquire(
rc = sqlite3_step(pRtree->pReadNode);
if( rc==SQLITE_ROW ){
const u8 *zBlob = sqlite3_column_blob(pRtree->pReadNode, 0);
assert( sqlite3_column_bytes(pRtree->pReadNode, 0)==pRtree->iNodeSize );
memcpy(pNode->zData, zBlob, pRtree->iNodeSize);
nodeReference(pParent);
}else{
@ -2619,31 +2620,69 @@ static int rtreeSqlInit(
}
/*
** This routine queries database handle db for the page-size used by
** database zDb. If successful, the page-size in bytes is written to
** *piPageSize and SQLITE_OK returned. Otherwise, and an SQLite error
** code is returned.
** The second argument to this function contains the text of an SQL statement
** that returns a single integer value. The statement is compiled and executed
** using database connection db. If successful, the integer value returned
** is written to *piVal and SQLITE_OK returned. Otherwise, an SQLite error
** code is returned and the value of *piVal after returning is not defined.
*/
static int getPageSize(sqlite3 *db, const char *zDb, int *piPageSize){
static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){
int rc = SQLITE_NOMEM;
if( zSql ){
sqlite3_stmt *pStmt = 0;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pStmt) ){
*piVal = sqlite3_column_int(pStmt, 0);
}
rc = sqlite3_finalize(pStmt);
}
}
return rc;
}
/*
** This function is called from within the xConnect() or xCreate() method to
** determine the node-size used by the rtree table being created or connected
** to. If successful, pRtree->iNodeSize is populated and SQLITE_OK returned.
** Otherwise, an SQLite error code is returned.
**
** If this function is being called as part of an xConnect(), then the rtree
** table already exists. In this case the node-size is determined by inspecting
** the root node of the tree.
**
** Otherwise, for an xCreate(), use 64 bytes less than the database page-size.
** This ensures that each node is stored on a single database page. If the
** database page-size is so large that more than RTREE_MAXCELLS entries
** would fit in a single node, use a smaller node-size.
*/
static int getNodeSize(
sqlite3 *db, /* Database handle */
Rtree *pRtree, /* Rtree handle */
int isCreate /* True for xCreate, false for xConnect */
){
int rc;
char *zSql;
sqlite3_stmt *pStmt = 0;
zSql = sqlite3_mprintf("PRAGMA %Q.page_size", zDb);
if( !zSql ){
return SQLITE_NOMEM;
if( isCreate ){
int iPageSize;
zSql = sqlite3_mprintf("PRAGMA %Q.page_size", pRtree->zDb);
rc = getIntFromStmt(db, zSql, &iPageSize);
if( rc==SQLITE_OK ){
pRtree->iNodeSize = iPageSize-64;
if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
}
}
}else{
zSql = sqlite3_mprintf(
"SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1",
pRtree->zDb, pRtree->zName
);
rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
}
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc!=SQLITE_OK ){
return rc;
}
if( SQLITE_ROW==sqlite3_step(pStmt) ){
*piPageSize = sqlite3_column_int(pStmt, 0);
}
return sqlite3_finalize(pStmt);
return rc;
}
/*
@ -2683,11 +2722,6 @@ static int rtreeInit(
return SQLITE_ERROR;
}
rc = getPageSize(db, argv[1], &iPageSize);
if( rc!=SQLITE_OK ){
return rc;
}
/* Allocate the sqlite3_vtab structure */
nDb = strlen(argv[1]);
nName = strlen(argv[2]);
@ -2706,44 +2740,37 @@ static int rtreeInit(
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
/* Figure out the node size to use. By default, use 64 bytes less than
** the database page-size. This ensures that each node is stored on
** a single database page.
**
** If the databasd page-size is so large that more than RTREE_MAXCELLS
** entries would fit in a single node, use a smaller node-size.
*/
pRtree->iNodeSize = iPageSize-64;
if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
}
/* Figure out the node size to use. */
rc = getNodeSize(db, pRtree, isCreate);
/* Create/Connect to the underlying relational database schema. If
** that is successful, call sqlite3_declare_vtab() to configure
** the r-tree table schema.
*/
if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}else{
char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]);
char *zTmp;
int ii;
for(ii=4; zSql && ii<argc; ii++){
zTmp = zSql;
zSql = sqlite3_mprintf("%s, %s", zTmp, argv[ii]);
sqlite3_free(zTmp);
}
if( zSql ){
zTmp = zSql;
zSql = sqlite3_mprintf("%s);", zTmp);
sqlite3_free(zTmp);
}
if( !zSql ){
rc = SQLITE_NOMEM;
}else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
if( rc==SQLITE_OK ){
if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}else{
char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]);
char *zTmp;
int ii;
for(ii=4; zSql && ii<argc; ii++){
zTmp = zSql;
zSql = sqlite3_mprintf("%s, %s", zTmp, argv[ii]);
sqlite3_free(zTmp);
}
if( zSql ){
zTmp = zSql;
zSql = sqlite3_mprintf("%s);", zTmp);
sqlite3_free(zTmp);
}
if( !zSql ){
rc = SQLITE_NOMEM;
}else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}
sqlite3_free(zSql);
}
sqlite3_free(zSql);
}
if( rc==SQLITE_OK ){

58
ext/rtree/rtree7.test Normal file
View File

@ -0,0 +1,58 @@
# 2010 February 16
#
# 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.
#
#***********************************************************************
#
# Test that nothing goes wrong if an rtree table is created, then the
# database page-size is modified. At one point (3.6.22), this was causing
# malfunctions.
#
if {![info exists testdir]} {
set testdir [file join [file dirname $argv0] .. .. test]
}
source $testdir/tester.tcl
ifcapable !rtree||!vacuum {
finish_test
return
}
do_test rtree7-1.1 {
execsql {
PRAGMA page_size = 1024;
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2, y1, y2);
INSERT INTO rt VALUES(1, 1, 2, 3, 4);
}
} {}
do_test rtree7-1.2 {
execsql { SELECT * FROM rt }
} {1 1.0 2.0 3.0 4.0}
do_test rtree7-1.3 {
execsql {
PRAGMA page_size = 2048;
VACUUM;
SELECT * FROM rt;
}
} {1 1.0 2.0 3.0 4.0}
do_test rtree7-1.4 {
for {set i 2} {$i <= 51} {incr i} {
execsql { INSERT INTO rt VALUES($i, 1, 2, 3, 4) }
}
execsql { SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt }
} {51.0 102.0 153.0 204.0}
do_test rtree7-1.5 {
execsql {
PRAGMA page_size = 512;
VACUUM;
SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt
}
} {51.0 102.0 153.0 204.0}
finish_test

View File

@ -1,8 +1,5 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
C Fix\sthe\sALTER\sTABLE\sRENAME\scommand\sso\sthat\sit\sconverts\sFOREIGN\sKEY\sconstraints\nin\sATTACH-ed\sand\sin\sTEMP\stables\sas\swell\sas\sin\sthe\smain\sdatabase.\nTicket\s[13336e9c3c8c3f].
D 2010-02-15T18:03:20
C Fix\sfor\s[e9a9fde1f4].\sWhen\sopening\san\sexisting\srtree,\sdetermine\sthe\snode\ssize\sby\sinspecting\sthe\sroot\snode\sof\sthe\sr-tree\sstructure\s(instead\sof\sassuming\sit\sis\sa\sfunction\sof\sthe\spage-size).
D 2010-02-16T10:59:41
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in c5827ead754ab32b9585487177c93bb00b9497b3
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -77,7 +74,7 @@ F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33
F ext/icu/icu.c 850e9a36567bbcce6bd85a4b68243cad8e3c2de2
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c 038d59b05783c2e6c927a7352bb118a76c31065a
F ext/rtree/rtree.c b82403b0320a7278e0a0e6562c08c8bba17ee0dd
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
F ext/rtree/rtree1.test f72885ed80a329d6bd7991043016d74b51edf2c5
F ext/rtree/rtree2.test 7b665c44d25e51b3098068d983a39902b2e2d7a1
@ -85,6 +82,7 @@ F ext/rtree/rtree3.test dece988c363368af8c11862995c762071894918f
F ext/rtree/rtree4.test 94fdd570ab5bc47244d87d4590023be43ac786bd
F ext/rtree/rtree5.test 92508f5152a50110af6551fa5b769d1bbd7c4ef3
F ext/rtree/rtree6.test 11aade5311789068ca659be24a47cc0d852b1971
F ext/rtree/rtree7.test 6fd29fb8e13795c822f4ceeea92ab5d61c96976d
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
F ext/rtree/tkt3363.test 2bf324f7908084a5f463de3109db9c6e607feb1b
@ -790,14 +788,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P ec914af32675e472694270d46f3ba2214eb2fe90
R b63197d6039614d907827a453eecec99
U drh
Z 49dfd565a21afaa90179ba63716c3b3a
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
iD8DBQFLeYxroxKgR168RlERAp42AJ9eXZoQAtGar3vAWWJ+ElAji3XDgACfTqUL
/luMg2NSLMumM1Iu2R9tVWU=
=ahs6
-----END PGP SIGNATURE-----
P ab197d0aaf18016ac2dd3674f49bea5f1556451c
R 881d2a8a41b8ae3c95eeef834233ccdb
U dan
Z 64c445e5b0bc8d218abafa630888b286

View File

@ -1 +1 @@
ab197d0aaf18016ac2dd3674f49bea5f1556451c
ebc9433fddf78ef7b4237686951d8d79c1c98f03