Fix a crash that can occur if the sqlite_stat3 or sqlite_stat4 table is corrupt.

FossilOrigin-Name: d51df8a8fcc31c37f6e1c9612204af5738ed865e
This commit is contained in:
dan 2013-08-15 19:56:32 +00:00
parent af2583c83c
commit 0adbed8a60
4 changed files with 81 additions and 53 deletions

View File

@ -1,5 +1,5 @@
C Fix\sa\scrash\sthat\scan\soccur\sfollowing\san\sOOM\sfault.
D 2013-08-15T18:43:21.395
C Fix\sa\scrash\sthat\scan\soccur\sif\sthe\ssqlite_stat3\sor\ssqlite_stat4\stable\sis\scorrupt.
D 2013-08-15T19:56:32.997
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 e60d6329f77e84bac0a300d5227c28a05f5ff5de
F src/analyze.c 9533c7e948398bf9628178d6bf9a7845d7e29046
F src/attach.c 1816f5a9eea8d2010fc2b22b44f0f63eb3a62704
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 43b348822db3e4cef48b2ae5a445fbeb6c73a165
@ -308,7 +308,7 @@ F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
F test/analyze6.test 19151da2c4e918905d2081b74ac5c4d47fc850ab
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88
F test/analyze9.test 83e74db42a49bb185e05f3a44a5d65323aba8a40
F test/analyze9.test b73f9514af962a139d2c61d7741b0ba090789ea2
F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
@ -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 71070c9fce86103f174220e07771df99b2e01405
R fd0e4baaf9a9ffd0fe23644f24c090cf
P 9f80b2687012ab7c4d6d654fe19f40878bd78bd8
R abb1a9d20998265ab3bcabc4adb13b2c
U dan
Z 1c4d6e6edcc7281c470c7559e77faff9
Z 4cffc531446b09bd876c8b206583a719

View File

@ -1 +1 @@
9f80b2687012ab7c4d6d654fe19f40878bd78bd8
d51df8a8fcc31c37f6e1c9612204af5738ed865e

View File

@ -1268,6 +1268,44 @@ void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
}
#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
/*
** Populate the pIdx->aAvgEq[] array based on the samples currently
** stored in pIdx->aSample[].
*/
static void initAvgEq(Index *pIdx){
if( pIdx ){
IndexSample *aSample = pIdx->aSample;
IndexSample *pFinal = &aSample[pIdx->nSample-1];
int iCol;
for(iCol=0; iCol<pIdx->nColumn; iCol++){
int i; /* Used to iterate through samples */
tRowcnt sumEq = 0; /* Sum of the nEq values */
int nSum = 0; /* Number of terms contributing to sumEq */
tRowcnt avgEq = 0;
tRowcnt nDLt = pFinal->anDLt[iCol];
/* Set nSum to the number of distinct (iCol+1) field prefixes that
** occur in the stat4 table for this index before pFinal. Set
** sumEq to the sum of the nEq values for column iCol for the same
** set (adding the value only once where there exist dupicate
** prefixes). */
for(i=0; i<(pIdx->nSample-1); i++){
if( aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] ){
sumEq += aSample[i].anEq[iCol];
nSum++;
}
}
if( nDLt>nSum ){
avgEq = (pFinal->anLt[iCol] - sumEq)/(nDLt - nSum);
}
if( avgEq==0 ) avgEq = 1;
pIdx->aAvgEq[iCol] = avgEq;
if( pIdx->nSampleCol==1 ) break;
}
}
}
/*
** Load the content from either the sqlite_stat4 or sqlite_stat3 table
** into the relevant Index.aSample[] arrays.
@ -1292,7 +1330,6 @@ static int loadStatTbl(
sqlite3_stmt *pStmt = 0; /* An SQL statement being run */
char *zSql; /* Text of the SQL statement */
Index *pPrevIdx = 0; /* Previous index in the loop */
int idx = 0; /* slot in pIdx->aSample[] for next sample */
IndexSample *pSample; /* A slot in pIdx->aSample[] */
assert( db->lookaside.bEnabled==0 );
@ -1328,7 +1365,6 @@ static int loadStatTbl(
nAvgCol = pIdx->nColumn;
}
pIdx->nSampleCol = nIdxCol;
pIdx->nSample = nSample;
nByte = sizeof(IndexSample) * nSample;
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
nByte += nAvgCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
@ -1340,7 +1376,7 @@ static int loadStatTbl(
}
pSpace = (tRowcnt*)&pIdx->aSample[nSample];
pIdx->aAvgEq = pSpace; pSpace += nAvgCol;
for(i=0; i<pIdx->nSample; i++){
for(i=0; i<nSample; i++){
pIdx->aSample[i].anEq = pSpace; pSpace += nIdxCol;
pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol;
pIdx->aSample[i].anDLt = pSpace; pSpace += nIdxCol;
@ -1361,61 +1397,25 @@ static int loadStatTbl(
while( sqlite3_step(pStmt)==SQLITE_ROW ){
char *zIndex; /* Index name */
Index *pIdx; /* Pointer to the index object */
int i; /* Loop counter */
int nCol = 1; /* Number of columns in index */
zIndex = (char *)sqlite3_column_text(pStmt, 0);
if( zIndex==0 ) continue;
pIdx = sqlite3FindIndex(db, zIndex, zDb);
if( pIdx==0 ) continue;
if( pIdx==pPrevIdx ){
idx++;
}else{
pPrevIdx = pIdx;
idx = 0;
}
assert( idx<pIdx->nSample );
/* This next condition is true if data has already been loaded from
** the sqlite_stat4 table. In this case ignore stat3 data. */
if( bStat3 && pIdx->aSample[idx].anEq[0] ) continue;
pSample = &pIdx->aSample[idx];
if( bStat3==0 ){
nCol = pIdx->nColumn+1;
nCol = pIdx->nSampleCol;
if( bStat3 && nCol>1 ) continue;
if( pIdx!=pPrevIdx ){
initAvgEq(pPrevIdx);
pPrevIdx = pIdx;
}
pSample = &pIdx->aSample[pIdx->nSample++];
decodeIntArray((char*)sqlite3_column_text(pStmt,1), nCol, pSample->anEq, 0);
decodeIntArray((char*)sqlite3_column_text(pStmt,2), nCol, pSample->anLt, 0);
decodeIntArray((char*)sqlite3_column_text(pStmt,3), nCol, pSample->anDLt,0);
if( idx==pIdx->nSample-1 ){
IndexSample *aSample = pIdx->aSample;
int iCol;
for(iCol=0; iCol<pIdx->nColumn; iCol++){
tRowcnt sumEq = 0; /* Sum of the nEq values */
int nSum = 0; /* Number of terms contributing to sumEq */
tRowcnt avgEq = 0;
tRowcnt nDLt = pSample->anDLt[iCol];
/* Set nSum to the number of distinct (iCol+1) field prefixes that
** occur in the stat4 table for this index before pSample. Set
** sumEq to the sum of the nEq values for column iCol for the same
** set (adding the value only once where there exist dupicate
** prefixes). */
for(i=0; i<(pIdx->nSample-1); i++){
if( aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] ){
sumEq += aSample[i].anEq[iCol];
nSum++;
}
}
if( nDLt>nSum ){
avgEq = (pSample->anLt[iCol] - sumEq)/(nDLt - nSum);
}
if( avgEq==0 ) avgEq = 1;
pIdx->aAvgEq[iCol] = avgEq;
if( bStat3 ) break;
}
}
pSample->n = sqlite3_column_bytes(pStmt, 4);
pSample->p = sqlite3DbMallocZero(db, pSample->n);
if( pSample->p==0 ){
@ -1424,6 +1424,7 @@ static int loadStatTbl(
}
memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n);
}
initAvgEq(pPrevIdx);
return sqlite3_finalize(pStmt);
}

View File

@ -290,5 +290,32 @@ do_execsql_test 5.1 {
ANALYZE;
}
#-------------------------------------------------------------------------
# This was also crashing.
#
reset_db
do_execsql_test 6.1 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a);
CREATE INDEX i2 ON t1(b);
INSERT INTO t1 VALUES(1, 1);
INSERT INTO t1 VALUES(2, 2);
INSERT INTO t1 VALUES(3, 3);
INSERT INTO t1 VALUES(4, 4);
INSERT INTO t1 VALUES(5, 5);
ANALYZE;
PRAGMA writable_schema = 1;
CREATE TEMP TABLE x1 AS
SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat4
ORDER BY (rowid%5), rowid;
DELETE FROM sqlite_stat4;
INSERT INTO sqlite_stat4 SELECT * FROM x1;
PRAGMA writable_schema = 0;
ANALYZE sqlite_master;
}
do_execsql_test 6.2 {
SELECT * FROM t1 WHERE a = 'abc';
}
finish_test