Update the ANALYZE logic so that it works with WITHOUT ROWID tables.

FossilOrigin-Name: 9075770e4030b35677fbbe291f3c3c4946937a9a
This commit is contained in:
drh 2013-11-02 18:46:04 +00:00
parent c6bd4e4a36
commit ebe25af168
4 changed files with 99 additions and 19 deletions

View File

@ -1,5 +1,5 @@
C Store\sthe\sroot\spage\sof\sthe\sPRIMARY\sKEY\sindex\sfor\sa\sWITHOUT\sROWID\stable\sin\nthe\ssqlite_master\sentry\sfor\sthe\smain\stable\sand\somit\sthe\ssqlite_master\sentry\nfor\sthe\sPRIMARY\sKEY.
D 2013-11-02T14:37:18.563
C Update\sthe\sANALYZE\slogic\sso\sthat\sit\sworks\swith\sWITHOUT\sROWID\stables.
D 2013-11-02T18:46:04.859
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -159,7 +159,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
F src/analyze.c b6b115d69adaf0d2fa15001748b12735832fb296
F src/analyze.c 86f6a6cc4e263d333d72a3a698b6a172c6926886
F src/attach.c 0a17c9364895316ca4f52d06a97a72c0af1ae8b3
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 2f1987981139bd2f6d8c728d64bf09fb387443c3
@ -1076,7 +1076,7 @@ F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
F test/win32longpath.test e2aafc07e6990fe86c69be22a3d1a0e210cd329b
F test/without_rowid1.test c25455a420acf6239d3c4ae5f9107b62e063a204
F test/without_rowid1.test fd74502ecbde8b7078a3fd92a753cec3c5deac74
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd
F tool/build-all-msvc.bat 1bac6adc3fdb4d9204f21d17b14be25778370e48 x
@ -1128,7 +1128,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
P ac711459ff243e787ea5e9c01720dff75a5eda9b
R ae34f785e9853a53b0aaa3951983c6d8
P b7544bb280f1c1c55135a9b35aeb85604fef94a3
R cd75ad268fb226e12bc7de0b155a02b2
U drh
Z 71ade7b873cbec3da5d0aa4bb763c9f6
Z 442bd300793ddf9f249a185661da9d2f

View File

@ -1 +1 @@
b7544bb280f1c1c55135a9b35aeb85604fef94a3
9075770e4030b35677fbbe291f3c3c4946937a9a

View File

@ -269,6 +269,8 @@ struct Stat4Sample {
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
tRowcnt *anLt; /* sqlite_stat4.nLt */
i64 iRowid; /* Rowid in main table of the key */
u32 nRowid; /* Sizeof aRowid[] */
u8 *aRowid; /* Key for WITHOUT ROWID tables */
u8 isPSample; /* True if a periodic sample */
int iCol; /* If !isPSample, the reason for inclusion */
u32 iHash; /* Tiebreaker hash */
@ -281,13 +283,51 @@ struct Stat4Accum {
int mxSample; /* Maximum number of samples to accumulate */
Stat4Sample current; /* Current row as a Stat4Sample */
u32 iPrn; /* Pseudo-random number used for sampling */
Stat4Sample *aBest; /* Array of (nCol-1) best samples */
Stat4Sample *aBest; /* Array of nCol best samples */
int iMin; /* Index in a[] of entry with minimum score */
int nSample; /* Current number of samples */
int iGet; /* Index of current sample accessed by stat_get() */
Stat4Sample *a; /* Array of mxSample Stat4Sample objects */
sqlite3 *db; /* Database connection, for malloc() */
};
/* Reclaim memory used by a Stat4Sample
*/
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
static void sampleClear(sqlite3 *db, Stat4Sample *p){
sqlite3DbFree(db, p->aRowid);
p->aRowid = 0;
p->nRowid = 0;
}
#endif
/* Make a copy of the Stat4Sample.aRowid field.
*/
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
static void sampleDup(sqlite3 *db, Stat4Sample *p){
if( p->aRowid ){
u8 *aCopy = sqlite3DbMallocRaw(db, p->nRowid);
if( aCopy ){
memcpy(aCopy, p->aRowid, p->nRowid);
p->aRowid = aCopy;
}
}
}
#endif
/*
** Reclaim all memory of a Stat4Accum structure.
*/
static void stat4Destructor(void *pOld){
Stat4Accum *p = (Stat4Accum*)pOld;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
int i;
for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
#endif
sqlite3DbFree(p->db, p);
}
/*
** Implementation of the stat_init(N,C) SQL function. The two parameters
** are the number of rows in the table or index (C) and the number of columns
@ -306,6 +346,7 @@ static void statInit(
int nCol; /* Number of columns in index being sampled */
int nColUp; /* nCol rounded up for alignment */
int n; /* Bytes of space to allocate */
sqlite3 *db; /* Database connection */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
int mxSample = SQLITE_STAT4_SAMPLES;
#endif
@ -322,16 +363,18 @@ static void statInit(
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anLt */
+ sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */
+ sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */
+ sizeof(tRowcnt)*3*nColUp*(nCol+mxSample)
#endif
;
p = sqlite3MallocZero(n);
db = sqlite3_context_db_handle(context);
p = sqlite3DbMallocZero(db, n);
if( p==0 ){
sqlite3_result_error_nomem(context);
return;
}
p->db = db;
p->nRow = 0;
p->nCol = nCol;
p->current.anDLt = (tRowcnt*)&p[1];
@ -366,7 +409,7 @@ static void statInit(
#endif
/* Return a pointer to the allocated object to the caller */
sqlite3_result_blob(context, p, sizeof(p), sqlite3_free);
sqlite3_result_blob(context, p, sizeof(p), stat4Destructor);
}
static const FuncDef statInitFuncdef = {
1+IsStat34, /* nArg */
@ -448,6 +491,10 @@ static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
pTo->isPSample = pFrom->isPSample;
pTo->iCol = pFrom->iCol;
pTo->iHash = pFrom->iHash;
sampleClear(p->db, pTo);
pTo->nRowid = pFrom->nRowid;
pTo->aRowid = pFrom->aRowid;
sampleDup(p->db, pTo);
memcpy(pTo->anEq, pFrom->anEq, sizeof(tRowcnt)*p->nCol);
memcpy(pTo->anLt, pFrom->anLt, sizeof(tRowcnt)*p->nCol);
memcpy(pTo->anDLt, pFrom->anDLt, sizeof(tRowcnt)*p->nCol);
@ -596,16 +643,17 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
}
/*
** Implementation of the stat_push SQL function: stat_push(P,R,C)
** Implementation of the stat_push SQL function: stat_push(P,C,R)
** Arguments:
**
** P Pointer to the Stat4Accum object created by stat_init()
** C Index of left-most column to differ from previous row
** R Rowid for the current row
** R Rowid for the current row. Might be a key record for
** WITHOUT ROWID tables.
**
** The SQL function always returns NULL.
**
** The R parameter is only used for STAT3 and STAT4.
** The R parameter is only used for STAT3 and STAT4
*/
static void statPush(
sqlite3_context *context,
@ -645,7 +693,15 @@ static void statPush(
}
p->nRow++;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
p->current.iRowid = sqlite3_value_int64(argv[2]);
if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
p->current.iRowid = sqlite3_value_int64(argv[2]);
p->current.aRowid = 0;
p->current.nRowid = 0;
}else{
p->current.iRowid = 0;
p->current.nRowid = sqlite3_value_bytes(argv[2]);
p->current.aRowid = (u8*)sqlite3_value_blob(argv[2]);
}
p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345;
#endif
@ -769,7 +825,12 @@ static void statGet(
p->iGet = 0;
}
if( p->iGet<p->nSample ){
sqlite3_result_int64(context, p->a[p->iGet].iRowid);
Stat4Sample *pS = p->a + p->iGet;
if( pS->nRowid==0 ){
sqlite3_result_int64(context, pS->iRowid);
}else{
sqlite3_result_blob(context, pS->aRowid, pS->nRowid, SQLITE_STATIC);
}
}
}else{
tRowcnt *aCnt = 0;
@ -1038,8 +1099,21 @@ static void analyzeOneTable(
*/
sqlite3VdbeJumpHere(v, aGotoChng[nCol]);
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
assert( regRowid==(regStat4+2) );
if( HasRowid(pTab) ){
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
int j, k, regKey;
regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
for(j=0; j<pPk->nKeyCol; j++){
k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
}
#endif
assert( regChng==(regStat4+1) );
sqlite3VdbeAddOp3(v, OP_Function, 1, regStat4, regTemp);
@ -1065,6 +1139,7 @@ static void analyzeOneTable(
int regSampleRowid = regCol + nCol;
int addrNext;
int addrIsNull;
u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
pParse->nMem = MAX(pParse->nMem, regCol+nCol+1);
@ -1074,7 +1149,7 @@ static void analyzeOneTable(
callStatGet(v, regStat4, STAT_GET_NEQ, regEq);
callStatGet(v, regStat4, STAT_GET_NLT, regLt);
callStatGet(v, regStat4, STAT_GET_NDLT, regDLt);
sqlite3VdbeAddOp3(v, OP_NotExists, iTabCur, addrNext, regSampleRowid);
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
#ifdef SQLITE_ENABLE_STAT3
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
pIdx->aiColumn[0], regSample);

View File

@ -91,5 +91,10 @@ do_execsql_test without_rowid1-1.40 {
} {1250 phone flipper harvard | journal sherman ammonia 3.1415926 | journal sherman gamma 3.1415926 | arctic sleep ammonia helena |}
integrity_check without_rowid1-1.41
do_execsql_test without_rowid1-1.50 {
ANALYZE;
SELECT * FROM sqlite_stat1 ORDER BY idx;
} {t1 sqlite_autoindex_t1_1 {4 2 1} t1 t1bd {4 2 2}}
finish_test