]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Update the ANALYZE logic so that it works with WITHOUT ROWID tables.
authordrh <drh@noemail.net>
Sat, 2 Nov 2013 18:46:04 +0000 (18:46 +0000)
committerdrh <drh@noemail.net>
Sat, 2 Nov 2013 18:46:04 +0000 (18:46 +0000)
FossilOrigin-Name: 9075770e4030b35677fbbe291f3c3c4946937a9a

manifest
manifest.uuid
src/analyze.c
test/without_rowid1.test

index c01b546d054a589a99179fbbf33420ca43cdbbac..639c93061ece55dec8821b3f49ad740696eaad40 100644 (file)
--- 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
index 2764a20dcaae4981b43d6f18ed800a4db8394962..12db755f4b53c8fd63060a2984a74a71da87c79f 100644 (file)
@@ -1 +1 @@
-b7544bb280f1c1c55135a9b35aeb85604fef94a3
\ No newline at end of file
+9075770e4030b35677fbbe291f3c3c4946937a9a
\ No newline at end of file
index d04e51da6e1c05b03b8751e7edd9aa2f9a714f6e..4d88a91ade1aa7473ed73bcf346c4da07d405933 100644 (file)
@@ -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; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
+  for(i=0; i<p->mxSample; 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->iGet<p->nSample ){
-      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; j<pPk->nKeyCol; 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);
index 7abbc07cfd87aa60b2697aff5b4351a3427e3642..9e3782838569e28bf53f696dfd6e3d4f92d18cb5 100644 (file)
@@ -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