]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Test cases to improve coverage of rtree module. Fixes associated with the same.
authordan <dan@noemail.net>
Wed, 25 Aug 2010 17:53:17 +0000 (17:53 +0000)
committerdan <dan@noemail.net>
Wed, 25 Aug 2010 17:53:17 +0000 (17:53 +0000)
FossilOrigin-Name: 865cec04e4d814f63fb71feb67de7f06f8d54035

ext/rtree/rtree.c
ext/rtree/rtree2.test
ext/rtree/rtree3.test
ext/rtree/rtree4.test
ext/rtree/rtree8.test [new file with mode: 0644]
manifest
manifest.uuid

index a0b45bbc788f236fb9df3782658d8316aba16b90..c8e4ea23073344eb7ca3a00e4d381b1d154cc5cd 100644 (file)
@@ -53,6 +53,9 @@
   #define AssignCells splitNodeStartree
 #endif
 
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) 
+# define NDEBUG 1
+#endif
 
 #ifndef SQLITE_CORE
   #include "sqlite3ext.h"
@@ -306,10 +309,8 @@ static void nodeReference(RtreeNode *p){
 ** Clear the content of node p (set all bytes to 0x00).
 */
 static void nodeZero(Rtree *pRtree, RtreeNode *p){
-  if( p ){
-    memset(&p->zData[2], 0, pRtree->iNodeSize-2);
-    p->isDirty = 1;
-  }
+  memset(&p->zData[2], 0, pRtree->iNodeSize-2);
+  p->isDirty = 1;
 }
 
 /*
@@ -338,13 +339,11 @@ static RtreeNode *nodeHashLookup(Rtree *pRtree, i64 iNode){
 ** Add node pNode to the node hash table.
 */
 static void nodeHashInsert(Rtree *pRtree, RtreeNode *pNode){
-  if( pNode ){
-    int iHash;
-    assert( pNode->pNext==0 );
-    iHash = nodeHash(pNode->iNode);
-    pNode->pNext = pRtree->aHash[iHash];
-    pRtree->aHash[iHash] = pNode;
-  }
+  int iHash;
+  assert( pNode->pNext==0 );
+  iHash = nodeHash(pNode->iNode);
+  pNode->pNext = pRtree->aHash[iHash];
+  pRtree->aHash[iHash] = pNode;
 }
 
 /*
@@ -366,11 +365,11 @@ static void nodeHashDelete(Rtree *pRtree, RtreeNode *pNode){
 ** assigned a node number when nodeWrite() is called to write the
 ** node contents out to the database.
 */
-static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent, int zero){
+static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
   RtreeNode *pNode;
   pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize);
   if( pNode ){
-    memset(pNode, 0, sizeof(RtreeNode) + (zero?pRtree->iNodeSize:0));
+    memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize);
     pNode->zData = (u8 *)&pNode[1];
     pNode->nRef = 1;
     pNode->pParent = pParent;
@@ -434,7 +433,7 @@ nodeAcquire(
   *ppNode = pNode;
   rc = sqlite3_reset(pRtree->pReadNode);
 
-  if( rc==SQLITE_OK && iNode==1 ){
+  if( pNode && iNode==1 ){
     pRtree->iDepth = readInt16(pNode->zData);
   }
 
@@ -762,9 +761,15 @@ static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor){
     );
 
     switch( p->op ){
-      case RTREE_LE: case RTREE_LT: bRes = p->rValue<cell_min; break;
-      case RTREE_GE: case RTREE_GT: bRes = p->rValue>cell_max; break;
-      case RTREE_EQ: 
+      case RTREE_LE: case RTREE_LT: 
+        bRes = p->rValue<cell_min; 
+        break;
+
+      case RTREE_GE: case RTREE_GT: 
+        bRes = p->rValue>cell_max; 
+        break;
+
+      default: assert( p->op==RTREE_EQ );
         bRes = (p->rValue>cell_max || p->rValue<cell_min);
         break;
     }
@@ -797,7 +802,7 @@ static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor){
       case RTREE_LT: res = (coord<p->rValue);  break;
       case RTREE_GE: res = (coord>=p->rValue); break;
       case RTREE_GT: res = (coord>p->rValue);  break;
-      case RTREE_EQ: res = (coord==p->rValue); break;
+      default:       res = (coord==p->rValue); break;
     }
 
     if( !res ) return 1;
@@ -900,13 +905,17 @@ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){
   RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
   int rc = SQLITE_OK;
 
+  /* RtreeCursor.pNode must not be NULL. If is is NULL, then this cursor is
+  ** already at EOF. It is against the rules to call the xNext() method of
+  ** a cursor that has already reached EOF.
+  */
+  assert( pCsr->pNode );
+
   if( pCsr->iStrategy==1 ){
     /* This "scan" is a direct lookup by rowid. There is no next entry. */
     nodeRelease(pRtree, pCsr->pNode);
     pCsr->pNode = 0;
-  }
-
-  else if( pCsr->pNode ){
+  }else{
     /* Move to the next entry that matches the configured constraints. */
     int iHeight = 0;
     while( pCsr->pNode ){
@@ -1016,7 +1025,8 @@ static int rtreeFilter(
     i64 iRowid = sqlite3_value_int64(argv[0]);
     rc = findLeafNode(pRtree, iRowid, &pLeaf);
     pCsr->pNode = pLeaf; 
-    if( pLeaf && rc==SQLITE_OK ){
+    if( pLeaf ){
+      assert( rc==SQLITE_OK );
       pCsr->iCell = nodeRowidIndex(pRtree, pLeaf, iRowid);
     }
   }else{
@@ -1272,7 +1282,12 @@ static float cellOverlap(
   int ii;
   float overlap = 0.0;
   for(ii=0; ii<nCell; ii++){
-    if( ii!=iExclude ){
+#if VARIANT_RSTARTREE_CHOOSESUBTREE
+    if( ii!=iExclude )
+#else
+    assert( iExclude==-1 );
+#endif
+    {
       int jj;
       float o = 1.0;
       for(jj=0; jj<(pRtree->nDim*2); jj+=2){
@@ -1365,22 +1380,31 @@ static int ChooseLeaf(
     ** the smallest area.
     */
     for(iCell=0; iCell<nCell; iCell++){
+      int bBest = 0;
       float growth;
       float area;
       float overlap = 0.0;
       nodeGetCell(pRtree, pNode, iCell, &cell);
       growth = cellGrowth(pRtree, &cell, pCell);
       area = cellArea(pRtree, &cell);
+
 #if VARIANT_RSTARTREE_CHOOSESUBTREE
       if( ii==(pRtree->iDepth-1) ){
         overlap = cellOverlapEnlargement(pRtree,&cell,pCell,aCell,nCell,iCell);
       }
-#endif
       if( (iCell==0) 
        || (overlap<fMinOverlap) 
        || (overlap==fMinOverlap && growth<fMinGrowth)
        || (overlap==fMinOverlap && growth==fMinGrowth && area<fMinArea)
       ){
+        bBest = 1;
+      }
+#else
+      if( iCell==0||growth<fMinGrowth||(growth==fMinGrowth && area<fMinArea) ){
+        bBest = 1;
+      }
+#endif
+      if( bBest ){
         fMinOverlap = overlap;
         fMinGrowth = growth;
         fMinArea = area;
@@ -1950,14 +1974,14 @@ static int SplitNode(
   nCell++;
 
   if( pNode->iNode==1 ){
-    pRight = nodeNew(pRtree, pNode, 1);
-    pLeft = nodeNew(pRtree, pNode, 1);
+    pRight = nodeNew(pRtree, pNode);
+    pLeft = nodeNew(pRtree, pNode);
     pRtree->iDepth++;
     pNode->isDirty = 1;
     writeInt16(pNode->zData, pRtree->iDepth);
   }else{
     pLeft = pNode;
-    pRight = nodeNew(pRtree, pLeft->pParent, 1);
+    pRight = nodeNew(pRtree, pLeft->pParent);
     nodeReference(pLeft);
   }
 
@@ -2358,7 +2382,9 @@ static int rtreeUpdate(
   rtreeReference(pRtree);
 
   assert(nData>=1);
+#if 0
   assert(hashIsEmpty(pRtree));
+#endif
 
   /* If azData[0] is not an SQL NULL value, it is the rowid of a
   ** record to delete from the r-tree table. The following block does
index 307e7e0208d29ca28f32ca0e53172645db3c28be..4ffa88034806bb83c816a30c9a3477edce8cd490 100644 (file)
@@ -27,7 +27,7 @@ set ::NROW   1000
 set ::NDEL     10
 set ::NSELECT 100
 
-if {[info exists ISQUICK] && $ISQUICK} {
+if {[info exists G(isquick)] && $G(isquick)} {
   set ::NROW 100
   set ::NSELECT 10
 }
index 1ce131c53aeb329039da1f8a6158349d2df9c53d..5076908f916bdc1d709fd99a5cb68feed295ed91 100644 (file)
@@ -17,6 +17,7 @@ if {![info exists testdir]} {
   set testdir [file join [file dirname $argv0] .. .. test]
 } 
 source $testdir/tester.tcl
+source $testdir/malloc_common.tcl
 
 ifcapable !rtree {
   finish_test
@@ -32,34 +33,61 @@ if {!$MEMDEBUG} {
    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;
-} 
+if 1 {
+
+do_faultsim_test rtree3-1 -faults oom* -prep {
+  faultsim_delete_and_reopen
+} -body {
+  execsql {
+    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_test rtree3-2.prep {
+  faultsim_delete_and_reopen
+  execsql {
+    CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2);
+    INSERT INTO rt VALUES(NULL, 3, 5, 7, 9);
+  }
+  faultsim_save_and_close
+} {}
+do_faultsim_test rtree3-2 -faults oom* -prep {
+  faultsim_restore_and_reopen
+} -body {
+  execsql { DROP TABLE rt } 
+}
+
+do_malloc_test rtree3-3.prep {
+  faultsim_delete_and_reopen
+  execsql {
+    CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2);
+    INSERT INTO rt VALUES(NULL, 3, 5, 7, 9);
+  }
+  faultsim_save_and_close
+} {}
 
-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 {
+do_faultsim_test rtree3-3a -faults oom* -prep {
+  faultsim_restore_and_reopen
+} -body {
   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
+}
+faultsim_save_and_close
+
+do_faultsim_test rtree3-3b -faults oom* -prep {
+  faultsim_restore_and_reopen
+} -body {
   db eval BEGIN
   for {set ii 0} {$ii < 100} {incr ii} {
     set f [expr rand()]
@@ -68,4 +96,28 @@ do_malloc_test rtree3-3 -sqlprep {
   db eval COMMIT
 } 
 
+}
+
+do_test rtree3-4.prep {
+  faultsim_delete_and_reopen
+  execsql {
+    BEGIN;
+    PRAGMA page_size = 512;
+    CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2);
+  }
+  for {set i 0} {$i < 1500} {incr i} {
+    execsql { INSERT INTO rt VALUES($i, $i, $i+1, $i, $i+1) }
+  }
+  execsql { COMMIT }
+  faultsim_save_and_close
+} {}
+
+do_faultsim_test rtree3-4 -faults oom-transient -prep {
+  faultsim_restore_and_reopen
+} -body {
+  db eval { SELECT count(*) FROM rt }
+} -test {
+  faultsim_test_result {0 1500}
+}
+
 finish_test
index fa0d606faf07be77dddcb1f6f0e40b80c96b6e9a..715473bf024f7a1d596498a9dbf0d8f49167942f 100644 (file)
@@ -23,7 +23,7 @@ ifcapable !rtree {
 }
 
 set ::NROW 2500
-if {[info exists ISQUICK] && $ISQUICK} {
+if {[info exists G(isquick)] && $G(isquick)} {
   set ::NROW 250
 }
 
diff --git a/ext/rtree/rtree8.test b/ext/rtree/rtree8.test
new file mode 100644 (file)
index 0000000..e48dc12
--- /dev/null
@@ -0,0 +1,126 @@
+# 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.
+#
+#***********************************************************************
+# 
+#
+
+if {![info exists testdir]} {
+  set testdir [file join [file dirname $argv0] .. .. test]
+} 
+source $testdir/tester.tcl
+ifcapable !rtree { finish_test ; return }
+
+#-------------------------------------------------------------------------
+# The following block of tests - rtree8-1.* - feature reading and writing
+# an r-tree table while there exist open cursors on it.
+#
+proc populate_t1 {n} {
+  execsql { DELETE FROM t1 }
+  for {set i 1} {$i <= $n} {incr i} {
+    execsql { INSERT INTO t1 VALUES($i, $i, $i+2) }
+  }
+}
+
+# A DELETE while a cursor is reading the table.
+#
+do_test rtree8-1.1.1 {
+  execsql { PRAGMA page_size = 512 }
+  execsql { CREATE VIRTUAL TABLE t1 USING rtree_i32(id, x1, x2) }
+  populate_t1 5
+} {}
+do_test rtree8-1.1.2 {
+  set res [list]
+  db eval { SELECT * FROM t1 } { 
+    lappend res $x1 $x2
+    if {$id==3} { db eval { DELETE FROM t1 WHERE id>3 } }
+  }
+  set res
+} {1 3 2 4 3 5}
+do_test rtree8-1.1.3 {
+  execsql { SELECT * FROM t1 }
+} {1 1 3 2 2 4 3 3 5}
+
+# Many SELECTs on the same small table.
+#
+proc nested_select {n} {
+  set ::max $n
+  db eval { SELECT * FROM t1 } {
+    if {$id == $n} { nested_select [expr $n+1] }
+  }
+  return $::max
+}
+do_test rtree8-1.2.1 { populate_t1 50  } {}
+do_test rtree8-1.2.2 { nested_select 1 } {51}
+
+# This test runs many SELECT queries simultaneously against a large 
+# table, causing a collision in the hash-table used to store r-tree 
+# nodes internally.
+#
+populate_t1 1500
+do_execsql_test rtree8-1.3.1 { SELECT max(nodeno) FROM t1_node } {164}
+do_test rtree8-1.3.2 {
+  set rowids [execsql {SELECT min(rowid) FROM t1_rowid GROUP BY nodeno}]
+  set stmt_list [list]
+  foreach row $rowids {
+    set stmt [sqlite3_prepare db "SELECT * FROM t1 WHERE id = $row" -1 tail]
+    sqlite3_step $stmt
+    lappend res_list [sqlite3_column_int $stmt 0]
+    lappend stmt_list $stmt 
+  }
+} {}
+do_test rtree8-1.3.3 { set res_list } $rowids
+do_execsql_test rtree8-1.3.4 { SELECT count(*) FROM t1 } {1500}
+do_test rtree8-1.3.5 { 
+  foreach stmt $stmt_list { sqlite3_finalize $stmt }
+} {}
+
+
+#-------------------------------------------------------------------------
+# The following block of tests - rtree8-2.* - test a couple of database
+# corruption cases. In this case things are not corrupted at the b-tree
+# level, but the contents of the various tables used internally by an
+# r-tree table are inconsistent.
+#
+populate_t1 50
+do_execsql_test rtree8-2.1.1 { SELECT max(nodeno) FROM t1_node } {5}
+do_execsql_test rtree8-2.1.2 { DELETE FROM t1_node } {}
+for {set i 1} {$i <= 50} {incr i} {
+  do_catchsql_test rtree8-2.1.3.$i { 
+    SELECT * FROM t1 WHERE id = $i 
+  } {1 {database disk image is malformed}}
+}
+do_catchsql_test rtree8-2.1.4 { 
+  SELECT * FROM t1
+} {1 {database disk image is malformed}}
+do_catchsql_test rtree8-2.1.5 { 
+  DELETE FROM t1
+} {1 {database disk image is malformed}}
+
+do_execsql_test rtree8-2.1.6 { 
+  DELETE FROM t1_node;
+  DELETE FROM t1_parent;
+  DELETE FROM t1_rowid;
+  DROP TABLE t1;
+  CREATE VIRTUAL TABLE t1 USING rtree_i32(id, x1, x2);
+} {}
+
+#-------------------------------------------------------------------------
+# Test that trying to use the MATCH operator with the r-tree module does
+# not confuse it.
+#
+breakpoint
+populate_t1 10
+do_catchsql_test rtree8-3.1 { 
+  SELECT * FROM t1 WHERE x1 MATCH '1234'
+} {1 {}}
+
+
+finish_test
+
index 688fdc247e2f27a5d9166f8b52a69daa533523c8..ed16861ae11ffaab440cb65715ae4c61aa3bf359 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Replicate\sasserts\son\sunixOpen()\sto\swinOpen()\sin\sos_win.c.
-D 2010-08-24T20:46:53
+C Test\scases\sto\simprove\scoverage\sof\srtree\smodule.\sFixes\sassociated\swith\sthe\ssame.
+D 2010-08-25T17:53:17
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 543f91f24cd7fee774ecc0a61c19704c0c3e78fd
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -78,15 +78,16 @@ F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
 F ext/icu/icu.c 850e9a36567bbcce6bd85a4b68243cad8e3c2de2
 F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
-F ext/rtree/rtree.c 1a39ad566196d2342f4a5ef337e165b7a016e6cd
+F ext/rtree/rtree.c 73a4df9b61bfdb39e29d9d8a9927d811bb0f3389
 F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
 F ext/rtree/rtree1.test 51bb0cd0405970501e63258401ae5ad235a4f468
-F ext/rtree/rtree2.test 7b665c44d25e51b3098068d983a39902b2e2d7a1
-F ext/rtree/rtree3.test dece988c363368af8c11862995c762071894918f
-F ext/rtree/rtree4.test 94fdd570ab5bc47244d87d4590023be43ac786bd
+F ext/rtree/rtree2.test 47b90f549a59e667e9fb01338956ead6f66c8d9d
+F ext/rtree/rtree3.test 5ffcb3f44fe925e7a2e6e1960f3d2bf628683db3
+F ext/rtree/rtree4.test 2adce44dc544f6eb570898c8d5270bdf6ca64bd8
 F ext/rtree/rtree5.test 92508f5152a50110af6551fa5b769d1bbd7c4ef3
 F ext/rtree/rtree6.test 903720aaab819764c3693aaac0affe8174104ac8
 F ext/rtree/rtree7.test 6fd29fb8e13795c822f4ceeea92ab5d61c96976d
+F ext/rtree/rtree8.test d226534180f063924ee9d5500d43aebaeba28c7e
 F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
 F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
 F ext/rtree/tkt3363.test 2bf324f7908084a5f463de3109db9c6e607feb1b
@@ -846,7 +847,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P d1ed743b6ed07ad0ee7d466932c5a83caa9489ee
-R 4de3851ce739f58f5ec292f30759a537
-U shaneh
-Z b2eb9e260c96bf7904a512bfdbfae9ac
+P 40526d8390896ccb883c45afa70e7adb568d174f
+R 34bbfc350aec51a2c8611327e89641b5
+U dan
+Z ca03a4a4ecb8f93f6b9fcda928df5c52
index 401d4c42d5aa07252c31c3a1b7764db2dae538bc..6c1567bfc0305e116c8995bfef94222791fb5ab2 100644 (file)
@@ -1 +1 @@
-40526d8390896ccb883c45afa70e7adb568d174f
\ No newline at end of file
+865cec04e4d814f63fb71feb67de7f06f8d54035
\ No newline at end of file