From 0adbed8a6014e4d3af66b8c25a73566ddcae66cb Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 15 Aug 2013 19:56:32 +0000 Subject: [PATCH] Fix a crash that can occur if the sqlite_stat3 or sqlite_stat4 table is corrupt. FossilOrigin-Name: d51df8a8fcc31c37f6e1c9612204af5738ed865e --- manifest | 14 +++---- manifest.uuid | 2 +- src/analyze.c | 91 +++++++++++++++++++++++----------------------- test/analyze9.test | 27 ++++++++++++++ 4 files changed, 81 insertions(+), 53 deletions(-) diff --git a/manifest b/manifest index a2529d2cb2..55b717508b 100644 --- a/manifest +++ b/manifest @@ -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 diff --git a/manifest.uuid b/manifest.uuid index f0c5e4a7e1..3e8d68298e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9f80b2687012ab7c4d6d654fe19f40878bd78bd8 \ No newline at end of file +d51df8a8fcc31c37f6e1c9612204af5738ed865e \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 2c7a142fd0..79fd421a78 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -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; iColnColumn; 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; inSample; i++){ + for(i=0; iaSample[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( idxnSample ); /* 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; iColnColumn; 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); } diff --git a/test/analyze9.test b/test/analyze9.test index 21b354792b..7e67c5f832 100644 --- a/test/analyze9.test +++ b/test/analyze9.test @@ -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