]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
If ENABLE_STAT3 is defined but ENABLE_STAT4 is not, have ANALYZE create and populate...
authordan <dan@noemail.net>
Mon, 12 Aug 2013 20:14:04 +0000 (20:14 +0000)
committerdan <dan@noemail.net>
Mon, 12 Aug 2013 20:14:04 +0000 (20:14 +0000)
FossilOrigin-Name: cca8bf4372ab7a0258aa5c9397818415c6cf0abf

21 files changed:
manifest
manifest.uuid
src/analyze.c
src/ctime.c
src/sqliteInt.h
src/test_config.c
src/vdbemem.c
src/where.c
test/analyze.test
test/analyze3.test
test/analyze5.test
test/analyze6.test
test/analyze7.test
test/analyze8.test
test/analyzeA.test
test/auth.test
test/dbstatus.test
test/index6.test
test/table.test
test/tkt-cbd054fa6b.test
test/where9.test

index d7c9529c7f7c722b117bb579572988995ef16e55..2b09ccada8e7e37a6e0dabacfec95d493bde1992 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C If\sthere\sis\sdata\sin\sboth\sthe\ssqlite_stat4\sand\ssqlite_stat3\stables\sfor\sa\ssingle\sindex,\signore\sthe\ssqlite_stat3\srecords.
-D 2013-08-12T17:31:32.368
+C If\sENABLE_STAT3\sis\sdefined\sbut\sENABLE_STAT4\sis\snot,\shave\sANALYZE\screate\sand\spopulate\sthe\ssqlite_stat3\stable\sinstead\sof\ssqlite_stat4.
+D 2013-08-12T20:14:04.167
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -157,7 +157,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
 F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
 F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
 F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
-F src/analyze.c c020f2ff9991412d85d8c5c736097de82c38ea51
+F src/analyze.c cbd13a1b3c7122729814d34245ce2b4007262f5e
 F src/attach.c 1816f5a9eea8d2010fc2b22b44f0f63eb3a62704
 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
 F src/backup.c 43b348822db3e4cef48b2ae5a445fbeb6c73a165
@@ -169,7 +169,7 @@ F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2
 F src/build.c c2e4d057c833b616c6e32e690c29c03ba949b571
 F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc
 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
-F src/ctime.c 177fa0cbf28b8deda3f216603beee0b883408a40
+F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
 F src/delete.c 2317c814866d9aa71fea16b3faf4fdd4d6a49b94
 F src/expr.c 0bbb44462a19169189b2709fbbd800950521b5ae
@@ -221,7 +221,7 @@ F src/shell.c 128eb16ccec68509a4a2f1948f2483819bf63425
 F src/sqlite.h.in bd1451ba1ab681022a53bccc3c39580ba094a3ff
 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
 F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
-F src/sqliteInt.h 646063fc1564842fd8e54eee00f8b8b429e2eb1f
+F src/sqliteInt.h 35ee14455ae3cb21b166fea7777867a42c60d0d5
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -239,7 +239,7 @@ F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
 F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
 F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
 F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16
-F src/test_config.c 636ecd15a6ba18bf97a590b5a21f47573c8c2b65
+F src/test_config.c 3d148e338b575bd937f7746824f36a9c6682d238
 F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
 F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
@@ -283,14 +283,14 @@ F src/vdbeInt.h e9b7c6b165a31a4715c5aa97223d20d265515231
 F src/vdbeapi.c 4d13580bd058b39623e8fcfc233b7df4b8191e8b
 F src/vdbeaux.c a6ea36a9dc714e1128a0173249a0532ddcab0489
 F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69
-F src/vdbemem.c b16ba7b3d1ead79c081d1f79e157e6b2efd13ca5
+F src/vdbemem.c 7ec9a78d6d4b2d4ebb4d3fd9b706065146616019
 F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017
 F src/vdbetrace.c e7ec40e1999ff3c6414424365d5941178966dcbc
 F src/vtab.c 2e8b489db47e20ae36cd247932dc671c9ded0624
 F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73
-F src/where.c c1090a2769c6e47b88aa79cd34f2e763af5282f8
+F src/where.c d97b5cb215c2e3e5b172b84000d2f3ee67ca0e86
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
@@ -301,15 +301,15 @@ F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
 F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
 F test/alter4.test 8e93bf7a7e6919b14b0c9a6c1e4908bcf21b0165
 F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
-F test/analyze.test 4d08a739c5ec28db93e0465e3b5a468befdf145f
-F test/analyze3.test ea4cba3277eb89d16dfeada7259ea437e7b00f3b
+F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4
+F test/analyze3.test 412f690dfe95b337475e3e78a84a85d25f6f125d
 F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213
-F test/analyze5.test 96ac783a56142bbbedb58a7c1eebd1808b49cfae
-F test/analyze6.test 3c01e084309706a1033f850330ea24f6f7846297
-F test/analyze7.test c0af22c5e0140e2e4ac556a21c2b6fff58229c98
-F test/analyze8.test 8d1f76ff1e47c4093bb7be3971ba08fa56dc470d
+F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
+F test/analyze6.test 19151da2c4e918905d2081b74ac5c4d47fc850ab
+F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
+F test/analyze8.test f3afd910c09f7d9b76f853e3f2f2fb169196d0b1
 F test/analyze9.test 1b419d03407f2a6f4f1485620d54cb3e1bab3a71
-F test/analyzeA.test 3a24600dd50e4a8815a952e1470ecb610046b069
+F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944
 F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
 F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
 F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
@@ -321,7 +321,7 @@ F test/attach2.test e54436ed956d3d88bdee61221da59bf3935a0966
 F test/attach3.test d89ccfe4fe6e2b5e368d480fcdfe4b496c54cf4e
 F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
 F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
-F test/auth.test cb43e31c14b8f5849d04edd6d3a1f844687cc855
+F test/auth.test 9bea29041871807d9f289ee679d05d3ed103642f
 F test/auth2.test a2a371aa6df15f8b0c8109b33d3d7f0f73e4c9aa
 F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
 F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf
@@ -413,7 +413,7 @@ F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
 F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
 F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
 F test/date.test f3228180c87bbe5d39c9397bf001c0095c3821b9
-F test/dbstatus.test 1e64356a8c0407d7aeead201852fc4de9418196a
+F test/dbstatus.test aee30c3f337e6c217ff06df59fb8fe6e6448dce2
 F test/dbstatus2.test 10418e62b3db5dca070f0c3eef3ea13946f339c2
 F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
 F test/delete.test a065b05d2ebf60fd16639c579a4adfb7c381c701
@@ -592,7 +592,7 @@ F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
 F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7
 F test/index4.test 2983216eb8c86ee62d9ed7cb206b5cc3331c0026
 F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33
-F test/index6.test 5be279e46e5f40e2dcc67d9b2aecdb5b0031db18
+F test/index6.test d84c03a7c16222b874877e8f4efb2bb7fed5d29e
 F test/indexedby.test 0e959308707c808515c3a51363f7a9835027108c
 F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
 F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
@@ -811,7 +811,7 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
 F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
 F test/syscall.test a653783d985108c4912cc64d341ffbbb55ad2806
 F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
-F test/table.test 03135ef2fd49b2a21894be22afdb3c7de32cecd3
+F test/table.test 30423211108121884588d24d6776c7f38702ad7b
 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
 F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
@@ -866,7 +866,7 @@ F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3
 F test/tkt-bd484a090c.test 60460bf946f79a79712b71f202eda501ca99b898
 F test/tkt-bdc6bbbb38.test fc38bb09bdd440e3513a1f5f98fc60a075182d7d
 F test/tkt-c48d99d690.test ba61977d62ab612fc515b3c488a6fbd6464a2447
-F test/tkt-cbd054fa6b.test 6595eac9c561b0aa46c1e4f4bae3f876acf38ce3
+F test/tkt-cbd054fa6b.test 06ccd57af3c0c7895d0f7dc844f13c51f8258885
 F test/tkt-d11f09d36e.test d999b548fef885d1d1afa49a0e8544ecf436869d
 F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09
 F test/tkt-d82e3f3721.test bcc0dfba658d15bab30fd4a9320c9e35d214ce30
@@ -1049,7 +1049,7 @@ F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
 F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8
 F test/where8.test 6f95896633cf2d307b5263145b942b7d33e837c6
 F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
-F test/where9.test 71aa15cc17cb3343566a2de3aef47d4548610e4d
+F test/where9.test 74245dea86592a744b758dff2e7daf0a07bade7d
 F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
 F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
 F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a
@@ -1107,7 +1107,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
-P fa1588adab6759fd3d1be02524aa19a0d1c6adaa
-R f7aa978164035b98da3c8ba701a7b74c
+P 2a41736728d83a777ea8112da927cb047ec6684e
+R ebabceacbf319f11921788de02fa2c3b
 U dan
-Z fe069e15f895d55c37e51ff5b63e6804
+Z 6caae0dd3ca2077b483e5c3e88d20d9e
index 3d11676d20b30d4d1285e08f0564d30e7b6b89ca..5f36a65cc707f4312e184df68dcf74936b417d19 100644 (file)
@@ -1 +1 @@
-2a41736728d83a777ea8112da927cb047ec6684e
\ No newline at end of file
+cca8bf4372ab7a0258aa5c9397818415c6cf0abf
\ No newline at end of file
index c631854b31db9c56f5cf11132483ab98f31dde98..be6b9586f14ce2d86bde357d5d8115aa8374cf1f 100644 (file)
 #ifndef SQLITE_OMIT_ANALYZE
 #include "sqliteInt.h"
 
+#ifdef SQLITE_ENABLE_STAT4
+# define IsStat3 0
+#else
+# define IsStat3 1
+#endif
+
 /*
 ** This routine generates code that opens the sqlite_stat1 table for
 ** writing with cursor iStatCur. If the library was built with the
@@ -170,8 +176,10 @@ static void openStatTable(
     { "sqlite_stat1", "tbl,idx,stat" },
 #if defined(SQLITE_ENABLE_STAT4)
     { "sqlite_stat4", "tbl,idx,neq,nlt,ndlt,sample" },
+    { "sqlite_stat3", 0 },
 #elif defined(SQLITE_ENABLE_STAT3)
     { "sqlite_stat3", "tbl,idx,neq,nlt,ndlt,sample" },
+    { "sqlite_stat4", 0 },
 #endif
   };
 
@@ -194,15 +202,17 @@ static void openStatTable(
     const char *zTab = aTable[i].zName;
     Table *pStat;
     if( (pStat = sqlite3FindTable(db, zTab, pDb->zName))==0 ){
-      /* The sqlite_stat[12] table does not exist. Create it. Note that a 
-      ** side-effect of the CREATE TABLE statement is to leave the rootpage 
-      ** of the new table in register pParse->regRoot. This is important 
-      ** because the OpenWrite opcode below will be needing it. */
-      sqlite3NestedParse(pParse,
-          "CREATE TABLE %Q.%s(%s)", pDb->zName, zTab, aTable[i].zCols
-      );
-      aRoot[i] = pParse->regRoot;
-      aCreateTbl[i] = OPFLAG_P2ISREG;
+      if( aTable[i].zCols ){
+        /* The sqlite_stat[12] table does not exist. Create it. Note that a 
+        ** side-effect of the CREATE TABLE statement is to leave the rootpage 
+        ** of the new table in register pParse->regRoot. This is important 
+        ** because the OpenWrite opcode below will be needing it. */
+        sqlite3NestedParse(pParse,
+            "CREATE TABLE %Q.%s(%s)", pDb->zName, zTab, aTable[i].zCols
+        );
+        aRoot[i] = pParse->regRoot;
+        aCreateTbl[i] = OPFLAG_P2ISREG;
+      }
     }else{
       /* The table already exists. If zWhere is not NULL, delete all entries 
       ** associated with the table zWhere. If zWhere is NULL, delete the
@@ -214,14 +224,14 @@ static void openStatTable(
            "DELETE FROM %Q.%s WHERE %s=%Q", pDb->zName, zTab, zWhereType, zWhere
         );
       }else{
-        /* The sqlite_stat[12] table already exists.  Delete all rows. */
+        /* The sqlite_stat[134] table already exists.  Delete all rows. */
         sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
       }
     }
   }
 
   /* Open the sqlite_stat[14] tables for writing. */
-  for(i=0; i<ArraySize(aTable); i++){
+  for(i=0; i<ArraySize(aRoot); i++){
     sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb);
     sqlite3VdbeChangeP4(v, -1, (char *)3, P4_INT32);
     sqlite3VdbeChangeP5(v, aCreateTbl[i]);
@@ -271,7 +281,7 @@ struct Stat4Accum {
   } *a;                     /* An array of samples */
 };
 
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
 /*
 ** Implementation of the stat4_init(C,N,S) SQL function. The three parameters
 ** are the number of rows in the table or index (C), the number of columns
@@ -297,8 +307,8 @@ static void stat4Init(
   /* Decode the three function arguments */
   UNUSED_PARAMETER(argc);
   nRow = (tRowcnt)sqlite3_value_int64(argv[0]);
-  nCol = sqlite3_value_int(argv[1]);
   mxSample = sqlite3_value_int(argv[2]);
+  nCol = sqlite3_value_int(argv[1]);
   assert( nCol>1 );               /* >1 because it includes the rowid column */
 
   /* Allocate the space required for the Stat4Accum object */
@@ -370,14 +380,16 @@ static void stat4Push(
   u32 h;                          /* Hash value for this key */
   int iMin = p->iMin;
   int i;
-  u8 isPSample = 0;
+  int nSampleCol;                 /* Number of fields in samples */
+  u8 isPSample = 0;               /* True if this is a periodic sample */
   u8 doInsert = 0;
 
   sqlite3_value **aEq = &argv[3];
   sqlite3_value **aLt = &argv[3+p->nCol];
   sqlite3_value **aDLt = &argv[3+p->nCol+p->nCol];
 
-  i64 nLt = sqlite3_value_int64(aLt[p->nCol-1]);
+  i64 nLt;
+  i64 nEq;
 
   UNUSED_PARAMETER(context);
   UNUSED_PARAMETER(argc);
@@ -385,6 +397,18 @@ static void stat4Push(
   assert( argc==(3 + 3*p->nCol) );
   assert( p->bHaveNonP==0 || p->bHaveP==0 );
 
+  if( IsStat3 ){
+    /* Stat3 builds ignore any call with bNewKey==0. And consider only
+    ** the first column of the index keys. */
+    if( bNewKey==0 ) return;
+    nEq = sqlite3_value_int64(aEq[0]);
+    nSampleCol = 1;
+  }else{
+    nEq = 1;
+    nSampleCol = p->nCol;
+  }
+  nLt = sqlite3_value_int64(aLt[nSampleCol-1]);
+
   if( bNewKey ){
     p->bHaveP = 0;
     p->bHaveNonP = 0;
@@ -394,7 +418,7 @@ static void stat4Push(
   /* Check if this should be a periodic sample. If this is a periodic
   ** sample and there is already a non-periodic sample for this key,
   ** replace it.  */
-  if( (nLt/p->nPSample) != (nLt+1)/p->nPSample ){
+  if( (nLt/p->nPSample) != (nLt+nEq)/p->nPSample ){
     doInsert = isPSample = 1;
     if( p->bHaveNonP ){
       p->nSample--;
@@ -423,7 +447,7 @@ static void stat4Push(
     p->bHaveNonP = 1;
   }else{
     tRowcnt *aMinEq = p->a[iMin].anEq;
-    for(i=p->nCol-2; i>=0; i--){
+    for(i=(IsStat3 ? 0 : p->nCol-2); i>=0; i--){
       i64 nEq = sqlite3_value_int64(aEq[i]);
       if( nEq<aMinEq[i] ) break;
       if( nEq>aMinEq[i] ){
@@ -456,12 +480,12 @@ static void stat4Push(
   pSample->iRowid = rowid;
   pSample->iHash = h;
   pSample->isPSample = isPSample;
-  for(i=0; i<p->nCol; i++){
+  for(i=0; i<nSampleCol; i++){
     pSample->anEq[i] = sqlite3_value_int64(aEq[i]);
     pSample->anLt[i] = sqlite3_value_int64(aLt[i]);
     pSample->anDLt[i] = sqlite3_value_int64(aDLt[i])-1;
     assert( sqlite3_value_int64(aDLt[i])>0 );
-  } 
+  }
 
   /* Find the new minimum */
   if( p->nSample==p->mxSample ){
@@ -472,7 +496,7 @@ static void stat4Push(
         iMin = i;
       }else{
         int j;
-        for(j=p->nCol-1; j>=0; j++){
+        for(j=nSampleCol-1; j>=0; j++){
           i64 iCmp = (p->a[iMin].anEq[j] - p->a[i].anEq[j]);
           if( iCmp<0 ){ iMin = i; }
           if( iCmp ) break;
@@ -533,19 +557,23 @@ static void stat4Get(
       default: aCnt = p->a[n].anDLt; break;
     }
 
-    zRet = sqlite3MallocZero(p->nCol * 25);
-    if( zRet==0 ){
-      sqlite3_result_error_nomem(context);
+    if( IsStat3 ){
+      sqlite3_result_int64(context, (i64)aCnt[0]);
     }else{
-      int i;
-      char *z = zRet;
-      for(i=0; i<p->nCol; i++){
-        sqlite3_snprintf(24, z, "%lld ", aCnt[i]);
-        z += sqlite3Strlen30(z);
+      zRet = sqlite3MallocZero(p->nCol * 25);
+      if( zRet==0 ){
+        sqlite3_result_error_nomem(context);
+      }else{
+        int i;
+        char *z = zRet;
+        for(i=0; i<p->nCol; i++){
+          sqlite3_snprintf(24, z, "%lld ", aCnt[i]);
+          z += sqlite3Strlen30(z);
+        }
+        assert( z[0]=='\0' && z>zRet );
+        z[-1] = '\0';
+        sqlite3_result_text(context, zRet, -1, sqlite3_free);
       }
-      assert( z[0]=='\0' && z>zRet );
-      z[-1] = '\0';
-      sqlite3_result_text(context, zRet, -1, sqlite3_free);
     }
   }
 }
@@ -591,7 +619,7 @@ static void analyzeOneTable(
   int regTabname = iMem++;     /* Register containing table name */
   int regIdxname = iMem++;     /* Register containing index name */
   int regStat1 = iMem++;       /* The stat column of sqlite_stat1 */
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
   int regNumEq = regStat1;     /* Number of instances.  Same as regStat1 */
   int regNumLt = iMem++;       /* Number of keys less than regSample */
   int regNumDLt = iMem++;      /* Number of distinct keys less than regSample */
@@ -646,7 +674,6 @@ static void analyzeOneTable(
     int nCol;                     /* Number of columns indexed by pIdx */
     KeyInfo *pKey;                /* KeyInfo structure for pIdx */
     int *aChngAddr;               /* Array of jump instruction addresses */
-
     int regPrev;                  /* First in array of previous values */
     int regDLte;                  /* First in array of nDlt registers */
     int regLt;                    /* First in array of nLt registers */
@@ -688,6 +715,7 @@ static void analyzeOneTable(
     **     regEq(0) += 1
     **     Next csr(0)
     **   }while ( csr(0)[0] == regPrev(0) )
+    **   if( IsStat3 ) regKeychng = 1
     ** 
     **  next_1:
     **   regPrev(1) = csr(1)[1]
@@ -699,7 +727,7 @@ static void analyzeOneTable(
     **     Next csr(1)
     **   }while ( csr(1)[0..1] == regPrev(0..1) )
     ** 
-    **   regKeychng = 1
+    **   if( IsStat3==0 ) regKeychng = 1
     **  next_row:
     **   regRowid = csr(2)[rowid]
     **   regEq(2) = 1
@@ -754,12 +782,15 @@ static void analyzeOneTable(
       VdbeComment((v, "%s", pIdx->zName));
     }
 
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
     /* Invoke the stat4_init() function. The arguments are:
     ** 
     **     * the number of rows in the index,
     **     * the number of columns in the index including the rowid,
     **     * the recommended number of samples for the stat4 table.
+    **
+    ** If this is a stat3 build, the number of columns in the index is
+    ** set to 1 (as this is the number of index fields gathered).
     */
     sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+1);
     sqlite3VdbeAddOp2(v, OP_Integer, nCol+1, regStat4+2);
@@ -830,6 +861,10 @@ static void analyzeOneTable(
       }
       sqlite3VdbeAddOp2(v, OP_Goto, 0, iDo);
       sqlite3VdbeResolveLabel(v, iNe);
+
+      if( IsStat3 && i==0 ){
+        sqlite3VdbeAddOp2(v, OP_Integer, 1, regKeychng);
+      }
     }
 
     /* This stuff:
@@ -846,8 +881,10 @@ static void analyzeOneTable(
     **   Next csr(2)
     **   if( eof( csr(2) ) ) goto endOfScan
     */
-#ifdef SQLITE_ENABLE_STAT4
-    sqlite3VdbeAddOp2(v, OP_Integer, 1, regKeychng);
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
+    if( 0==IsStat3 ){
+      sqlite3VdbeAddOp2(v, OP_Integer, 1, regKeychng);
+    }
     aChngAddr[nCol] =
     sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur+nCol, regRowid);
     sqlite3VdbeAddOp2(v, OP_Integer, 1, regEq+nCol);
@@ -875,7 +912,7 @@ static void analyzeOneTable(
 
     sqlite3VdbeResolveLabel(v, endOfScan);
 
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
     /* Add rows to the sqlite_stat4 table */
     regLoop = regStat4+1;
     sqlite3VdbeAddOp2(v, OP_Integer, -1, regLoop);
@@ -886,12 +923,17 @@ static void analyzeOneTable(
     sqlite3VdbeAddOp1(v, OP_IsNull, regEq+nCol);
 
     sqlite3VdbeAddOp3(v, OP_NotExists, iTabCur, shortJump, regEq+nCol);
-    for(i=0; i<nCol; i++){
-      int iCol = pIdx->aiColumn[i];
-      sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regEq+i);
+    if( IsStat3==0 ){
+      for(i=0; i<nCol; i++){
+        int iCol = pIdx->aiColumn[i];
+        sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regEq+i);
+      }
+      sqlite3VdbeAddOp3(v, OP_MakeRecord, regEq, nCol+1, regSample);
+      sqlite3VdbeChangeP4(v, -1, pIdx->zColAff, 0);
+    }else{
+      int iCol = pIdx->aiColumn[0];
+      sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regSample);
     }
-    sqlite3VdbeAddOp3(v, OP_MakeRecord, regEq, nCol+1, regSample);
-    sqlite3VdbeChangeP4(v, -1, pIdx->zColAff, 0);
 
     sqlite3VdbeAddOp3(v, OP_Function, 1, regStat4, regNumEq);
     sqlite3VdbeChangeP4(v, -1, (char*)&stat4GetFuncdef, P4_FUNCDEF);
@@ -1189,7 +1231,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
 ** and its contents.
 */
 void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
   if( pIdx->aSample ){
     int j;
     for(j=0; j<pIdx->nSample; j++){
@@ -1208,62 +1250,7 @@ void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
 #endif
 }
 
-#ifdef SQLITE_ENABLE_STAT4
-
-/*
-** The implementation of the sqlite_record() function. This function accepts
-** a single argument of any type. The return value is a formatted database 
-** record (a blob) containing the argument value.
-**
-** This is used to convert the value stored in the 'sample' column of the
-** sqlite_stat3 table to the record format SQLite uses internally.
-*/
-static void recordFunc(
-  sqlite3_context *context,
-  int argc,
-  sqlite3_value **argv
-){
-  const int file_format = 1;
-  int iSerial;                    /* Serial type */
-  int nSerial;                    /* Bytes of space for iSerial as varint */
-  int nVal;                       /* Bytes of space required for argv[0] */
-  int nRet;
-  sqlite3 *db;
-  u8 *aRet;
-
-  iSerial = sqlite3VdbeSerialType(argv[0], file_format);
-  nSerial = sqlite3VarintLen(iSerial);
-  nVal = sqlite3VdbeSerialTypeLen(iSerial);
-  db = sqlite3_context_db_handle(context);
-
-  nRet = 1 + nSerial + nVal;
-  aRet = sqlite3DbMallocRaw(db, nRet);
-  if( aRet==0 ){
-    sqlite3_result_error_nomem(context);
-  }else{
-    aRet[0] = nSerial+1;
-    sqlite3PutVarint(&aRet[1], iSerial);
-    sqlite3VdbeSerialPut(&aRet[1+nSerial], nVal, argv[0], file_format);
-    sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
-    sqlite3DbFree(db, aRet);
-  }
-}
-
-/*
-** Register built-in functions used to help read ANALYZE data.
-*/
-void sqlite3AnalyzeFunctions(void){
-  static SQLITE_WSD FuncDef aAnalyzeTableFuncs[] = {
-    FUNCTION(sqlite_record,   1, 0, 0, recordFunc),
-  };
-  int i;
-  FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
-  FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAnalyzeTableFuncs);
-  for(i=0; i<ArraySize(aAnalyzeTableFuncs); i++){
-    sqlite3FuncDefInsert(pHash, &aFunc[i]);
-  }
-}
-
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
 /*
 ** Load the content from either the sqlite_stat4 or sqlite_stat3 table 
 ** into the relevant Index.aSample[] arrays.
@@ -1323,6 +1310,7 @@ static int loadStatTbl(
       nIdxCol = pIdx->nColumn+1;
       nAvgCol = pIdx->nColumn;
     }
+    pIdx->nSampleCol = nIdxCol;
     pIdx->nSample = nSample;
     nByte = sizeof(IndexSample) * nSample;
     nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
@@ -1484,7 +1472,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
   for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
     Index *pIdx = sqliteHashData(i);
     sqlite3DefaultRowEst(pIdx);
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
     sqlite3DeleteIndexSamples(db, pIdx);
     pIdx->aSample = 0;
 #endif
@@ -1509,7 +1497,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
 
 
   /* Load the statistics from the sqlite_stat4 table. */
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
   if( rc==SQLITE_OK ){
     int lookasideEnabled = db->lookaside.bEnabled;
     db->lookaside.bEnabled = 0;
index d69763a304d50fec5d337c61d6d5aa7f995be9a5..7c915d58c6ea3f7d159bc594400b184b3d468f42 100644 (file)
@@ -117,8 +117,10 @@ static const char * const azCompileOpt[] = {
 #ifdef SQLITE_ENABLE_RTREE
   "ENABLE_RTREE",
 #endif
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4)
   "ENABLE_STAT4",
+#elif defined(SQLITE_ENABLE_STAT3)
+  "ENABLE_STAT3",
 #endif
 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
   "ENABLE_UNLOCK_NOTIFY",
index 2b8c1ad55e276c0c16e035a0398f373f1ce99514..658ebc2941ccebaaa06b6748468ebde4a17f054f 100644 (file)
@@ -1549,8 +1549,9 @@ struct Index {
   unsigned autoIndex:2;    /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
   unsigned bUnordered:1;   /* Use this index for == or IN queries only */
   unsigned uniqNotNull:1;  /* True if UNIQUE and NOT NULL for all columns */
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
   int nSample;             /* Number of elements in aSample[] */
+  int nSampleCol;          /* Size of IndexSample.anEq[] and so on */
   tRowcnt *aAvgEq;         /* Average nEq values for keys not in aSample */
   IndexSample *aSample;    /* Samples of the left-most key */
 #endif
index c80fae295a06d75e3e8ee45ef10b0aad1aaad68c..de1822e3b13143d97cc03acfdcaf115e3628b9d9 100644 (file)
@@ -463,6 +463,11 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
 #else
   Tcl_SetVar2(interp, "sqlite_options", "stat4", "0", TCL_GLOBAL_ONLY);
 #endif
+#if defined(SQLITE_ENABLE_STAT3) && !defined(SQLITE_ENABLE_STAT4)
+  Tcl_SetVar2(interp, "sqlite_options", "stat3", "1", TCL_GLOBAL_ONLY);
+#else
+  Tcl_SetVar2(interp, "sqlite_options", "stat3", "0", TCL_GLOBAL_ONLY);
+#endif
 
 #if !defined(SQLITE_ENABLE_LOCKING_STYLE)
 #  if defined(__APPLE__)
index 8eef88ed3ba3c34786afbf4e69707b0fb7a43e5e..db3e6b262eeae58ca4ffdec1b2afcff6ddc3240f 100644 (file)
@@ -1046,7 +1046,7 @@ int valueFromExpr(
   ** The ifdef here is to enable us to achieve 100% branch test coverage even
   ** when SQLITE_ENABLE_STAT4 is omitted.
   */
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
   if( op==TK_REGISTER ) op = pExpr->op2;
 #else
   if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
@@ -1152,7 +1152,61 @@ int sqlite3ValueFromExpr(
   return valueFromExpr(db, pExpr, enc, affinity, ppVal, valueNew, (void*)db);
 }
 
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
+/*
+** The implementation of the sqlite_record() function. This function accepts
+** a single argument of any type. The return value is a formatted database 
+** record (a blob) containing the argument value.
+**
+** This is used to convert the value stored in the 'sample' column of the
+** sqlite_stat3 table to the record format SQLite uses internally.
+*/
+static void recordFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  const int file_format = 1;
+  int iSerial;                    /* Serial type */
+  int nSerial;                    /* Bytes of space for iSerial as varint */
+  int nVal;                       /* Bytes of space required for argv[0] */
+  int nRet;
+  sqlite3 *db;
+  u8 *aRet;
+
+  iSerial = sqlite3VdbeSerialType(argv[0], file_format);
+  nSerial = sqlite3VarintLen(iSerial);
+  nVal = sqlite3VdbeSerialTypeLen(iSerial);
+  db = sqlite3_context_db_handle(context);
+
+  nRet = 1 + nSerial + nVal;
+  aRet = sqlite3DbMallocRaw(db, nRet);
+  if( aRet==0 ){
+    sqlite3_result_error_nomem(context);
+  }else{
+    aRet[0] = nSerial+1;
+    sqlite3PutVarint(&aRet[1], iSerial);
+    sqlite3VdbeSerialPut(&aRet[1+nSerial], nVal, argv[0], file_format);
+    sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
+    sqlite3DbFree(db, aRet);
+  }
+}
+
+/*
+** Register built-in functions used to help read ANALYZE data.
+*/
+void sqlite3AnalyzeFunctions(void){
+  static SQLITE_WSD FuncDef aAnalyzeTableFuncs[] = {
+    FUNCTION(sqlite_record,   1, 0, 0, recordFunc),
+  };
+  int i;
+  FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
+  FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAnalyzeTableFuncs);
+  for(i=0; i<ArraySize(aAnalyzeTableFuncs); i++){
+    sqlite3FuncDefInsert(pHash, &aFunc[i]);
+  }
+}
+
 /*
 ** A pointer to an instance of this object is passed as the context 
 ** pointer to valueNewStat4() (see below.
index 1fd185d418228c44979970059a6c594fdd9b4ee6..3b9d0239385bd6d255ea91c43fcec81aed046ffe 100644 (file)
@@ -285,7 +285,7 @@ struct WhereTerm {
 #define TERM_ORINFO     0x10   /* Need to free the WhereTerm.u.pOrInfo object */
 #define TERM_ANDINFO    0x20   /* Need to free the WhereTerm.u.pAndInfo obj */
 #define TERM_OR_OK      0x40   /* Used during OR-clause processing */
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
 #  define TERM_VNULL    0x80   /* Manufactured x>NULL or x<=NULL term */
 #else
 #  define TERM_VNULL    0x00   /* Disabled if not using stat3 */
@@ -391,7 +391,7 @@ struct WhereLoopBuilder {
   ExprList *pOrderBy;       /* ORDER BY clause */
   WhereLoop *pNew;          /* Template WhereLoop */
   WhereOrSet *pOrSet;       /* Record best loops here, if not NULL */
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
   UnpackedRecord *pRec;     /* Probe for stat4 (if required) */
   int nRecValid;            /* Number of valid fields currently in pRec */
 #endif
@@ -1789,7 +1789,7 @@ static void exprAnalyze(
   }
 #endif /* SQLITE_OMIT_VIRTUALTABLE */
 
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
   /* When sqlite_stat3 histogram data is available an operator of the
   ** form "x IS NOT NULL" can sometimes be evaluated more efficiently
   ** as "x>NULL" if x is not an INTEGER PRIMARY KEY.  So construct a
@@ -2397,7 +2397,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
 #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
 
 
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
 /*
 ** Estimate the location of a particular key among all keys in an
 ** index.  Store the results in aStat as follows:
@@ -2422,7 +2422,7 @@ static void whereKeyStats(
   int res;                    /* Result of comparison operation */
 
   assert( pIdx->nSample>0 );
-  assert( pRec->nField>0 && iCol<=pIdx->nColumn );
+  assert( pRec->nField>0 && iCol<pIdx->nSampleCol );
   do{
     iTest = (iMin+i)/2;
     res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec);
@@ -2533,11 +2533,12 @@ static int whereRangeScanEst(
   int rc = SQLITE_OK;
   int nOut = (int)*pnOut;
 
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
   Index *p = pBuilder->pNew->u.btree.pIndex;
   int nEq = pBuilder->pNew->u.btree.nEq;
 
-  if( nEq==pBuilder->nRecValid 
+  if( nEq==pBuilder->nRecValid
+   && nEq<p->nSampleCol
    && p->nSample 
    && OptimizationEnabled(pParse->db, SQLITE_Stat3) 
   ){
@@ -2640,7 +2641,7 @@ static int whereRangeScanEst(
   return rc;
 }
 
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
 /*
 ** Estimate the number of rows that will be returned based on
 ** an equality constraint x=VALUE and where that VALUE occurs in
@@ -2706,7 +2707,7 @@ static int whereEqualScanEst(
 }
 #endif /* defined(SQLITE_ENABLE_STAT4) */
 
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
 /*
 ** Estimate the number of rows that will be returned based on
 ** an IN constraint where the right-hand side of the IN operator
@@ -4296,7 +4297,7 @@ static int whereLoopAddBtreeIndex(
   rLogSize = estLog(whereCost(pProbe->aiRowEst[0]));
   for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
     int nIn = 0;
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
     int nRecValid = pBuilder->nRecValid;
     assert( pNew->nOut==saved_nOut );
     if( (pTerm->wtFlags & TERM_VNULL)!=0 && pSrc->pTab->aCol[iCol].notNull ){
@@ -4366,8 +4367,12 @@ static int whereLoopAddBtreeIndex(
       assert( pNew->nOut==saved_nOut );
       whereRangeScanEst(pParse, pBuilder, pBtm, pTop, &pNew->nOut);
     }
-#ifdef SQLITE_ENABLE_STAT4
-    if( nInMul==0 && pProbe->nSample && OptimizationEnabled(db, SQLITE_Stat3) ){
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
+    if( nInMul==0 
+     && pProbe->nSample 
+     && pNew->u.btree.nEq<=pProbe->nSampleCol
+     && OptimizationEnabled(db, SQLITE_Stat3) 
+    ){
       Expr *pExpr = pTerm->pExpr;
       tRowcnt nOut = 0;
       if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){
@@ -4400,7 +4405,7 @@ static int whereLoopAddBtreeIndex(
       whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn);
     }
     pNew->nOut = saved_nOut;
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
     pBuilder->nRecValid = nRecValid;
 #endif
   }
@@ -4631,7 +4636,7 @@ static int whereLoopAddBtree(
     }
 
     rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0);
-#ifdef SQLITE_ENABLE_STAT4
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
     sqlite3Stat4ProbeFree(pBuilder->pRec);
     pBuilder->nRecValid = 0;
     pBuilder->pRec = 0;
index 144834924ae552c70663b9a183cd531beb7a018c..c44508426396de42b8b877156a7687e5aa497d3d 100644 (file)
@@ -288,7 +288,7 @@ do_test analyze-4.3 {
 } {}
 
 # Verify that DROP TABLE and DROP INDEX remove entries from the 
-# sqlite_stat1 and sqlite_stat4 tables.
+# sqlite_stat1, sqlite_stat3 and sqlite_stat4 tables.
 #
 do_test analyze-5.0 {
   execsql {
@@ -306,12 +306,13 @@ do_test analyze-5.0 {
     SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
   }
 } {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4}
-ifcapable stat4 {
+ifcapable stat4||stat3 {
+  ifcapable stat4 {set stat sqlite_stat4} else {set stat sqlite_stat3}
   do_test analyze-5.1 {
-    execsql {
-      SELECT DISTINCT idx FROM sqlite_stat4 ORDER BY 1;
-      SELECT DISTINCT tbl FROM sqlite_stat4 ORDER BY 1;
-    }
+    execsql "
+      SELECT DISTINCT idx FROM $stat ORDER BY 1;
+      SELECT DISTINCT tbl FROM $stat ORDER BY 1;
+    "
   } {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4}
 }
 do_test analyze-5.2 {
@@ -321,12 +322,12 @@ do_test analyze-5.2 {
     SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
   }
 } {t3i1 t3i3 t4i1 t4i2 t3 t4}
-ifcapable stat4 {
+ifcapable stat4||stat3 {
   do_test analyze-5.3 {
-    execsql {
-      SELECT DISTINCT idx FROM sqlite_stat4 ORDER BY 1;
-      SELECT DISTINCT tbl FROM sqlite_stat4 ORDER BY 1;
-    }
+    execsql "
+      SELECT DISTINCT idx FROM $stat ORDER BY 1;
+      SELECT DISTINCT tbl FROM $stat ORDER BY 1;
+    "
   } {t3i1 t3i3 t4i1 t4i2 t3 t4}
 }
 do_test analyze-5.4 {
@@ -336,12 +337,12 @@ do_test analyze-5.4 {
     SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
   }
 } {t4i1 t4i2 t4}
-ifcapable stat4 {
+ifcapable stat4||stat3 {
   do_test analyze-5.5 {
-    execsql {
-      SELECT DISTINCT idx FROM sqlite_stat4 ORDER BY 1;
-      SELECT DISTINCT tbl FROM sqlite_stat4 ORDER BY 1;
-    }
+    execsql "
+      SELECT DISTINCT idx FROM $stat ORDER BY 1;
+      SELECT DISTINCT tbl FROM $stat ORDER BY 1;
+    "
   } {t4i1 t4i2 t4}
 }
 
index 394d321b9706eb9e4c4730c3d5634b329a599b76..fb26303ee3f2a3e76d9281720ae0cff1e00b736d 100644 (file)
@@ -17,7 +17,7 @@
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 
-ifcapable !stat4 {
+ifcapable !stat4&&!stat3 {
   finish_test
   return
 }
@@ -95,8 +95,11 @@ do_test analyze3-1.1.1 {
     COMMIT;
     ANALYZE;
   }
-  execsql {
-    SELECT count(*)>0 FROM sqlite_stat4;
+
+  ifcapable stat4 {
+    execsql { SELECT count(*)>0 FROM sqlite_stat4; }
+  } else {
+    execsql { SELECT count(*)>0 FROM sqlite_stat3; }
   }
 } {1}
 
index 048e6a5ef7d61950b1f1604c3785e865cb220464..ac175c07b5953b74a3541a398b34ad2005994fda 100644 (file)
@@ -17,7 +17,7 @@
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 
-ifcapable !stat4 {
+ifcapable !stat4&&!stat3 {
   finish_test
   return
 }
@@ -66,20 +66,40 @@ do_test analyze5-1.0 {
     CREATE INDEX t1y ON t1(y);  -- integers 0 and very few 1s
     CREATE INDEX t1z ON t1(z);  -- integers 0, 1, 2, and 3
     ANALYZE;
-    SELECT DISTINCT lindex(test_decode(sample),0) 
-    FROM sqlite_stat4 WHERE idx='t1u' ORDER BY nlt;
+  }
+  ifcapable stat4 {
+    db eval {
+      SELECT DISTINCT lindex(test_decode(sample),0) 
+        FROM sqlite_stat4 WHERE idx='t1u' ORDER BY nlt;
+    }
+  } else {
+    db eval {
+      SELECT sample FROM sqlite_stat3 WHERE idx='t1u' ORDER BY nlt;
+    }
   }
 } {alpha bravo charlie delta}
 
 do_test analyze5-1.1 {
-  db eval {
-    SELECT DISTINCT lower(lindex(test_decode(sample), 0)) 
-    FROM sqlite_stat4 WHERE idx='t1v' ORDER BY 1
+  ifcapable stat4 {
+    db eval {
+      SELECT DISTINCT lower(lindex(test_decode(sample), 0)) 
+        FROM sqlite_stat4 WHERE idx='t1v' ORDER BY 1
+    }
+  } else {
+    db eval {
+      SELECT lower(sample) FROM sqlite_stat3 WHERE idx='t1v' ORDER BY 1
+    }
   }
 } {alpha bravo charlie delta}
-do_test analyze5-1.2 {
-  db eval {SELECT idx, count(*) FROM sqlite_stat4 GROUP BY 1 ORDER BY 1}
-} {t1t 8 t1u 8 t1v 8 t1w 8 t1x 8 t1y 9 t1z 8}
+ifcapable stat4 {
+  do_test analyze5-1.2 {
+    db eval {SELECT idx, count(*) FROM sqlite_stat4 GROUP BY 1 ORDER BY 1}
+  } {t1t 8 t1u 8 t1v 8 t1w 8 t1x 8 t1y 9 t1z 8}
+} else {
+  do_test analyze5-1.2 {
+    db eval {SELECT idx, count(*) FROM sqlite_stat3 GROUP BY 1 ORDER BY 1}
+  } {t1t 4 t1u 4 t1v 4 t1w 4 t1x 4 t1y 2 t1z 4}
+}
 
 # Verify that range queries generate the correct row count estimates
 #
index 7c8e653b40a9e7e9c2885fbd66afa22966cb61bc..d2c96518beae798101d8d53a9beeb8efb9db5d42 100644 (file)
@@ -17,7 +17,7 @@
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 
-ifcapable !stat4 {
+ifcapable !stat4&&!stat3 {
   finish_test
   return
 }
index 07d6ad52a0b16366725f93e284e7ae5d2fcf2d43..76664546a5ff4cc13e79b57629033b902f078e4a 100644 (file)
@@ -82,7 +82,7 @@ do_test analyze7-3.1 {
 do_test analyze7-3.2.1 {
   execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=?;}
 } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}}
-ifcapable stat4 {
+ifcapable stat4||stat3 {
   # If ENABLE_STAT4 is defined, SQLite comes up with a different estimated
   # row count for (c=2) than it does for (c=?).
   do_test analyze7-3.2.2 {
@@ -98,7 +98,8 @@ ifcapable stat4 {
 do_test analyze7-3.3 {
   execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123}
 } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
-ifcapable {!stat4} {
+
+ifcapable {!stat4 && !stat3} {
   do_test analyze7-3.4 {
     execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123}
   } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
index 3a00e69e536ee7c20ece78182894a243210622e2..b46d38651f06a48d8ed7154b2e8c9558ce8ba89d 100644 (file)
@@ -16,7 +16,7 @@
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 
-ifcapable !stat4 {
+ifcapable !stat4&&!stat3 {
   finish_test
   return
 }
index 47fd2f0dd6b9a34ca6d70231f12ac357c9ce7760..d9ca2c0f3bafe7c519bacae52f4e447aa1fd3670 100644 (file)
@@ -61,12 +61,41 @@ proc populate_stat3 {{bDropTable 1}} {
   db2 close
 }
 
+# Populate the stat4 table according to the current contents of the db
+#
+proc populate_stat4 {{bDropTable 1}} {
+  sqlite3 db2 test.db
+  execsql { ANALYZE }
+
+  ifcapable stat3 {
+    execsql {
+      PRAGMA writable_schema = on;
+      CREATE TABLE sqlite_stat4(tbl,idx,neq,nlt,ndlt,sample);
+      INSERT INTO sqlite_stat4 
+      SELECT tbl, idx, neq, nlt, ndlt, sqlite_record(sample) 
+      FROM sqlite_stat3;
+    } db2
+    if {$bDropTable} { execsql {DROP TABLE sqlite_stat3} db2 }
+    execsql { PRAGMA writable_schema = off }
+  }
+  # Modify the database schema cookie to ensure that the other connection
+  # reloads the schema.
+  #
+  execsql {
+    CREATE TABLE obscure_tbl_nm(x);
+    DROP TABLE obscure_tbl_nm;
+  } db2
+  db2 close
+}
+
 # Populate the stat4 table according to the current contents of the db.
 # Leave deceptive data in the stat3 table. This data should be ignored
 # in favour of that from the stat4 table.
 #
 proc populate_both {} {
-  populate_stat3 0
+  ifcapable stat4 { populate_stat3 0 }
+  ifcapable stat3 { populate_stat4 0 }
 
   sqlite3 db2 test.db
   execsql {
@@ -78,30 +107,9 @@ proc populate_both {} {
     CREATE TABLE obscure_tbl_nm(x);
     DROP TABLE obscure_tbl_nm;
   } db2
-
   db2 close
 }
 
-
-# Populate the stat4 table according to the current contents of the db
-#
-proc populate_stat4 {} {
-  execsql { ANALYZE }
-#  ifcapable stat3 {
-#    execsql {
-#      PRAGMA writable_schema = on;
-#      CREATE TABLE sqlite_stat4(tbl,idx,neq,nlt,ndlt,sample);
-#      INSERT INTO sqlite_stat4 SELECT 
-#          tbl, idx, nlt, neq, ndlt,
-#          test_extract(sample, 1)
-#      FROM sqlite_stat4;
-#      DROP TABLE sqlite_stat4;
-#      PRAGMA writable_schema = off;
-#      ANALYZE sqlite_master;
-#    }
-#  }
-}
-
 foreach {tn analyze_cmd} {
   1 populate_stat4 
   2 populate_stat3
@@ -155,6 +163,5 @@ foreach {tn analyze_cmd} {
   } {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}
 }
 
-
 finish_test
 
index e7d110f2ec934dad83744cf55d725df243c282de..5e91b33eaa879d25c7109d5cb6d16274d3ba6574 100644 (file)
@@ -2328,7 +2328,11 @@ ifcapable compound&&subquery {
   ifcapable stat4 {
     set stat4 "sqlite_stat4 "
   } else {
-    set stat4 ""
+    ifcapable stat3 {
+      set stat4 "sqlite_stat3 "
+    } else {
+      set stat4 ""
+    }
   }
   do_test auth-5.2 {
     execsql {
index ae9a7344b7c88a502200977353f693664be2614d..c22fe15d4370911c7bc955cbe435d6597b5eaca7 100644 (file)
@@ -61,7 +61,7 @@ proc lookaside {db} {
   }
 }
 
-ifcapable stat4 {
+ifcapable stat4||stat3 {
   set STAT3 1
 } else {
   set STAT3 0
index d2c2e981384338f03a7da088a01132f3d32450b7..5e362b3577e7f51fb96f1f366077ef4fc1246694 100644 (file)
@@ -144,7 +144,7 @@ do_test index6-2.2 {
     SELECT * FROM t2 WHERE a=5;
   }
 } {/.* TABLE t2 USING INDEX t2a1 .*/}
-ifcapable stat4 {
+ifcapable stat4||stat3 {
   do_test index6-2.3stat4 {
     execsql {
       EXPLAIN QUERY PLAN
index 9047df23ddb9c4c71ff961558dd63fb5f3a1c573..e186450a2f6a20b4caacc6bc8f8f051d7653c483 100644 (file)
@@ -267,6 +267,7 @@ do_test table-5.2.1 {
     ANALYZE;
     DROP TABLE IF EXISTS sqlite_stat1;
     DROP TABLE IF EXISTS sqlite_stat2;
+    DROP TABLE IF EXISTS sqlite_stat3;
     DROP TABLE IF EXISTS sqlite_stat4;
     SELECT name FROM sqlite_master WHERE name GLOB 'sqlite_stat*';
   }
index 92b367e700eea23aff554c1505477797079ffc6e..2951233a5bb974c5213b7df5bd3950f585848386 100644 (file)
@@ -16,7 +16,7 @@
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 
-ifcapable !stat4 {
+ifcapable !stat4&&!stat3 {
   finish_test
   return
 }
@@ -54,18 +54,30 @@ do_test tkt-cbd05-1.1 {
   }
 } {10}
 do_test tkt-cbd05-1.2 {
-  db eval {
-    ANALYZE;
+  db eval { ANALYZE; }
+  ifcapable stat4 {
+    db eval {
+      PRAGMA writable_schema = 1;
+      CREATE VIEW vvv AS 
+      SELECT tbl,idx,neq,nlt,ndlt,test_extract(sample,0) AS sample
+      FROM sqlite_stat4;
+      PRAGMA writable_schema = 0;
+    }
+  } else {
+    db eval {
+      CREATE VIEW vvv AS 
+      SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat3;
+    }
   }
 } {}
 do_test tkt-cbd05-1.3 {
   execsql { 
     SELECT tbl,idx,group_concat(s(sample),' ') 
-    FROM sqlite_stat4 
+    FROM vvv 
     WHERE idx = 't1_x' 
     GROUP BY tbl,idx
   }
-} {t1 t1_x {... ...A. ...B. ...C. ...D. ...E. ...F. ...G. ...H. ...I.}}
+} {t1 t1_x { A B C D E F G H I}}
 
 do_test tkt-cbd05-2.1 {
   db eval {
@@ -93,10 +105,10 @@ do_test tkt-cbd05-2.2 {
 do_test tkt-cbd05-2.3 {
   execsql { 
     SELECT tbl,idx,group_concat(s(sample),' ') 
-    FROM sqlite_stat4 
+    FROM vvv 
     WHERE idx = 't1_x' 
     GROUP BY tbl,idx
   }
-} {t1 t1_x {... ...A. ...B. ...C. ...D. ...E. ...F. ...G. ...H. ...I.}}
+} {t1 t1_x { A B C D E F G H I}}
 
 finish_test
index 403178e3107fde6107196d64f6445b5cf26ffad3..f3f67dbdce07b102368014e8a98b74dd7fedbcc5 100644 (file)
@@ -781,7 +781,7 @@ do_test where9-6.8.2 {
         OR (b NOT NULL AND c NOT NULL AND d IS NULL)
   }
 } {1 {no query solution}}
-ifcapable stat4 {
+ifcapable stat4||stat3 {
   # When STAT3 is enabled, the "b NOT NULL" terms get translated
   # into b>NULL, which can be satified by the index t1b.  It is a very
   # expensive way to do the query, but it works, and so a solution is possible.
@@ -851,6 +851,11 @@ do_test where9-7.0 {
     INSERT INTO t6 SELECT * FROM t5;
     ANALYZE t5;
   }
+  ifcapable stat3 {
+    sqlite3 db2 test.db
+    db2 eval { DROP TABLE IF EXISTS sqlite_stat3 }
+    db2 close
+  }
 } {}
 do_test where9-7.1.1 {
   count_steps {