]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Experimental change to include changes made to the sqlite_stat1 table in
authordan <dan@noemail.net>
Fri, 12 Jan 2018 16:44:29 +0000 (16:44 +0000)
committerdan <dan@noemail.net>
Fri, 12 Jan 2018 16:44:29 +0000 (16:44 +0000)
changesets generated by the sessions module. sqlite_stat1 entries in such
changesets are ignored by legacy clients.

FossilOrigin-Name: bd46c4429693545eb16db85692fc591ac529796aa746f5f21df1ce4380619320

ext/session/sessionstat1.test [new file with mode: 0644]
ext/session/sqlite3session.c
manifest
manifest.uuid
src/analyze.c
src/delete.c
src/vdbe.c
src/vdbe.h
src/vdbeaux.c
test/hook.test

diff --git a/ext/session/sessionstat1.test b/ext/session/sessionstat1.test
new file mode 100644 (file)
index 0000000..47bbda1
--- /dev/null
@@ -0,0 +1,125 @@
+# 2018 January 12
+#
+# 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 [info script]] .. .. test]
+} 
+source [file join [file dirname [info script]] session_common.tcl]
+source $testdir/tester.tcl
+ifcapable !session {finish_test; return}
+
+set testprefix sessionstat1
+
+do_execsql_test 1.0 {
+  CREATE TABLE t1(a PRIMARY KEY, b, c);
+  CREATE INDEX t1b ON t1(b);
+  CREATE INDEX t1c ON t1(c);
+
+  WITH s(i) AS (
+    SELECT 0 UNION ALL SELECT i+1 FROM s WHERE (i+1)<32
+  )
+  INSERT INTO t1 SELECT i, i%8, i%2 FROM s;
+}
+
+do_iterator_test 1.1 {} {
+  ANALYZE
+} {
+  {INSERT sqlite_stat1 0 XX. {} {t t1 t sqlite_autoindex_t1_1 t {32 1}}}
+  {INSERT sqlite_stat1 0 XX. {} {t t1 t t1b t {32 4}}} 
+  {INSERT sqlite_stat1 0 XX. {} {t t1 t t1c t {32 16}}}
+}
+
+do_execsql_test 1.2 {
+  WITH s(i) AS (
+    SELECT 32 UNION ALL SELECT i+1 FROM s WHERE (i+1)<64
+  )
+  INSERT INTO t1 SELECT i, i%8, i%2 FROM s;
+}
+
+do_iterator_test 1.3 {} {
+  ANALYZE
+} {
+  {UPDATE sqlite_stat1 0 XX. {t t1 t sqlite_autoindex_t1_1 t {32 1}} {{} {} {} {} t {64 1}}} 
+  {UPDATE sqlite_stat1 0 XX. {t t1 t t1b t {32 4}} {{} {} {} {} t {64 8}}} 
+  {UPDATE sqlite_stat1 0 XX. {t t1 t t1c t {32 16}} {{} {} {} {} t {64 32}}}
+}
+
+do_iterator_test 1.5 {} {
+  DROP INDEX t1b;
+} {
+  {DELETE sqlite_stat1 0 XX. {t t1 t t1b t {64 8}} {}}
+}
+
+do_iterator_test 1.6 {} {
+  DROP TABLE t1;
+} {
+  {DELETE sqlite_stat1 0 XX. {t t1 t sqlite_autoindex_t1_1 t {64 1}} {}}
+  {DELETE sqlite_stat1 0 XX. {t t1 t t1c t {64 32}} {}}
+}
+
+#-------------------------------------------------------------------------
+#
+catch { db2 close }
+forcedelete test.db2
+sqlite3 db2 test.db2
+
+do_test 2.0 {
+  do_common_sql {
+    CREATE TABLE t1(a PRIMARY KEY, b, c);
+    CREATE INDEX t1b ON t1(b);
+    CREATE INDEX t1c ON t1(c);
+    ANALYZE;
+  }
+} {}
+
+do_test 2.1 {
+  do_then_apply_sql {
+    WITH s(i) AS (
+        SELECT 0 UNION ALL SELECT i+1 FROM s WHERE (i+1)<32
+    )
+    INSERT INTO t1 SELECT i, i%8, i%2 FROM s;
+    ANALYZE;
+  }
+} {}
+
+do_execsql_test -db db2 2.2 {
+  SELECT * FROM sqlite_stat1
+} {
+  t1 sqlite_autoindex_t1_1 {32 1} 
+  t1 t1b {32 4} 
+  t1 t1c {32 16}
+}
+
+do_test 2.3 {
+  do_then_apply_sql { DROP INDEX t1c }
+} {}
+
+do_execsql_test -db db2 2.4 {
+  SELECT * FROM sqlite_stat1
+} {
+  t1 sqlite_autoindex_t1_1 {32 1} 
+  t1 t1b {32 4} 
+}
+
+do_test 2.3 {
+  do_then_apply_sql { DROP TABLE t1 }
+} {}
+
+do_execsql_test -db db2 2.4 {
+  SELECT * FROM sqlite_stat1
+} {
+}
+
+do_execsql_test -db db2 2.4 { SELECT count(*) FROM t1 } 32
+
+finish_test
+
index d5cb4673747c9cbd1483b4bd3b782e8c4e524ad3..ffaa4c98b0ea1e79bed76e33e552023c04509434 100644 (file)
@@ -944,7 +944,16 @@ static int sessionTableInfo(
   assert( pazCol && pabPK );
 
   nThis = sqlite3Strlen30(zThis);
-  zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
+  if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){
+    /* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */
+    zPragma = sqlite3_mprintf(
+        "SELECT 0, 'tbl',  '', 0, '', 1     UNION ALL "
+        "SELECT 1, 'idx',  '', 0, '', 2     UNION ALL "
+        "SELECT 2, 'stat', '', 0, '', 0"
+    );
+  }else{
+    zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
+  }
   if( !zPragma ) return SQLITE_NOMEM;
 
   rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
index 628128b51f82fcd0d71b26ec2d2df34485e54d8c..7e21810e823a401bd6c32c3096e1ca1d10ab128e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sa\stest\sto\sensure\sthat\sthe\ssqlite3changeset_apply()\sfunction\signores\stables\nthat\sdo\snot\shave\sthe\sexpected\sprimary\skeys.
-D 2018-01-12T12:02:02.075
+C Experimental\schange\sto\sinclude\schanges\smade\sto\sthe\ssqlite_stat1\stable\sin\nchangesets\sgenerated\sby\sthe\ssessions\smodule.\ssqlite_stat1\sentries\sin\ssuch\nchangesets\sare\signored\sby\slegacy\sclients.
+D 2018-01-12T16:44:29.077
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in 38f84f301cbef443b2d269f67a74b8cc536469831f70df7c3e912acc04932cc2
@@ -397,8 +397,9 @@ F ext/session/sessionat.test feb7d22b3124882064b9d9df69f5484a9bb8c123dc9ddc6ffcd
 F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
 F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
 F ext/session/sessionfault2.test 04aa0bc9aa70ea43d8de82c4f648db4de1e990b0
+F ext/session/sessionstat1.test a361997e6ea72d427cb4b1313226b56278b9c74d3045817c33c99de5bef0f2e9
 F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc
-F ext/session/sqlite3session.c cc127222a9ea6f4eaa31281aa9da924f5244f6099be0ee526c950684fb3513a6
+F ext/session/sqlite3session.c 604aa21fa17c161a982595ec76c533add0e3f02ad7fb48bd4ece59335901a421
 F ext/session/sqlite3session.h cb4d860101ba6d3ac810f18684539b766d24d668fa2436cdde90d711af9464fb
 F ext/session/test_session.c eb0bd6c1ea791c1d66ee4ef94c16500dad936386
 F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
@@ -420,7 +421,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
 F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
 F src/alter.c cf7a8af45cb0ace672f47a1b29ab24092a9e8cd8d945a9974e3b5d925f548594
-F src/analyze.c 0d0ccf7520a201d8747ea2f02c92c26e26f801bc161f714f27b9f7630dde0421
+F src/analyze.c f9bfffd0416c547a916cb96793b94684bdb0d26a71542ea31819c6757741c19d
 F src/attach.c 84c477e856b24c2b9a0983b438a707c0cf4d616cee7a425401d418e58afec24c
 F src/auth.c 6277d63837357549fe14e723490d6dc1a38768d71c795c5eb5c0f8a99f918f73
 F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
@@ -436,7 +437,7 @@ F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
 F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
 F src/dbpage.c 8db4c97f630e7d83f884ea75caf1ffd0988c160e9d530194d93721c80821e0f6
 F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
-F src/delete.c 74667ad914ac143731a444a1bacf29ceb18f6eded8a0dd17aafae80baa07f8bb
+F src/delete.c 20c8788451dc737a967c87ea53ad43544d617f5b57d32ccce8bd52a0daf9e89b
 F src/expr.c ad6e7a9c34a4bab9d10cc857d647ae7ce370a633b5c0bfa71f1c29b81ae364b8
 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
 F src/fkey.c d617daf66b5515e2b42c1405b2b4984c30ca50fb705ab164271a9bf66c69e331
@@ -553,11 +554,11 @@ F src/update.c 8bd52c38d6d426925be4488ee106db26d9ee344406315671ed246ddace8d6091
 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
 F src/util.c 7315e97a8dc2c8e19ca64196c652cf0a65d13fd0a211b2cec082062372dc6261
 F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739
-F src/vdbe.c 4d0666741d884dfaceb6ac5bbededbd947068e4b742163898feea84a027dace6
-F src/vdbe.h d50cadf12bcf9fb99117ef392ce1ea283aa429270481426b6e8b0280c101fd97
+F src/vdbe.c 5d83f28acbce72f3bb35917c75c34131022010f0a54dbd5ae2cbbf21f08c38c1
+F src/vdbe.h 134beb7a12a6213c00eba58febaede33447cc4441bc568a0d9c144b33fc3720a
 F src/vdbeInt.h a0969c14950bcc61b2dfa19c6f62b42c5012013fcda342ca927a192ed37e6592
 F src/vdbeapi.c f519346f6db99a1eb3f85ca3ae8aede9ff9c4d90fec809dae7cb946786b2e270
-F src/vdbeaux.c 7ae48b180e5dd5d282e6752d155f1ab7929196d8e6577b82742044188152ca85
+F src/vdbeaux.c 7d635c30e55196ee8e0af605aceab0c3036ed6d6ed55dd6639c4b2a2a4593b4f
 F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
 F src/vdbemem.c 8478f7fb1948bf8fdeec7c2cb59ea58155c31258b9cd43c56d485e03ed40bd07
 F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
@@ -944,7 +945,7 @@ F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
 F test/having.test e4098a4b8962f9596035c3b87a8928a10648acc509f1bb8d6f96413bbf79a1b3
 F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
 F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
-F test/hook.test dbc0b87756e1e20e7497b56889c9e9cd2f8cc2b5
+F test/hook.test 1604b3b2f5931430087540404555c1b6be3618600b81558657c66b533ed70b13
 F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
 F test/icu.test 41aa8847745a879b897a7febea0f8f9efc8e67fe8bf680589b6e07c7b0a1569a
 F test/ieee754.test 806fc0ce7f305f57e3331eaceeddcfec9339e607
@@ -1698,7 +1699,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P a5d09dfaa337fa51d6e702c6aefe58824ab1e7d221c6e79166e2c6f9c7ab1501
-R 180a0996d52ee7f7f835ebd96e9ccca1
+P bf2daf06279e46bc37cc92ad1becec1b12d2aa804a14b101fca8b3a7fdb280c3
+R df0683427f9c775029b8cffecc77e29c
+T *branch * sessions-stat1
+T *sym-sessions-stat1 *
+T -sym-trunk *
 U dan
-Z 12f762acfd5b059fba2b906c66463308
+Z e2d0263dd242b14c8f682e74527ab3ca
index 5e594f1a7297ae517ae8aab996d5b431b5f7fa6a..00b7d3d5a54c4877fe76feac02518c7b279369a5 100644 (file)
@@ -1 +1 @@
-bf2daf06279e46bc37cc92ad1becec1b12d2aa804a14b101fca8b3a7fdb280c3
\ No newline at end of file
+bd46c4429693545eb16db85692fc591ac529796aa746f5f21df1ce4380619320
\ No newline at end of file
index 495cc954accdc25a2c7efc2ff994c6eab63da9ae..85c603ffdf50fd3bd3fdffb071f3537d2dea93b7 100644 (file)
@@ -234,6 +234,10 @@ static void openStatTable(
            "DELETE FROM %Q.%s WHERE %s=%Q",
            pDb->zDbSName, zTab, zWhereType, zWhere
         );
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+      }else if( db->xPreUpdateCallback ){
+        sqlite3NestedParse(pParse, "DELETE FROM %Q.%s", pDb->zDbSName, zTab);
+#endif
       }else{
         /* The sqlite_stat[134] table already exists.  Delete all rows. */
         sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
@@ -998,6 +1002,9 @@ static void analyzeOneTable(
   int regIdxname = iMem++;     /* Register containing index name */
   int regStat1 = iMem++;       /* Value for the stat column of sqlite_stat1 */
   int regPrev = iMem;          /* MUST BE LAST (see below) */
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+  Table *pStat1 = 0; 
+#endif
 
   pParse->nMem = MAX(pParse->nMem, iMem);
   v = sqlite3GetVdbe(pParse);
@@ -1023,6 +1030,18 @@ static void analyzeOneTable(
   }
 #endif
 
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+  if( db->xPreUpdateCallback ){
+    pStat1 = (Table*)sqlite3DbMallocZero(db, sizeof(Table) + 13);
+    if( pStat1==0 ) return;
+    pStat1->zName = (char*)&pStat1[1];
+    memcpy(pStat1->zName, "sqlite_stat1", 13);
+    pStat1->nCol = 3;
+    pStat1->iPKey = -1;
+    sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNBLOB);
+  }
+#endif
+
   /* Establish a read-lock on the table at the shared-cache level. 
   ** Open a read-only cursor on the table. Also allocate a cursor number
   ** to use for scanning indexes (iIdxCur). No index cursor is opened at
@@ -1224,6 +1243,9 @@ static void analyzeOneTable(
     sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
     sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
     sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+    sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE);
+#endif
     sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
 
     /* Add the entries to the stat3 or stat4 table. */
index 5808ac51d40df15cafec9b31da9421b4913dc5eb..2b69e4763af11ae7b9cd403c6062e25ff36a63ce 100644 (file)
@@ -760,7 +760,7 @@ void sqlite3GenerateRowDelete(
     u8 p5 = 0;
     sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
     sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
-    if( pParse->nested==0 ){
+    if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlite_stat1") ){
       sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE);
     }
     if( eMode!=ONEPASS_OFF ){
index b00174bb10c57a822dc1f1abbb1c2c10635c2fc3..f5112e0daa4db9f8f43f3ed01ed0a5dd42e57860 100644 (file)
@@ -4483,7 +4483,8 @@ case OP_InsertInt: {
 
   /* Invoke the update-hook if required. */
   if( rc ) goto abort_due_to_error;
-  if( db->xUpdateCallback && op ){
+  assert( !op || pTab->aCol || !sqlite3_stricmp(pTab->zName,"sqlite_stat1") );
+  if( db->xUpdateCallback && op && pTab->aCol ){
     db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, x.nKey);
   }
   break;
index 3e77eb9db5f3c9ce76ef0bfa546ebc609feb98d7..f002e05d81b79aff9516bd8139631c682f6d4407 100644 (file)
@@ -127,6 +127,7 @@ typedef struct VdbeOpList VdbeOpList;
 #define P4_INT64      (-14) /* P4 is a 64-bit signed integer */
 #define P4_INTARRAY   (-15) /* P4 is a vector of 32-bit integers */
 #define P4_FUNCCTX    (-16) /* P4 is a pointer to an sqlite3_context object */
+#define P4_DYNBLOB    (-17) /* Pointer to memory from sqliteMalloc() */
 
 /* Error message codes for OP_Halt */
 #define P5_ConstraintNotNull 1
index bc4bbda8e447b9e5e5941049aae459c057f6aa25..1780d37b8c9a606e13e771e04331e77761cf7076 100644 (file)
@@ -866,6 +866,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
     case P4_REAL:
     case P4_INT64:
     case P4_DYNAMIC:
+    case P4_DYNBLOB:
     case P4_INTARRAY: {
       sqlite3DbFree(db, p4);
       break;
@@ -1407,6 +1408,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
       sqlite3XPrintf(&x, "program");
       break;
     }
+    case P4_DYNBLOB:
     case P4_ADVANCE: {
       zTemp[0] = 0;
       break;
index 9ba220cdede5462ace8fb87bcb7778ddd83da0fb..1c9145baef44db95a8db2f926cfd7c484743afb2 100644 (file)
@@ -906,5 +906,56 @@ do_preupdate_test 10.3 {
   DELETE FROM t3 WHERE b=1
 } {DELETE main t3 1 1 0 {} 1}
 
+#-------------------------------------------------------------------------
+# Test that the "update" hook is not fired for operations on the 
+# sqlite_stat1 table performed by ANALYZE, even if a pre-update hook is
+# registered.
+ifcapable analyze {
+  reset_db
+  do_execsql_test 11.1 {
+    CREATE TABLE t1(a, b);
+    CREATE INDEX idx1 ON t1(a);
+    CREATE INDEX idx2 ON t1(b);
+
+    INSERT INTO t1 VALUES(1, 2);
+    INSERT INTO t1 VALUES(3, 4);
+    INSERT INTO t1 VALUES(5, 6);
+    INSERT INTO t1 VALUES(7, 8);
+  }
+
+  db preupdate hook preupdate_cb
+  db update_hook update_cb
+
+  proc preupdate_cb {args} { lappend ::res "preupdate" $args }
+  proc update_cb {args} { lappend ::res "update" $args }
+
+  set ::res [list]
+  do_test 11.2 {
+    execsql ANALYZE
+    set ::res
+  } [list {*}{
+    preupdate {INSERT main sqlite_stat1 1 1}
+    preupdate {INSERT main sqlite_stat1 2 2}
+  }]
+
+  do_execsql_test 11.3 {
+    INSERT INTO t1 VALUES(9, 10);
+    INSERT INTO t1 VALUES(11, 12);
+    INSERT INTO t1 VALUES(13, 14);
+    INSERT INTO t1 VALUES(15, 16);
+  }
+
+  set ::res [list]
+  do_test 11.4 {
+    execsql ANALYZE
+    set ::res
+  } [list {*}{
+    preupdate {DELETE main sqlite_stat1 1 1}
+    preupdate {DELETE main sqlite_stat1 2 2}
+    preupdate {INSERT main sqlite_stat1 1 1}
+    preupdate {INSERT main sqlite_stat1 2 2}
+  }]
+}
+
 
 finish_test