]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add tests cases and fix minor issues in the rtreecheck() function.
authordan <dan@noemail.net>
Wed, 25 Oct 2017 18:17:24 +0000 (18:17 +0000)
committerdan <dan@noemail.net>
Wed, 25 Oct 2017 18:17:24 +0000 (18:17 +0000)
FossilOrigin-Name: d6130cd226c0ca95e02f0cbabfdc27071acdcf83e0d0cb0eaa47d992479ed9a1

ext/rtree/rtree.c
ext/rtree/rtreecheck.test
manifest
manifest.uuid

index c7bf671c96492d446a61695ac75909928b68e988..ff15a192a19643a644e42063682bd3678a4a5b0e 100644 (file)
@@ -3659,7 +3659,11 @@ static sqlite3_stmt *rtreeCheckPrepare(
   z = sqlite3_vmprintf(zFmt, ap);
 
   if( pCheck->rc==SQLITE_OK ){
-    pCheck->rc = sqlite3_prepare_v2(pCheck->db, z, -1, &pRet, 0);
+    if( z==0 ){
+      pCheck->rc = SQLITE_NOMEM;
+    }else{
+      pCheck->rc = sqlite3_prepare_v2(pCheck->db, z, -1, &pRet, 0);
+    }
   }
 
   sqlite3_free(z);
@@ -3781,7 +3785,7 @@ static void rtreeCheckMapping(
     );
   }else if( rc==SQLITE_ROW ){
     i64 ii = sqlite3_column_int64(pStmt, 0);
-   if( ii!=iVal ){
+    if( ii!=iVal ){
       rtreeCheckAppendMsg(pCheck, 
           "Found (%lld -> %lld) in %s table, expected (%lld -> %lld)",
           iKey, ii, (bLeaf ? "%_rowid" : "%_parent"), iKey, iVal
@@ -3791,10 +3795,22 @@ static void rtreeCheckMapping(
   rtreeCheckReset(pCheck, pStmt);
 }
 
+/*
+** Argument pCell points to an array of coordinates stored on an rtree page.
+** This function checks that the coordinates are internally consistent (no
+** x1>x2 conditions) and adds an error message to the RtreeCheck object
+** if they are not.
+**
+** Additionally, if pParent is not NULL, then it is assumed to point to
+** the array of coordinates on the parent page that bound the page 
+** containing pCell. In this case it is also verified that the two
+** sets of coordinates are mutually consistent and an error message added
+** to the RtreeCheck object if they are not.
+*/
 static void rtreeCheckCellCoord(
   RtreeCheck *pCheck, 
-  i64 iNode,
-  int iCell,
+  i64 iNode,                      /* Node id to use in error messages */
+  int iCell,                      /* Cell number to use in error messages */
   u8 *pCell,                      /* Pointer to cell coordinates */
   u8 *pParent                     /* Pointer to parent coordinates */
 ){
@@ -3829,6 +3845,14 @@ static void rtreeCheckCellCoord(
   }
 }
 
+/*
+** Run rtreecheck() checks on node iNode, which is at depth iDepth within
+** the r-tree structure. Argument aParent points to the array of coordinates
+** that bound node iNode on the parent node.
+**
+** If any problems are discovered, an error message is appended to the
+** report accumulated in the RtreeCheck object.
+*/
 static void rtreeCheckNode(
   RtreeCheck *pCheck,
   int iDepth,                     /* Depth of iNode (0==leaf) */
@@ -3864,19 +3888,20 @@ static void rtreeCheckNode(
             "Node %lld is too small for cell count of %d (%d bytes)", 
             iNode, nCell, nNode
         );
-      }
-      for(i=0; i<nCell; i++){
-        u8 *pCell = &aNode[4 + i*(8 + pCheck->nDim*2*4)];
-        i64 iVal = readInt64(pCell);
-        rtreeCheckCellCoord(pCheck, iNode, i, &pCell[8], aParent);
-
-        if( iDepth>0 ){
-          rtreeCheckMapping(pCheck, 0, iVal, iNode);
-          rtreeCheckNode(pCheck, iDepth-1, &pCell[8], iVal);
-          pCheck->nNonLeaf++;
-        }else{
-          rtreeCheckMapping(pCheck, 1, iVal, iNode);
-          pCheck->nLeaf++;
+      }else{
+        for(i=0; i<nCell; i++){
+          u8 *pCell = &aNode[4 + i*(8 + pCheck->nDim*2*4)];
+          i64 iVal = readInt64(pCell);
+          rtreeCheckCellCoord(pCheck, iNode, i, &pCell[8], aParent);
+
+          if( iDepth>0 ){
+            rtreeCheckMapping(pCheck, 0, iVal, iNode);
+            rtreeCheckNode(pCheck, iDepth-1, &pCell[8], iVal);
+            pCheck->nNonLeaf++;
+          }else{
+            rtreeCheckMapping(pCheck, 1, iVal, iNode);
+            pCheck->nLeaf++;
+          }
         }
       }
     }
@@ -3884,9 +3909,14 @@ static void rtreeCheckNode(
   }
 }
 
-static void rtreeCheckCount(
-  RtreeCheck *pCheck, const char *zTbl, i64 nExpected
-){
+/*
+** The second argument to this function must be either "_rowid" or
+** "_parent". This function checks that the number of entries in the
+** %_rowid or %_parent table is exactly nExpect. If not, it adds
+** an error message to the report in the RtreeCheck object indicated
+** by the first argument.
+*/
+static void rtreeCheckCount(RtreeCheck *pCheck, const char *zTbl, i64 nExpect){
   if( pCheck->rc==SQLITE_OK ){
     sqlite3_stmt *pCount;
     pCount = rtreeCheckPrepare(pCheck, "SELECT count(*) FROM %Q.'%q%s'",
@@ -3895,9 +3925,9 @@ static void rtreeCheckCount(
     if( pCount ){
       if( sqlite3_step(pCount)==SQLITE_ROW ){
         i64 nActual = sqlite3_column_int64(pCount, 0);
-        if( nActual!=nExpected ){
+        if( nActual!=nExpect ){
           rtreeCheckAppendMsg(pCheck, "Wrong number of entries in %%%s table"
-              " - expected %lld, actual %lld" , zTbl, nExpected, nActual
+              " - expected %lld, actual %lld" , zTbl, nExpect, nActual
           );
         }
       }
@@ -3906,7 +3936,11 @@ static void rtreeCheckCount(
   }
 }
 
-static int rtreeCheck(
+/*
+** This function does the bulk of the work for the rtree integrity-check.
+** It is called by rtreecheck(), which is the SQL function implementation.
+*/
+static int rtreeCheckTable(
   sqlite3 *db,                    /* Database handle to access db through */
   const char *zDb,                /* Name of db ("main", "temp" etc.) */
   const char *zTab,               /* Name of rtree table to check */
@@ -3945,11 +3979,13 @@ static int rtreeCheck(
   }
 
   /* Do the actual integrity-check */
-  if( check.rc==SQLITE_OK ){
-    rtreeCheckNode(&check, 0, 0, 1);
+  if( check.nDim>=1 ){
+    if( check.rc==SQLITE_OK ){
+      rtreeCheckNode(&check, 0, 0, 1);
+    }
+    rtreeCheckCount(&check, "_rowid", check.nLeaf);
+    rtreeCheckCount(&check, "_parent", check.nNonLeaf);
   }
-  rtreeCheckCount(&check, "_rowid", check.nLeaf);
-  rtreeCheckCount(&check, "_parent", check.nNonLeaf);
 
   /* Finalize SQL statements used by the integrity-check */
   sqlite3_finalize(check.pGetNode);
@@ -4018,7 +4054,7 @@ static void rtreecheck(
     }else{
       zTab = (const char*)sqlite3_value_text(apArg[1]);
     }
-    rc = rtreeCheck(sqlite3_context_db_handle(ctx), zDb, zTab, &zReport);
+    rc = rtreeCheckTable(sqlite3_context_db_handle(ctx), zDb, zTab, &zReport);
     if( rc==SQLITE_OK ){
       sqlite3_result_text(ctx, zReport ? zReport : "ok", -1, SQLITE_TRANSIENT);
     }else{
index eb0e8f0acb88213368e7e9e57fb0a6eb27c57b46..cbe8b513c91dbb60a0cc2dcf1c4b335583d45d78 100644 (file)
@@ -35,6 +35,12 @@ proc swap_int32 {blob i0 i1} {
   binary format I* $L
 }
 
+proc set_int32 {blob idx val} {
+  binary scan $blob I* L
+  lset L $idx $val
+  binary format I* $L
+}
+
 do_catchsql_test 1.0 {
   SELECT rtreecheck();
 } {1 {wrong number of arguments to function rtreecheck()}}
@@ -85,7 +91,6 @@ do_execsql_test 2.5 {
   SELECT rtreecheck('r1') 
 } {{Found (3 -> 2) in %_rowid table, expected (3 -> 1)}}
 
-################
 reset_db
 do_execsql_test 3.0 { 
   CREATE VIRTUAL TABLE r1 USING rtree_i32(id, x1, x2);
@@ -101,13 +106,53 @@ do_execsql_test 3.0 {
   SELECT rtreecheck('r1') 
 } {ok}
 
-breakpoint
 do_execsql_test 3.1 { 
   CREATE VIRTUAL TABLE r2 USING rtree_i32(id, x1, x2);
   INSERT INTO r2 VALUES(2, -1*(1<<31), -1*(1<<31)+5);
   SELECT rtreecheck('r2') 
 } {ok}
 
+do_execsql_test 3.2 {
+  BEGIN;
+    UPDATE r2_node SET data = X'123456';
+    SELECT rtreecheck('r2')!="ok";
+} {1}
+
+do_execsql_test 3.3 {
+  ROLLBACK;
+  UPDATE r2_node SET data = X'00001234';
+  SELECT rtreecheck('r2')!="ok";
+} {1}
+
+do_execsql_test 4.0 {
+  CREATE TABLE notanrtree(i);
+  SELECT rtreecheck('notanrtree');
+} {{Schema corrupt or not an rtree}}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+db func set_int32 set_int32
+do_execsql_test 5.0 {
+  CREATE VIRTUAL TABLE r3 USING rtree_i32(id, x1, x2, y1, y2);
+  WITH x(i) AS (
+    SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<1000
+  )
+  INSERT INTO r3 SELECT i, i, i, i, i FROM x;
+}
+do_execsql_test 5.1 {
+  BEGIN;
+    UPDATE r3_node SET data = set_int32(data, 3, 5000);
+    UPDATE r3_node SET data = set_int32(data, 4, 5000);
+    SELECT rtreecheck('r3')=='ok'
+} 0
+do_execsql_test 5.2 {
+  ROLLBACK;
+  BEGIN;
+    UPDATE r3_node SET data = set_int32(data, 3, 0);
+    UPDATE r3_node SET data = set_int32(data, 4, 0);
+    SELECT rtreecheck('r3')=='ok'
+} 0
 
 finish_test
 
index 1b6fc596a8979b17b0369bb75a7704d89713fe80..367a1a1375e6ae0f22673889e3d251c603b224c2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sSQL\sscalar\sfunction\srtreecheck()\sto\sthe\srtree\smodule.\sFor\srunning\schecks\sto\sensure\sthe\sshadow\stables\sused\sby\san\srtree\svirtual\stable\sare\sinternally\sconsistent.
-D 2017-10-25T18:01:58.383
+C Add\stests\scases\sand\sfix\sminor\sissues\sin\sthe\srtreecheck()\sfunction.
+D 2017-10-25T18:17:24.834
 F Makefile.in e016061b23e60ac9ec27c65cb577292b6bde0307ca55abd874ab3487b3b1beb2
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc 37740aba9c4bb359c627eadccf1cfd7be4f5f847078723777ea7763969e533b1
@@ -329,7 +329,7 @@ F ext/rbu/test_rbu.c 7073979b9cc80912bb03599ac8d85ab5d3bf03cfacd3463f2dcdd782299
 F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
 F ext/repair/checkfreelist.c 0abb84b4545016d57ba1a2aa8884c72c73ed838968909858c03bc1f38fb6b054
 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
-F ext/rtree/rtree.c 49ced71763c4bd170ceb0b46ab34c749f3356a8c0e36ce6b9e2f36dc63716609
+F ext/rtree/rtree.c cc91b6905bf55512c6ebc7dfdd37ac81c86f1753db8cfa6d62f0ee864464044f
 F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
 F ext/rtree/rtree1.test 82a353747fcab1083d114b2ac84723dfefdbf86c1a6e1df57bf588c7d4285436
 F ext/rtree/rtree2.test 5f25b01acd03470067a2d52783b2eb0a50bf836803d4342d20ca39e541220fe2
@@ -349,7 +349,7 @@ F ext/rtree/rtreeF.test 81ffa7ef51c4e4618d497a57328c265bf576990c7070633b623b23cd
 F ext/rtree/rtreeG.test fd3af1ca944a0bdb0cbb5455a4905c9f012e2fffcab6b791f07afa0dcbbcae0e
 F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
 F ext/rtree/rtree_util.tcl db734b4c5e75fed6acc56d9701f2235345acfdec750b5fc7b587936f5f6bceed
-F ext/rtree/rtreecheck.test f610cb77ca1ba611e656018a7d960cd46054baecd2f12d1149bf1fec121aa230
+F ext/rtree/rtreecheck.test 4d29103d1e16fcbf90135d1c637b833688492b063b2971dfb5dc6ba76555cfee
 F ext/rtree/rtreeconnect.test 225ad3fcb483d36cbee423a25052a6bbae762c9576ae9268332360c68c170d3d
 F ext/rtree/sqlite3rtree.h 9c5777af3d2921c7b4ae4954e8e5697502289d28
 F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
@@ -1666,8 +1666,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P adfa7ed2de3e833fff65935455e71236a59602aaf7b97ece667ab300dca9f673 61870b42b033189509b244c76d28932f7a447b887ffe04a3c81461148e54cfb5
-R bbf1f0574f080f1a74b750b54fc22d8d
-T +closed 61870b42b033189509b244c76d28932f7a447b887ffe04a3c81461148e54cfb5
-U mistachkin
-Z cbebd749084c1ed38ad0d901e97967c8
+P 7d26498063bbc4525976ace698fafcf161d939908f4ffb36d7a4df8fb1bce1fb
+R b18b38b834db7af5e4754d71c435762f
+U dan
+Z f91c79bfd0a67ab59612bc897b82c53b
index 74306142d265a516755999f1c2eb343d03457348..cb99ca30c6a9fe5634d346e3d8655e679de19bbc 100644 (file)
@@ -1 +1 @@
-7d26498063bbc4525976ace698fafcf161d939908f4ffb36d7a4df8fb1bce1fb
\ No newline at end of file
+d6130cd226c0ca95e02f0cbabfdc27071acdcf83e0d0cb0eaa47d992479ed9a1
\ No newline at end of file