]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the OP_SqlExec opcode and use it to implement "PRAGMA analyze_as_needed",
authordrh <drh@noemail.net>
Sat, 18 Feb 2017 15:58:52 +0000 (15:58 +0000)
committerdrh <drh@noemail.net>
Sat, 18 Feb 2017 15:58:52 +0000 (15:58 +0000)
invoking ANALYZE subcommands as necessary.  This simplifies the implementation.

FossilOrigin-Name: d386015f5e7ecdd951d70db56b7bbd858be7ad90

manifest
manifest.uuid
src/analyze.c
src/pragma.c
src/sqliteInt.h
src/vdbe.c

index 5af18e20b22d176d23617f4a4908eca495b03862..984bdbb4fcef3612484422994945bd86a41142e3 100644 (file)
--- 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
index 07d49087a1be8bd613840216c93b94e318bf2bb4..323aca9202b473bf3cf3b3970c8ed1ec05baff4a 100644 (file)
@@ -1 +1 @@
-4229caec0b60a1617b9d5ff94b47271cbd7be1e0
\ No newline at end of file
+d386015f5e7ecdd951d70db56b7bbd858be7ad90
\ No newline at end of file
index 118cdb93830c2a9550a34a3a8a5dc8d6132840bd..3ecf469cd38a3837a733a6484d3a1266853dc3e0 100644 (file)
@@ -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; iDb<nHit; iDb++){
-      sqlite3VdbeAddOp1(v, OP_LoadAnalysis, aHit[iDb]);
-    }
-    sqlite3VdbeAddOp0(v, OP_Expire);
-    sqlite3VdbeJumpHere(v, addrTop);
+  sqlite3BeginWriteOperation(pParse, 0, iDb);
+  iStatCur = pParse->nTab;
+  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; i<db->nDb; 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);
 }
 
 /*
index 3bcf62f69fe7b60e058c152ee09b288b5d2b7059..49d711ded7dd79b2ff6b21b2ee64c2a18a3863e0 100644 (file)
@@ -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;
   }
 
index 218c2c6af6c853d5b20524b7e796633068203daa..19c7481223b55745de9d907836afeadc01a69358 100644 (file)
@@ -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 *);
index b595c4fb01b96abbc3c0e6d6997ee5939d95f66d..b8050e8d506ed5843957437cbab1511f8179610e 100644 (file)
@@ -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