From: drh Date: Sat, 18 Feb 2017 15:58:52 +0000 (+0000) Subject: Add the OP_SqlExec opcode and use it to implement "PRAGMA analyze_as_needed", X-Git-Tag: version-3.18.0~81^2~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4a54bb579480352dce25d2982b2f266c58255248;p=thirdparty%2Fsqlite.git Add the OP_SqlExec opcode and use it to implement "PRAGMA analyze_as_needed", invoking ANALYZE subcommands as necessary. This simplifies the implementation. FossilOrigin-Name: d386015f5e7ecdd951d70db56b7bbd858be7ad90 --- diff --git a/manifest b/manifest index 5af18e20b2..984bdbb4fc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\serrors\sin\sthe\stable\sresize\sdetection. -D 2017-02-18T02:42:54.892 +C Add\sthe\sOP_SqlExec\sopcode\sand\suse\sit\sto\simplement\s"PRAGMA\sanalyze_as_needed",\ninvoking\sANALYZE\ssubcommands\sas\snecessary.\s\sThis\ssimplifies\sthe\simplementation. +D 2017-02-18T15:58:52.451 F Makefile.in edb6bcdd37748d2b1c3422ff727c748df7ffe918 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc a89ea37ab5928026001569f056973b9059492fe2 @@ -331,7 +331,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c 3b23977620ce9662ac54443f65b87ba996e36121 -F src/analyze.c e01e5362ba2ac8430ab7833022afb6081ade8315 +F src/analyze.c 1b7197d619788353437d390de42a9bccbb4aa2ac F src/attach.c 8c476f8bd5d2afe11d925f890d30e527e5b0ce43 F src/auth.c 930b376a9c56998557367e6f7f8aaeac82a2a792 F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b @@ -387,7 +387,7 @@ F src/parse.y 591704fce84f814d9a3642774c1f011d38f4149c F src/pcache.c 62835bed959e2914edd26afadfecce29ece0e870 F src/pcache.h 2cedcd8407eb23017d92790b112186886e179490 F src/pcache1.c e3967219b2a92b9edcb9324a4ba75009090d3953 -F src/pragma.c cf0f101d2986d258699cbbd249392858ec9a6b7e +F src/pragma.c 1ed159f6fed5af7f5b095f55bdefcb0848956397 F src/pragma.h 065e184494f12e94111da1ab6984faa7b6142e68 F src/prepare.c b1140c3d0cf59bc85ace00ce363153041b424b7a F src/printf.c 67427bbee66d891fc6f6f5aada857e9cdb368c1c @@ -399,7 +399,7 @@ F src/shell.c bb8e20789499aec921a01d8744c616b81b8214f1 F src/sqlite.h.in 751ff125eb159c8f92c182b8df980a5e4f50e966 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae -F src/sqliteInt.h 70abfa92e02688f1d189bf63fd25d309ca8d8d1e +F src/sqliteInt.h 87857c2b8d8825e22970ce3f466b8618ee55b44e F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247 F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -461,7 +461,7 @@ F src/update.c 456d4a4656f8a03c2abc88a51b19172197400e58 F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c F src/util.c ca8440ede81e155d15cff7c101654f60b55a9ae6 F src/vacuum.c 33c174b28886b2faf26e503b5a49a1c01a9b1c16 -F src/vdbe.c ac8538b96af5c63d6f18484ffd981d4f44db0073 +F src/vdbe.c 02f9db522c73ba4e1743585e9fd6f8ac6c71515b F src/vdbe.h 59998ffd71d7caa8886bc78dafaf8caeccd4c13c F src/vdbeInt.h 4e4b15b2e1330e1636e4e01974eab2b0b985092f F src/vdbeapi.c 3e4a8893feeb78620f4aac4ac5b85d92255b97e1 @@ -1557,7 +1557,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 882599a4a7ea92c9e7752e0745475508e58a11c3 -R cf9f80fd407d6e9e7cfac9c2957017b5 +P 4229caec0b60a1617b9d5ff94b47271cbd7be1e0 +R 03be76497e56750b0101f816e3587990 U drh -Z 225df65ba1e601aba9cbc975df68b3a8 +Z 8d178351b984357dd4d18d50fe476798 diff --git a/manifest.uuid b/manifest.uuid index 07d49087a1..323aca9202 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4229caec0b60a1617b9d5ff94b47271cbd7be1e0 \ No newline at end of file +d386015f5e7ecdd951d70db56b7bbd858be7ad90 \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 118cdb9383..3ecf469cd3 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -958,12 +958,10 @@ static void analyzeOneTable( Index *pOnlyIdx, /* If not NULL, only analyze this one index */ int iStatCur, /* Index of VdbeCursor that writes the sqlite_stat1 table */ int iMem, /* Available memory locations begin here */ - int iTab, /* Next available cursor */ - LogEst szOld /* Run the analysis if table row count is larger than this */ + int iTab /* Next available cursor */ ){ sqlite3 *db = pParse->db; /* Database handle */ Index *pIdx; /* An index to being analyzed */ - int addrSizeCk = 0; /* Address of the IfSmaller */ int iIdxCur; /* Cursor open on index being analyzed */ int iTabCur; /* Table cursor */ Vdbe *v; /* The virtual machine being built up */ @@ -971,7 +969,6 @@ static void analyzeOneTable( int jZeroRows = -1; /* Jump from here if number of rows is zero */ int iDb; /* Index of database containing pTab */ u8 needTableCnt = 1; /* True to count the table */ - int regWorkDone = iMem++; /* Set to 1 if any work is done */ int regNewRowid = iMem++; /* Rowid for the inserted record */ int regStat4 = iMem++; /* Register to hold Stat4Accum object */ int regChng = iMem++; /* Index of changed index field */ @@ -1017,10 +1014,6 @@ static void analyzeOneTable( iIdxCur = iTab++; pParse->nTab = MAX(pParse->nTab, iTab); sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); - if( szOld>0 ){ - addrSizeCk = sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur, 0, szOld); - VdbeCoverage(v); - } sqlite3VdbeLoadString(v, regTabname, pTab->zName); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ @@ -1278,107 +1271,43 @@ static void analyzeOneTable( sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeJumpHere(v, jZeroRows); } - sqlite3VdbeAddOp2(v, OP_Integer, 1, regWorkDone); - VdbeComment((v, "work was done")); - sqlite3VdbeJumpHere(v, addrSizeCk); } + /* -** Return true if table pTab might need to being reanalyzed. Return -** false if we know that pTab should not be reanalyzed. -** -** If returning true, also set *pThreshold to a size threshold that -** will determine at run-time whether or not the reanalysis occurs. -** The reanalysis will only occur if the size of the table is greater -** than the threshold. Not that the threshold is a logarithmic LogEst -** value. +** Generate code that will cause the most recent index analysis to +** be loaded into internal hash tables where is can be used. */ -static int analyzeNeeded(Table *pTab, LogEst *pThreshold){ - Index *pIdx; - if( (pTab->tabFlags & TF_StatsUsed)==0 ) return 0; - - /* If TF_StatsUsed is true, then we might need to reanalyze. - ** TUNING: Only reanalyze if the table size has grown by a factor - ** of 25 or more. */ - *pThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 ); - - /* Except, if any of the indexes of the table do not have valid - ** sqlite_stat1 entries, then set the size threshold to zero to - ** ensure the analysis will always occur. */ - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( !pIdx->hasStat1 ){ - *pThreshold = 0; - break; - } +static void loadAnalysis(Parse *pParse, int iDb){ + Vdbe *v = sqlite3GetVdbe(pParse); + if( v ){ + sqlite3VdbeAddOp1(v, OP_LoadAnalysis, iDb); } - return 1; } /* -** Generate code that will do an analysis of an entire database, or -** all databases in the connection if iDbReq is negative. -** -** If onlyIfNeeded is true, then only run the analysis if SQLite thinks -** it is actually needed. +** Generate code that will do an analysis of an entire database */ -void sqlite3AnalyzeDatabase( - Parse *pParse, /* The parsing context */ - int iDbReq, /* Which schema to analyze. -1 for all (except TEMP) */ - int onlyIfNeeded /* Only do the analysis if needed, when true */ -){ +static void analyzeDatabase(Parse *pParse, int iDb){ sqlite3 *db = pParse->db; - Schema *pSchema; + Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */ HashElem *k; - int iStatCur = 0; - int iMem = 0; - int iTab = 0; - int iDb; /* Database currently being analyzed */ - int iDbFirst, iDbLast; /* Range of databases to be analyzed */ - int bStatTabs = 0; - Vdbe *v = sqlite3GetVdbe(pParse); - int nHit = 0; - unsigned char aHit[SQLITE_MAX_ATTACHED+2]; + int iStatCur; + int iMem; + int iTab; - if( v==0 ) return; - if( iDbReq>=0 ){ - iDbFirst = iDbLast = iDbReq; - }else{ - iDbFirst = 0; - iDbLast = db->nDb-1; - } - for(iDb=iDbFirst; iDb<=iDbLast; iDb++, bStatTabs=0){ - if( iDb==1 ) continue; /* Do not analyze the TEMP database */ - pSchema = db->aDb[iDb].pSchema; - assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ - Table *pTab = (Table*)sqliteHashData(k); - LogEst szThreshold = 0; - if( !onlyIfNeeded || analyzeNeeded(pTab, &szThreshold) ){ - if( iMem==0 ){ - iStatCur = pParse->nTab; - pParse->nTab += 3; - iMem = pParse->nMem+1; - iTab = pParse->nTab; - sqlite3VdbeAddOp2(v, OP_Integer, 0, iMem); - } - if( !bStatTabs ){ - aHit[nHit++] = iDb; - sqlite3BeginWriteOperation(pParse, 0, iDb); - openStatTable(pParse, iDb, iStatCur, 0, 0); - bStatTabs = 1; - } - analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab, szThreshold); - } - } - } - if( iMem ){ - int addrTop = sqlite3VdbeAddOp1(v, OP_IfNot, iMem); VdbeCoverage(v); - for(iDb=0; iDbnTab; + pParse->nTab += 3; + openStatTable(pParse, iDb, iStatCur, 0, 0); + iMem = pParse->nMem+1; + iTab = pParse->nTab; + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ + Table *pTab = (Table*)sqliteHashData(k); + analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab); } + loadAnalysis(pParse, iDb); } /* @@ -1389,7 +1318,6 @@ void sqlite3AnalyzeDatabase( static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){ int iDb; int iStatCur; - Vdbe *v; assert( pTab!=0 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); @@ -1402,13 +1330,8 @@ static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){ }else{ openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl"); } - analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur, pParse->nMem+1, - pParse->nTab, 0); - v = sqlite3GetVdbe(pParse); - if( v ){ - sqlite3VdbeAddOp1(v, OP_LoadAnalysis, iDb); - sqlite3VdbeAddOp0(v, OP_Expire); - } + analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur,pParse->nMem+1,pParse->nTab); + loadAnalysis(pParse, iDb); } /* @@ -1422,19 +1345,16 @@ static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){ ** Form 1 causes all indices in all attached databases to be analyzed. ** Form 2 analyzes all indices the single database named. ** Form 3 analyzes all indices associated with the named table. -** -** If pName1 and pName2 are both NULL and if the ifNeeded flag is true, -** this routine computes an conditional ANALYZE on only those tables -** are believed to be in need of analysis. The conditional analysis -** might well be a no-op. */ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ sqlite3 *db = pParse->db; int iDb; + int i; char *z, *zDb; Table *pTab; Index *pIdx; Token *pTableName; + Vdbe *v; /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ @@ -1446,12 +1366,15 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ assert( pName2!=0 || pName1==0 ); if( pName1==0 ){ /* Form 1: Analyze everything */ - sqlite3AnalyzeDatabase(pParse, -1, 0); + for(i=0; inDb; i++){ + if( i==1 ) continue; /* Do not analyze the TEMP database */ + analyzeDatabase(pParse, i); + } }else if( pName2->n==0 ){ /* Form 2: Analyze the database or table named */ iDb = sqlite3FindDb(db, pName1); if( iDb>=0 ){ - sqlite3AnalyzeDatabase(pParse, iDb, 0); + analyzeDatabase(pParse, iDb); }else{ z = sqlite3NameFromToken(db, pName1); if( z ){ @@ -1479,6 +1402,8 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ } } } + v = sqlite3GetVdbe(pParse); + if( v ) sqlite3VdbeAddOp0(v, OP_Expire); } /* diff --git a/src/pragma.c b/src/pragma.c index 3bcf62f69f..49d711ded7 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1832,7 +1832,41 @@ void sqlite3Pragma( ** PRAGMA analyze_as_needed */ case PragTyp_ANALYZE_AS_NEEDED: { - sqlite3AnalyzeDatabase(pParse, zDb ? iDb : -1, 1); + int iDbLast; + int iTabCur; + HashElem *k; + Schema *pSchema; + Table *pTab; + Index *pIdx; + LogEst szThreshold; + char *zSubSql; + + iTabCur = pParse->nTab++; + for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){ + if( iDb==1 ) continue; + sqlite3CodeVerifySchema(pParse, iDb); + pSchema = db->aDb[iDb].pSchema; + for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ + pTab = (Table*)sqliteHashData(k); + if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue; + szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 ); + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( !pIdx->hasStat1 ){ + szThreshold = 0; + break; + } + } + if( szThreshold ){ + sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); + sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur, + sqlite3VdbeCurrentAddr(v)+2, szThreshold); + VdbeCoverage(v); + } + zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"", + db->aDb[iDb].zDbSName, pTab->zName); + sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC); + } + } break; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 218c2c6af6..19c7481223 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4028,7 +4028,6 @@ void sqlite3AlterBeginAddColumn(Parse *, SrcList *); CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); char sqlite3AffinityType(const char*, u8*); void sqlite3Analyze(Parse*, Token*, Token*); -void sqlite3AnalyzeDatabase(Parse*,int,int); int sqlite3InvokeBusyHandler(BusyHandler*); int sqlite3FindDb(sqlite3*, Token*); int sqlite3FindDbName(sqlite3 *, const char *); diff --git a/src/vdbe.c b/src/vdbe.c index b595c4fb01..b8050e8d50 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -5518,6 +5518,16 @@ case OP_CreateTable: { /* out2 */ break; } +/* Opcode: SqlExec * * * P4 * +** +** Run the SQL statement or statements specified in the P4 string. +*/ +case OP_SqlExec: { + rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0); + if( rc ) goto abort_due_to_error; + break; +} + /* Opcode: ParseSchema P1 * * P4 * ** ** Read and parse all entries from the SQLITE_MASTER table of database P1