If ENABLE_STAT3 is defined but ENABLE_STAT4 is not, have ANALYZE create and populate the sqlite_stat3 table instead of sqlite_stat4.

FossilOrigin-Name: cca8bf4372ab7a0258aa5c9397818415c6cf0abf
This commit is contained in:
dan 2013-08-12 20:14:04 +00:00
parent 86f69d98d2
commit 8ad169abb4
21 changed files with 320 additions and 211 deletions

View File

@ -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

View File

@ -1 +1 @@
2a41736728d83a777ea8112da927cb047ec6684e
cca8bf4372ab7a0258aa5c9397818415c6cf0abf

View File

@ -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; 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;

View 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",

View 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

View 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__)

View 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.

View 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;

View 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}
}

View 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}

View 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
#

View File

@ -17,7 +17,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !stat4 {
ifcapable !stat4&&!stat3 {
finish_test
return
}

View 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=?)}}

View File

@ -16,7 +16,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !stat4 {
ifcapable !stat4&&!stat3 {
finish_test
return
}

View 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

View 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 {

View File

@ -61,7 +61,7 @@ proc lookaside {db} {
}
}
ifcapable stat4 {
ifcapable stat4||stat3 {
set STAT3 1
} else {
set STAT3 0

View 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

View 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*';
}

View 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

View 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 {