From: drh Date: Sat, 2 Nov 2013 18:46:04 +0000 (+0000) Subject: Update the ANALYZE logic so that it works with WITHOUT ROWID tables. X-Git-Tag: version-3.8.2~137^2~29 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ebe25af168fa86b1fe21ac453af479147b5f2233;p=thirdparty%2Fsqlite.git Update the ANALYZE logic so that it works with WITHOUT ROWID tables. FossilOrigin-Name: 9075770e4030b35677fbbe291f3c3c4946937a9a --- diff --git a/manifest b/manifest index c01b546d05..639c93061e 100644 --- a/manifest +++ b/manifest @@ -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 diff --git a/manifest.uuid b/manifest.uuid index 2764a20dca..12db755f4b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b7544bb280f1c1c55135a9b35aeb85604fef94a3 \ No newline at end of file +9075770e4030b35677fbbe291f3c3c4946937a9a \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index d04e51da6e..4d88a91ade 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -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; inCol; i++) sampleClear(p->db, p->aBest+i); + for(i=0; imxSample; 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->iGetnSample ){ - 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; jnKeyCol; 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); diff --git a/test/without_rowid1.test b/test/without_rowid1.test index 7abbc07cfd..9e37828385 100644 --- a/test/without_rowid1.test +++ b/test/without_rowid1.test @@ -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