]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix for [e9a9fde1f4]. When opening an existing rtree, determine the node size by...
authordan <dan@noemail.net>
Tue, 16 Feb 2010 10:59:40 +0000 (10:59 +0000)
committerdan <dan@noemail.net>
Tue, 16 Feb 2010 10:59:40 +0000 (10:59 +0000)
FossilOrigin-Name: ebc9433fddf78ef7b4237686951d8d79c1c98f03

ext/rtree/rtree.c
ext/rtree/rtree7.test [new file with mode: 0644]
manifest
manifest.uuid

index 49c00a35bd0e43b1e1361bcf2b2ee725a6d1dce6..90a9595405ad7b951fe874abed1e6e99eadb2fa6 100644 (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;
-  char *zSql;
-  sqlite3_stmt *pStmt = 0;
-
-  zSql = sqlite3_mprintf("PRAGMA %Q.page_size", zDb);
-  if( !zSql ){
-    return 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;
+}
 
-  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
-  sqlite3_free(zSql);
-  if( rc!=SQLITE_OK ){
-    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;
+  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);
   }
 
-  if( SQLITE_ROW==sqlite3_step(pStmt) ){
-    *piPageSize = sqlite3_column_int(pStmt, 0);
-  }
-  return sqlite3_finalize(pStmt);
+  sqlite3_free(zSql);
+  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 ){
diff --git a/ext/rtree/rtree7.test b/ext/rtree/rtree7.test
new file mode 100644 (file)
index 0000000..5939afd
--- /dev/null
@@ -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
index ff847cc77c359b20c19c0f192dbfd2bbadb74565..c7e7aebcd9f0a7a9cfd072b8aade5bff2f2072ef 100644 (file)
--- a/manifest
+++ b/manifest
@@ -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
index 2f6721b605c0c859195af27c5fada0657d520d66..c100d6117a4047528750584d2b41c16cd4881f36 100644 (file)
@@ -1 +1 @@
-ab197d0aaf18016ac2dd3674f49bea5f1556451c
\ No newline at end of file
+ebc9433fddf78ef7b4237686951d8d79c1c98f03
\ No newline at end of file