]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Do not allow RTree writes when a read cursor is active on the same virtual
authordrh <drh@noemail.net>
Thu, 24 May 2018 22:31:01 +0000 (22:31 +0000)
committerdrh <drh@noemail.net>
Thu, 24 May 2018 22:31:01 +0000 (22:31 +0000)
table, as the writes might rebalance and disrupt the read cursors.  Return
the new SQLITE_LOCKED_VTAB error code if this happens.

FossilOrigin-Name: d4ce66610851c825cb712f985216b63e015c753fdd5521f929c67ad18bfd7664

ext/rtree/rtree.c
ext/rtree/rtree8.test
manifest
manifest.uuid
src/sqlite.h.in

index c4c536f8ce64d5f3d988d3c40a8af7b257f40c9b..54be2f6ced4563cfb81b866222dd219026ee39f1 100644 (file)
@@ -133,6 +133,7 @@ struct Rtree {
   u32 nBusy;                  /* Current number of users of this structure */
   i64 nRowEst;                /* Estimated number of rows in this table */
   u32 nCursor;                /* Number of open cursors */
+  u32 nNodeRef;               /* Number RtreeNodes with positive nRef */
   char *zReadAuxSql;          /* SQL for statement to read aux data */
 
   /* List of nodes removed during a CondenseTree operation. List is
@@ -534,6 +535,7 @@ static int writeInt64(u8 *p, i64 i){
 */
 static void nodeReference(RtreeNode *p){
   if( p ){
+    assert( p->nRef>0 );
     p->nRef++;
   }
 }
@@ -601,6 +603,7 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
     memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize);
     pNode->zData = (u8 *)&pNode[1];
     pNode->nRef = 1;
+    pRtree->nNodeRef++;
     pNode->pParent = pParent;
     pNode->isDirty = 1;
     nodeReference(pParent);
@@ -634,10 +637,10 @@ static int nodeAcquire(
   /* Check if the requested node is already in the hash table. If so,
   ** increase its reference count and return it.
   */
-  if( (pNode = nodeHashLookup(pRtree, iNode)) ){
+  if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
     assert( !pParent || !pNode->pParent || pNode->pParent==pParent );
     if( pParent && !pNode->pParent ){
-      nodeReference(pParent);
+      pParent->nRef++;
       pNode->pParent = pParent;
     }
     pNode->nRef++;
@@ -676,6 +679,7 @@ static int nodeAcquire(
       pNode->pParent = pParent;
       pNode->zData = (u8 *)&pNode[1];
       pNode->nRef = 1;
+      pRtree->nNodeRef++;
       pNode->iNode = iNode;
       pNode->isDirty = 0;
       pNode->pNext = 0;
@@ -716,7 +720,10 @@ static int nodeAcquire(
     }
     *ppNode = pNode;
   }else{
-    sqlite3_free(pNode);
+    if( pNode ){
+      pRtree->nNodeRef--;
+      sqlite3_free(pNode);
+    }
     *ppNode = 0;
   }
 
@@ -813,8 +820,10 @@ static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){
   int rc = SQLITE_OK;
   if( pNode ){
     assert( pNode->nRef>0 );
+    assert( pRtree->nNodeRef>0 );
     pNode->nRef--;
     if( pNode->nRef==0 ){
+      pRtree->nNodeRef--;
       if( pNode->iNode==1 ){
         pRtree->iDepth = -1;
       }
@@ -931,8 +940,9 @@ static void rtreeRelease(Rtree *pRtree){
   pRtree->nBusy--;
   if( pRtree->nBusy==0 ){
     pRtree->inWrTrans = 0;
-    pRtree->nCursor = 0;
+    assert( pRtree->nCursor==0 );
     nodeBlobReset(pRtree);
+    assert( pRtree->nNodeRef==0 );
     sqlite3_finalize(pRtree->pWriteNode);
     sqlite3_finalize(pRtree->pDeleteNode);
     sqlite3_finalize(pRtree->pReadRowid);
@@ -1403,7 +1413,7 @@ static RtreeSearchPoint *rtreeSearchPointNew(
       if( ii<RTREE_CACHE_SZ ){
         assert( pCur->aNode[ii]==0 );
         pCur->aNode[ii] = pCur->aNode[0];
-       }else{
+      }else{
         nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]);
       }
       pCur->aNode[0] = 0;
@@ -2473,7 +2483,7 @@ static int SplitNode(
   }else{
     pLeft = pNode;
     pRight = nodeNew(pRtree, pLeft->pParent);
-    nodeReference(pLeft);
+    pLeft->nRef++;
   }
 
   if( !pLeft || !pRight ){
@@ -2963,6 +2973,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
       rc = reinsertNodeContent(pRtree, pLeaf);
     }
     pRtree->pDeleted = pLeaf->pNext;
+    pRtree->nNodeRef--;
     sqlite3_free(pLeaf);
   }
 
@@ -3067,6 +3078,12 @@ static int rtreeUpdate(
   RtreeCell cell;                 /* New cell to insert if nData>1 */
   int bHaveRowid = 0;             /* Set to 1 after new rowid is determined */
 
+  if( pRtree->nNodeRef ){
+    /* Unable to write to the btree while another cursor is reading from it,
+    ** since the write might do a rebalance which would disrupt the read
+    ** cursor. */
+    return SQLITE_LOCKED_VTAB;
+  }
   rtreeReference(pRtree);
   assert(nData>=1);
 
index ac18fb477d4fbe46de7d43e9e7ee7e062d1cbd7e..84191eef4c6a4d34aa212c8cff46b267d090a0fd 100644 (file)
@@ -38,11 +38,20 @@ do_test rtree8-1.1.1 {
 } {}
 do_test rtree8-1.1.2 {
   set res [list]
-  db eval { SELECT * FROM t1 } { 
-    lappend res $x1 $x2
+  set rc [catch {
+    db eval { SELECT * FROM t1 } { 
+      lappend res $x1 $x2
+      if {$id==3} { db eval { DELETE FROM t1 WHERE id>3 } }
+    }
+  } msg];
+  lappend rc $msg
+  set rc
+} {1 {database table is locked}}
+do_test rtree8-1.1.2b {
+  db eval { SELECT * FROM t1 ORDER BY +id } { 
     if {$id==3} { db eval { DELETE FROM t1 WHERE id>3 } }
   }
-  set res
+  db eval {SELECT x1, x2 FROM t1}
 } {1 3 2 4 3 5}
 do_test rtree8-1.1.3 {
   execsql { SELECT * FROM t1 }
index 02f369cbf6c15a43207adb0e2145eb4048c5c074..2942e21208c2102be99f17452119c43f1fd1d641 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C In\sthe\sOOM\stesting\slogic,\sadd\sthe\ssqlite3FirstFault()\sroutine\sas\sa\splace\sto\nset\sa\sbreakpoint\sthe\sfirst\stime\sany\ssimulated\sOOM\sfault\soccurs\sfor\sa\ssingle\ntest\scase.
-D 2018-05-24T17:38:00.681
+C Do\snot\sallow\sRTree\swrites\swhen\sa\sread\scursor\sis\sactive\son\sthe\ssame\svirtual\ntable,\sas\sthe\swrites\smight\srebalance\sand\sdisrupt\sthe\sread\scursors.\s\sReturn\nthe\snew\sSQLITE_LOCKED_VTAB\serror\scode\sif\sthis\shappens.
+D 2018-05-24T22:31:01.304
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da
@@ -355,7 +355,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782
 F ext/repair/test/checkindex01.test 6945d0ffc0c1dc993b2ce88036b26e0f5d6fcc65da70fc9df27c2647bb358b0f
 F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
-F ext/rtree/rtree.c 148ae743198ca9fe1dfdf2fed74e5c3b0e69330e5b71ddc0d9df9993324dcedc
+F ext/rtree/rtree.c 204ddbb7cfe0aab0136aea8c8b68c24f102d54aa38ccb88f6b4782ad5a5c61c9
 F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
 F ext/rtree/rtree1.test 587889855b26fb8637417921b0709ca843cb6d36db94a882371fd8b7dcc3aa0b
 F ext/rtree/rtree2.test 5f25b01acd03470067a2d52783b2eb0a50bf836803d4342d20ca39e541220fe2
@@ -364,7 +364,7 @@ F ext/rtree/rtree4.test 304de65d484540111b896827e4261815e5dca4ce28eeecd58be648cd
 F ext/rtree/rtree5.test 49c9041d713d54560b315c2c7ef7207ee287eba1b20f8266968a06f2e55d3142
 F ext/rtree/rtree6.test 593e0d36510d5ac1d1fb39b018274ff17604fe8fdca8cf1f8e16559cea1477f4
 F ext/rtree/rtree7.test c8fb2e555b128dd0f0bdb520c61380014f497f8a23c40f2e820acc9f9e4fdce5
-F ext/rtree/rtree8.test 649f5a37ec656028a4a32674b9b1183104285a7625a09d2a8f52a1cef72c93f2
+F ext/rtree/rtree8.test f8aefd8b92f92333ae00b93eca7c197ab24522b219390a337f2a0c62a5d5f96a
 F ext/rtree/rtree9.test c646f12c8c1c68ef015c6c043d86a0c42488e2e68ed1bb1b0771a7ca246cbabf
 F ext/rtree/rtreeA.test 20623ca337ca3bd7e008cc9fb49e44dbe97f1a80b238e10a12bb4afcd0da3776
 F ext/rtree/rtreeB.test 4cec297f8e5c588654bbf3c6ed0903f10612be8a2878055dd25faf8c71758bc9
@@ -496,7 +496,7 @@ F src/resolve.c 6415381a0e9d22c0e7cba33ca4a53f81474190862f5d4838190f5eb5b0b47bc9
 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
 F src/select.c a35d462ee7a3c0856ad7a9d9c8921fbf3d91d911a8f39ad9d61302eb43b24a71
 F src/shell.c.in 51c100206f4b7f86cd9affd80b764825e0edc36ca0190c442e4ca7994611bfe2
-F src/sqlite.h.in ac6aec2abe10585733c1fea06622df5d73f7725c36c6cf054e89affeaccfa42b
+F src/sqlite.h.in e379906b85cc3539c6a37ab972f2c28711b28854a457f54e137d20f75db5db7c
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
 F src/sqliteInt.h 5abdade4744cf3bd567afb65bb144bb3c61f6132f86813b995a5ca79c7b584e8
@@ -1729,7 +1729,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 36cdfbf2ce1811691c790fde3eaeed0238c03b4dc97dc3a20d1e0397520145d1
-R 085dc0bd34d45e9f6435a293683fda7b
+P b4d80bd287ca7f3a6d182ba2435273266035b94fdf6a44047a64a4eff931c571
+R 2c56c09e62f3443ca0fffe92fcd36092
 U drh
-Z 2f994e2ed2922ec0ed95eb384d135eee
+Z 5e9f190f156904a95f9a8ccad0e9448c
index 7278a0f019def3c4116e0c3909cffaa6d3a2ae1f..d73aad0973c3075549aeceaf6bd1f83ec84275bc 100644 (file)
@@ -1 +1 @@
-b4d80bd287ca7f3a6d182ba2435273266035b94fdf6a44047a64a4eff931c571
\ No newline at end of file
+d4ce66610851c825cb712f985216b63e015c753fdd5521f929c67ad18bfd7664
\ No newline at end of file
index 7296597ea356bf132e4c3b16a9c0fc5902e66576..db2619ef5739f8e8f35e3052be5ca48521d2d9ea 100644 (file)
@@ -504,6 +504,7 @@ int sqlite3_exec(
 #define SQLITE_IOERR_COMMIT_ATOMIC     (SQLITE_IOERR | (30<<8))
 #define SQLITE_IOERR_ROLLBACK_ATOMIC   (SQLITE_IOERR | (31<<8))
 #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
+#define SQLITE_LOCKED_VTAB             (SQLITE_LOCKED |  (2<<8))
 #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
 #define SQLITE_BUSY_SNAPSHOT           (SQLITE_BUSY   |  (2<<8))
 #define SQLITE_CANTOPEN_NOTEMPDIR      (SQLITE_CANTOPEN | (1<<8))