diff --git a/manifest b/manifest index d7c9529c7f..2b09ccada8 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 3d11676d20..5f36a65cc7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2a41736728d83a777ea8112da927cb047ec6684e \ No newline at end of file +cca8bf4372ab7a0258aa5c9397818415c6cf0abf \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index c631854b31..be6b9586f1 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -140,6 +140,12 @@ #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; i1 ); /* >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( nEqaMinEq[i] ){ @@ -456,12 +480,12 @@ static void stat4Push( pSample->iRowid = rowid; pSample->iHash = h; pSample->isPSample = isPSample; - for(i=0; inCol; i++){ + for(i=0; ianEq[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; inCol; 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; inCol; 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; iaiColumn[i]; - sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regEq+i); + if( IsStat3==0 ){ + for(i=0; iaiColumn[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; jnSample; 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; inColumn+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; diff --git a/src/ctime.c b/src/ctime.c index d69763a304..7c915d58c6 100644 --- a/src/ctime.c +++ b/src/ctime.c @@ -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", diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 2b8c1ad55e..658ebc2941 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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 diff --git a/src/test_config.c b/src/test_config.c index c80fae295a..de1822e3b1 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -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__) diff --git a/src/vdbemem.c b/src/vdbemem.c index 8eef88ed3b..db3e6b262e 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -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; iNULL 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 && iColnSampleCol ); 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 + && nEqnSampleCol && 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; diff --git a/test/analyze.test b/test/analyze.test index 144834924a..c445084263 100644 --- a/test/analyze.test +++ b/test/analyze.test @@ -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} } diff --git a/test/analyze3.test b/test/analyze3.test index 394d321b97..fb26303ee3 100644 --- a/test/analyze3.test +++ b/test/analyze3.test @@ -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} diff --git a/test/analyze5.test b/test/analyze5.test index 048e6a5ef7..ac175c07b5 100644 --- a/test/analyze5.test +++ b/test/analyze5.test @@ -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 # diff --git a/test/analyze6.test b/test/analyze6.test index 7c8e653b40..d2c96518be 100644 --- a/test/analyze6.test +++ b/test/analyze6.test @@ -17,7 +17,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !stat4 { +ifcapable !stat4&&!stat3 { finish_test return } diff --git a/test/analyze7.test b/test/analyze7.test index 07d6ad52a0..76664546a5 100644 --- a/test/analyze7.test +++ b/test/analyze7.test @@ -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=?)}} diff --git a/test/analyze8.test b/test/analyze8.test index 3a00e69e53..b46d38651f 100644 --- a/test/analyze8.test +++ b/test/analyze8.test @@ -16,7 +16,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !stat4 { +ifcapable !stat4&&!stat3 { finish_test return } diff --git a/test/analyzeA.test b/test/analyzeA.test index 47fd2f0dd6..d9ca2c0f3b 100644 --- a/test/analyzeA.test +++ b/test/analyzeA.test @@ -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 cNULL, 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 {