]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix RBU so that it does not write rows that should be excluded into partial indexes...
authordan <dan@noemail.net>
Thu, 11 Apr 2019 16:54:20 +0000 (16:54 +0000)
committerdan <dan@noemail.net>
Thu, 11 Apr 2019 16:54:20 +0000 (16:54 +0000)
FossilOrigin-Name: 31eb27f438ad727b095a518bfe0f7ed37cb806fc1e6929b821eddcc6cc9de260

ext/rbu/rbupartial.test [new file with mode: 0644]
ext/rbu/sqlite3rbu.c
manifest
manifest.uuid

diff --git a/ext/rbu/rbupartial.test b/ext/rbu/rbupartial.test
new file mode 100644 (file)
index 0000000..3cb076f
--- /dev/null
@@ -0,0 +1,86 @@
+# 2019 April 11
+#
+# 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.
+#
+#***********************************************************************
+#
+
+source [file join [file dirname [info script]] rbu_common.tcl]
+set ::testprefix rbupartial
+
+db close
+sqlite3_shutdown
+sqlite3_config_uri 1
+
+foreach {tn without_rowid a b c d} {
+  1 ""              a b c d
+  2 "WITHOUT ROWID" aaa bbb ccc ddd
+  3 "WITHOUT ROWID" "\"hello\"" {"one'two"}  {[c]} ddd
+  4 "WITHOUT ROWID" {`a b`} {"one'two"}  {[c c c]} ddd
+  5 "" a b c {"d""d"}
+  6 "" {'one''two'} b {"c""c"} {"d""d"}
+} {
+  eval [string map [list \
+    %WITHOUT_ROWID% $without_rowid %A% $a %B% $b %C% $c %D% $d
+  ] {
+  reset_db
+  do_execsql_test $tn.1.0 {
+    CREATE TABLE t1(%A% PRIMARY KEY, %B%, %C%, %D%) %WITHOUT_ROWID% ;
+    CREATE INDEX i1b  ON t1(%B%);
+    CREATE INDEX i1b2 ON t1(%B%) WHERE %C%<5;
+    CREATE INDEX i1b3 ON t1(%B%) WHERE %C%>=5;
+
+    CREATE INDEX i1c  ON t1(%C%);
+    CREATE INDEX i1c2 ON t1(%C%) WHERE %C% IS NULL;
+    CREATE INDEX i1c3 ON t1(%C%) WHERE %C% IS NOT NULL;
+
+    CREATE INDEX i1c4 ON t1(%C%) WHERE %D% < 'd';
+  }
+
+  do_execsql_test $tn.1.1 {
+    INSERT INTO t1 VALUES(0, NULL, NULL, 'a');
+    INSERT INTO t1 VALUES(1, 2, 3, 'b');
+    INSERT INTO t1 VALUES(4, 5, 6, 'c');
+    INSERT INTO t1 VALUES(7, 8, 9, 'd');
+  }
+
+  forcedelete rbu.db
+  do_test $tn.1.2 {
+    sqlite3 rbu rbu.db
+    rbu eval {
+      CREATE TABLE data_t1(%A%, %B%, %C%, %D%, rbu_control);
+
+      INSERT INTO data_t1 VALUES(10, 11, 12, 'e', 0);
+      INSERT INTO data_t1 VALUES(13, 14, NULL, 'f', 0);
+
+      INSERT INTO data_t1 VALUES(0, NULL, NULL, NULL, 1);
+      INSERT INTO data_t1 VALUES(4, NULL, NULL, NULL, 1);
+
+      INSERT INTO data_t1 VALUES(7, NULL, 4, NULL, '..x.');
+      INSERT INTO data_t1 VALUES(1, 10, NULL, NULL, '.xx.');
+    }
+    rbu close
+  } {}
+
+  do_test $tn.1.3 {
+    run_rbu test.db rbu.db
+    execsql { PRAGMA integrity_check }
+  } {ok}
+
+  do_execsql_test $tn.1.4 {
+    SELECT * FROM t1 ORDER BY %A%;
+  } {
+    1 10 {} b   7 8 4 d   10 11 12 e   13 14 {} f
+  }
+
+  set step 0
+  do_rbu_vacuum_test $tn.1.5 0
+  }]
+}
+
+finish_test
index 1a78adc851eb6ad4456016932b7154e644f0dcde..198ed8ab27f1a768b65262a5af0610369fcf141a 100644 (file)
@@ -240,6 +240,11 @@ struct RbuUpdateStmt {
 **   it points to an array of flags nTblCol elements in size. The flag is
 **   set for each column that is either a part of the PK or a part of an
 **   index. Or clear otherwise.
+**
+**   If there are one or more partial indexes on the table, all fields of
+**   this array set set to 1. This is because in that case, the module has
+**   no way to tell which fields will be required to add and remove entries
+**   from the partial indexes.
 **   
 */
 struct RbuObjIter {
@@ -1250,8 +1255,12 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
   pIter->nIndex = 0;
   while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){
     const char *zIdx = (const char*)sqlite3_column_text(pList, 1);
+    int bPartial = sqlite3_column_int(pList, 4);
     sqlite3_stmt *pXInfo = 0;
     if( zIdx==0 ) break;
+    if( bPartial ){
+      memset(pIter->abIndexed, 0x01, sizeof(u8)*pIter->nTblCol);
+    }
     p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
         sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
     );
@@ -1958,6 +1967,62 @@ static void rbuTmpInsertFunc(
   }
 }
 
+static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){
+  sqlite3_stmt *pStmt = 0;
+  int rc = p->rc;
+  char *zRet = 0;
+
+  if( rc==SQLITE_OK ){
+    rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
+        "SELECT trim(sql) FROM sqlite_master WHERE type='index' AND name=?"
+    );
+  }
+  if( rc==SQLITE_OK ){
+    int rc2;
+    rc = sqlite3_bind_text(pStmt, 1, pIter->zIdx, -1, SQLITE_STATIC);
+    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+      const char *zSql = (const char*)sqlite3_column_text(pStmt, 0);
+      if( zSql ){
+        int nParen = 0;           /* Number of open parenthesis */
+        int i;
+        for(i=0; zSql[i]; i++){
+          char c = zSql[i];
+          if( c=='(' ){
+            nParen++;
+          }
+          else if( c==')' ){
+            nParen--;
+            if( nParen==0 ){
+              i++;
+              break;
+            }
+          }else if( c=='"' || c=='\'' || c=='`' ){
+            for(i++; 1; i++){
+              if( zSql[i]==c ){
+                if( zSql[i+1]!=c ) break;
+                i++;
+              }
+            }
+          }else if( c=='[' ){
+            for(i++; 1; i++){
+              if( zSql[i]==']' ) break;
+            }
+          }
+        }
+        if( zSql[i] ){
+          zRet = rbuStrndup(&zSql[i], &rc);
+        }
+      }
+    }
+
+    rc2 = sqlite3_finalize(pStmt);
+    if( rc==SQLITE_OK ) rc = rc2;
+  }
+
+  p->rc = rc;
+  return zRet;
+}
+
 /*
 ** Ensure that the SQLite statement handles required to update the 
 ** target database object currently indicated by the iterator passed 
@@ -1987,6 +2052,7 @@ static int rbuObjIterPrepareAll(
       char *zImposterPK = 0;      /* Primary key declaration for imposter */
       char *zWhere = 0;           /* WHERE clause on PK columns */
       char *zBind = 0;
+      char *zPart = 0;
       int nBind = 0;
 
       assert( pIter->eType!=RBU_PK_VTAB );
@@ -1994,6 +2060,7 @@ static int rbuObjIterPrepareAll(
           p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind
       );
       zBind = rbuObjIterGetBindlist(p, nBind);
+      zPart = rbuObjIterGetIndexWhere(p, pIter);
 
       /* Create the imposter table used to write to this index. */
       sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1);
@@ -2026,28 +2093,30 @@ static int rbuObjIterPrepareAll(
         char *zSql;
         if( rbuIsVacuum(p) ){
           zSql = sqlite3_mprintf(
-              "SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s",
+              "SELECT %s, 0 AS rbu_control FROM '%q' %s ORDER BY %s%s",
               zCollist, 
               pIter->zDataTbl,
-              zCollist, zLimit
+              zPart, zCollist, zLimit
           );
         }else
 
         if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
           zSql = sqlite3_mprintf(
-              "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' ORDER BY %s%s",
+              "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s ORDER BY %s%s",
               zCollist, p->zStateDb, pIter->zDataTbl,
-              zCollist, zLimit
+              zPart, zCollist, zLimit
           );
         }else{
           zSql = sqlite3_mprintf(
-              "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
+              "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s "
               "UNION ALL "
               "SELECT %s, rbu_control FROM '%q' "
-              "WHERE typeof(rbu_control)='integer' AND rbu_control!=1 "
+              "%s %s typeof(rbu_control)='integer' AND rbu_control!=1 "
               "ORDER BY %s%s",
-              zCollist, p->zStateDb, pIter->zDataTbl, 
+              zCollist, p->zStateDb, pIter->zDataTbl, zPart,
               zCollist, pIter->zDataTbl, 
+              zPart,
+              (zPart ? "AND" : "WHERE"),
               zCollist, zLimit
           );
         }
@@ -2058,6 +2127,7 @@ static int rbuObjIterPrepareAll(
       sqlite3_free(zImposterPK);
       sqlite3_free(zWhere);
       sqlite3_free(zBind);
+      sqlite3_free(zPart);
     }else{
       int bRbuRowid = (pIter->eType==RBU_PK_VTAB)
                     ||(pIter->eType==RBU_PK_NONE)
index 00c17f7cd6eff2a27e371d338253449f63917aa6..a6326e39c7712e807888d532cd2c2f1f3840adb1 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Update\sthe\slist\sof\sOMIT\soptions\sin\sthe\somittest.tcl\sscript.
-D 2019-04-10T18:29:40.308
+C Fix\sRBU\sso\sthat\sit\sdoes\snot\swrite\srows\sthat\sshould\sbe\sexcluded\sinto\spartial\sindexes\s(corrupting\sthe\sdatabase).
+D 2019-04-11T16:54:20.888
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -349,6 +349,7 @@ F ext/rbu/rbufault3.test e0052ccba428ffdd2bb989d3ae84716f058ec5ab5f7196c64ba407b
 F ext/rbu/rbufault4.test 03d2849c3df7d7bd14a622e789ff049e5080edd34a79cd432e01204db2a5930a
 F ext/rbu/rbufts.test 0ae8d1da191c75bd776b86e24456db0fb6e97b7c944259fae5407ea55d23c31d
 F ext/rbu/rbumulti.test 5fb139058f37ddc5a113c5b93238de915b769b7792de41b44c983bc7c18cf5b9
+F ext/rbu/rbupartial.test 73baf12a5941fe6891a829106a6f2e0a973f89aa49bd8659b12f547beb29b482
 F ext/rbu/rbuprogress.test 04614ff8820bab9c1ec1b7dbec1edc4b45474421d4fe7abbd2a879a9c02884f9
 F ext/rbu/rburesume.test dbdc4ca504e9c76375a69e5f0d91205db967dcc509a5166ca80231f8fda49eb1
 F ext/rbu/rbusave.test f4190a1a86fccf84f723af5c93813365ae33feda35845ba107b59683d1cdd926
@@ -357,7 +358,7 @@ F ext/rbu/rbutemplimit.test 7f408f49b90fa0a720d7599f3aec74a3c85e6cd78e56fdf726ce
 F ext/rbu/rbuvacuum.test 55e101e90168c2b31df6c9638fe73dc7f7cc666b6142266d1563697d79f73534
 F ext/rbu/rbuvacuum2.test b8e5b51dc8b2c0153373d024c0936be3f66f9234acbd6d0baab0869d56b14e6b
 F ext/rbu/rbuvacuum3.test 8addd82e4b83b4c93fa47428eae4fd0dbf410f8512c186f38e348feb49ba03dc
-F ext/rbu/sqlite3rbu.c d0627582dc894d96e70a1f4b3c8953abdd9fd4870f9a229479309ebfca9eda41
+F ext/rbu/sqlite3rbu.c 3f21eda2ee997ac2db4b351d6ed87b723056a4ce5484e06f0be6671ed602cf3e
 F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812
 F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a
 F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
@@ -1814,7 +1815,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 09435b5700a2650816ad9ffa628be5fa19da62369c30329801feb5e840463c7e
-R c89b872afec7ce06422a149342fb3f54
-U drh
-Z 699722b98f7dc28bf23e9dba9c74ebe1
+P f294cfc173c5653ef161dbff63b7838dbccdcad797f5163c49b3173f9f35ab0f
+R 74017336401c26983a6491011e631f20
+U dan
+Z 4692b4e4695b445534e3c622c0f2ec1d
index 522f665d0cab77309f631779a06016ff367842d6..4175898a504662f5b8570771f66b7fc1c16da455 100644 (file)
@@ -1 +1 @@
-f294cfc173c5653ef161dbff63b7838dbccdcad797f5163c49b3173f9f35ab0f
\ No newline at end of file
+31eb27f438ad727b095a518bfe0f7ed37cb806fc1e6929b821eddcc6cc9de260
\ No newline at end of file