-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
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
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
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
#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 */
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
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
+ 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];
#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 */
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);
}
/*
-** 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,
}
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
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;
*/
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);
int regSampleRowid = regCol + nCol;
int addrNext;
int addrIsNull;
+ u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
pParse->nMem = MAX(pParse->nMem, regCol+nCol+1);
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);