Cleaner separation of the STAT4-specific logic in the implementation of
ANALYZE. FossilOrigin-Name: 3df07e5a9a3781a4cf866fc6ee0e5c6f9cd7ca35ce0a6eb3aa7f5f3502e0ffae
This commit is contained in:
parent
ccb3781673
commit
afa1ecac9b
12
manifest
12
manifest
@ -1,5 +1,5 @@
|
||||
C Enhancements\sto\sthe\s".import"\scommand\sof\sthe\sCLI.
|
||||
D 2020-03-09T15:39:39.029
|
||||
C Cleaner\sseparation\sof\sthe\sSTAT4-specific\slogic\sin\sthe\simplementation\sof\nANALYZE.
|
||||
D 2020-03-09T18:26:11.821
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -466,7 +466,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c f48a4423c8f198d7f1ae4940f74b606707d05384ac79fb219be8e3323af2a2de
|
||||
F src/analyze.c b3ceec3fc052df8a96ca8a8c858d455dc5029ba681b4be98bb5c5a9162cfa58c
|
||||
F src/analyze.c 831bb090988477a00d3b4c000746e1b0454dcc93b10b793e6ebe1c47f25d193a
|
||||
F src/attach.c fa5addce233a2bb2dfdefeee3b37000e154c47214d3269cab1bb331416e330db
|
||||
F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06
|
||||
F src/backup.c 5e617c087f1c2d6005c2ec694ce80d6e16bc68d906e1b1c556d7c7c2228b636b
|
||||
@ -1860,7 +1860,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 86465c08f4d629a296332a7985937326ac43ea2822c5651bf03862cd79d370fc
|
||||
R 59ca84b4f9c863c565a73d91cc01fad5
|
||||
P cab1834cfc71f71bfed3c5170a0ba40a39385c3b2c50b7c6b6f09cc830dd1b1e
|
||||
R c62e646df7b5e5719c4a0602837bf1ef
|
||||
U drh
|
||||
Z ca4df02a4f4403d62ad30a31c55381b8
|
||||
Z 8147aa7ce1e35e16be35124cd1704d38
|
||||
|
@ -1 +1 @@
|
||||
cab1834cfc71f71bfed3c5170a0ba40a39385c3b2c50b7c6b6f09cc830dd1b1e
|
||||
3df07e5a9a3781a4cf866fc6ee0e5c6f9cd7ca35ce0a6eb3aa7f5f3502e0ffae
|
123
src/analyze.c
123
src/analyze.c
@ -256,9 +256,9 @@ static void openStatTable(
|
||||
** share an instance of the following structure to hold their state
|
||||
** information.
|
||||
*/
|
||||
typedef struct Stat4Accum Stat4Accum;
|
||||
typedef struct Stat4Sample Stat4Sample;
|
||||
struct Stat4Sample {
|
||||
typedef struct StatAccum StatAccum;
|
||||
typedef struct StatSample StatSample;
|
||||
struct StatSample {
|
||||
tRowcnt *anEq; /* sqlite_stat4.nEq */
|
||||
tRowcnt *anDLt; /* sqlite_stat4.nDLt */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
@ -273,27 +273,29 @@ struct Stat4Sample {
|
||||
u32 iHash; /* Tiebreaker hash */
|
||||
#endif
|
||||
};
|
||||
struct Stat4Accum {
|
||||
struct StatAccum {
|
||||
sqlite3 *db; /* Database connection, for malloc() */
|
||||
tRowcnt nRow; /* Number of rows in the entire table */
|
||||
tRowcnt nPSample; /* How often to do a periodic sample */
|
||||
int nCol; /* Number of columns in index + pk/rowid */
|
||||
int nKeyCol; /* Number of index columns w/o the pk/rowid */
|
||||
StatSample current; /* Current row as a StatSample */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
tRowcnt nPSample; /* How often to do a periodic sample */
|
||||
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 best samples */
|
||||
StatSample *aBest; /* Array of nCol best samples */
|
||||
int iMin; /* Index in a[] of entry with minimum score */
|
||||
int nSample; /* Current number of samples */
|
||||
int nMaxEqZero; /* Max leading 0 in anEq[] for any a[] entry */
|
||||
int iGet; /* Index of current sample accessed by stat_get() */
|
||||
Stat4Sample *a; /* Array of mxSample Stat4Sample objects */
|
||||
sqlite3 *db; /* Database connection, for malloc() */
|
||||
StatSample *a; /* Array of mxSample StatSample objects */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Reclaim memory used by a Stat4Sample
|
||||
/* Reclaim memory used by a StatSample
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void sampleClear(sqlite3 *db, Stat4Sample *p){
|
||||
static void sampleClear(sqlite3 *db, StatSample *p){
|
||||
assert( db!=0 );
|
||||
if( p->nRowid ){
|
||||
sqlite3DbFree(db, p->u.aRowid);
|
||||
@ -305,7 +307,7 @@ static void sampleClear(sqlite3 *db, Stat4Sample *p){
|
||||
/* Initialize the BLOB value of a ROWID
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
|
||||
static void sampleSetRowid(sqlite3 *db, StatSample *p, int n, const u8 *pData){
|
||||
assert( db!=0 );
|
||||
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
|
||||
p->u.aRowid = sqlite3DbMallocRawNN(db, n);
|
||||
@ -321,7 +323,7 @@ static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
|
||||
/* Initialize the INTEGER value of a ROWID.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
|
||||
static void sampleSetRowidInt64(sqlite3 *db, StatSample *p, i64 iRowid){
|
||||
assert( db!=0 );
|
||||
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
|
||||
p->nRowid = 0;
|
||||
@ -334,7 +336,7 @@ static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
|
||||
** Copy the contents of object (*pFrom) into (*pTo).
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
|
||||
static void sampleCopy(StatAccum *p, StatSample *pTo, StatSample *pFrom){
|
||||
pTo->isPSample = pFrom->isPSample;
|
||||
pTo->iCol = pFrom->iCol;
|
||||
pTo->iHash = pFrom->iHash;
|
||||
@ -350,10 +352,10 @@ static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Reclaim all memory of a Stat4Accum structure.
|
||||
** Reclaim all memory of a StatAccum structure.
|
||||
*/
|
||||
static void stat4Destructor(void *pOld){
|
||||
Stat4Accum *p = (Stat4Accum*)pOld;
|
||||
static void statAccumDestructor(void *pOld){
|
||||
StatAccum *p = (StatAccum*)pOld;
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int i;
|
||||
for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
|
||||
@ -381,9 +383,9 @@ static void stat4Destructor(void *pOld){
|
||||
** PRIMARY KEY of the table. The covering index that implements the
|
||||
** original WITHOUT ROWID table as N==K as a special case.
|
||||
**
|
||||
** This routine allocates the Stat4Accum object in heap memory. The return
|
||||
** value is a pointer to the Stat4Accum object. The datatype of the
|
||||
** return value is BLOB, but it is really just a pointer to the Stat4Accum
|
||||
** This routine allocates the StatAccum object in heap memory. The return
|
||||
** value is a pointer to the StatAccum object. The datatype of the
|
||||
** return value is BLOB, but it is really just a pointer to the StatAccum
|
||||
** object.
|
||||
*/
|
||||
static void statInit(
|
||||
@ -391,7 +393,7 @@ static void statInit(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
Stat4Accum *p;
|
||||
StatAccum *p;
|
||||
int nCol; /* Number of columns in index being sampled */
|
||||
int nKeyCol; /* Number of key columns */
|
||||
int nColUp; /* nCol rounded up for alignment */
|
||||
@ -410,13 +412,13 @@ static void statInit(
|
||||
assert( nKeyCol<=nCol );
|
||||
assert( nKeyCol>0 );
|
||||
|
||||
/* Allocate the space required for the Stat4Accum object */
|
||||
/* Allocate the space required for the StatAccum object */
|
||||
n = sizeof(*p)
|
||||
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anEq */
|
||||
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */
|
||||
+ sizeof(tRowcnt)*nColUp /* StatAccum.anEq */
|
||||
+ sizeof(tRowcnt)*nColUp /* StatAccum.anDLt */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anLt */
|
||||
+ sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */
|
||||
+ sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
|
||||
+ sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
|
||||
+ sizeof(tRowcnt)*3*nColUp*(nCol+mxSample)
|
||||
#endif
|
||||
;
|
||||
@ -445,8 +447,8 @@ static void statInit(
|
||||
p->current.anLt = &p->current.anEq[nColUp];
|
||||
p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
|
||||
|
||||
/* Set up the Stat4Accum.a[] and aBest[] arrays */
|
||||
p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
|
||||
/* Set up the StatAccum.a[] and aBest[] arrays */
|
||||
p->a = (struct StatSample*)&p->current.anLt[nColUp];
|
||||
p->aBest = &p->a[mxSample];
|
||||
pSpace = (u8*)(&p->a[mxSample+nCol]);
|
||||
for(i=0; i<(mxSample+nCol); i++){
|
||||
@ -466,7 +468,7 @@ static void statInit(
|
||||
** only the pointer (the 2nd parameter) matters. The size of the object
|
||||
** (given by the 3rd parameter) is never used and can be any positive
|
||||
** value. */
|
||||
sqlite3_result_blob(context, p, sizeof(*p), stat4Destructor);
|
||||
sqlite3_result_blob(context, p, sizeof(*p), statAccumDestructor);
|
||||
}
|
||||
static const FuncDef statInitFuncdef = {
|
||||
2+IsStat4, /* nArg */
|
||||
@ -493,9 +495,9 @@ static const FuncDef statInitFuncdef = {
|
||||
** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid.
|
||||
*/
|
||||
static int sampleIsBetterPost(
|
||||
Stat4Accum *pAccum,
|
||||
Stat4Sample *pNew,
|
||||
Stat4Sample *pOld
|
||||
StatAccum *pAccum,
|
||||
StatSample *pNew,
|
||||
StatSample *pOld
|
||||
){
|
||||
int nCol = pAccum->nCol;
|
||||
int i;
|
||||
@ -517,9 +519,9 @@ static int sampleIsBetterPost(
|
||||
** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid.
|
||||
*/
|
||||
static int sampleIsBetter(
|
||||
Stat4Accum *pAccum,
|
||||
Stat4Sample *pNew,
|
||||
Stat4Sample *pOld
|
||||
StatAccum *pAccum,
|
||||
StatSample *pNew,
|
||||
StatSample *pOld
|
||||
){
|
||||
tRowcnt nEqNew = pNew->anEq[pNew->iCol];
|
||||
tRowcnt nEqOld = pOld->anEq[pOld->iCol];
|
||||
@ -539,21 +541,21 @@ static int sampleIsBetter(
|
||||
** Copy the contents of sample *pNew into the p->a[] array. If necessary,
|
||||
** remove the least desirable sample from p->a[] to make room.
|
||||
*/
|
||||
static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
Stat4Sample *pSample = 0;
|
||||
static void sampleInsert(StatAccum *p, StatSample *pNew, int nEqZero){
|
||||
StatSample *pSample = 0;
|
||||
int i;
|
||||
|
||||
assert( IsStat4 || nEqZero==0 );
|
||||
|
||||
/* Stat4Accum.nMaxEqZero is set to the maximum number of leading 0
|
||||
** values in the anEq[] array of any sample in Stat4Accum.a[]. In
|
||||
/* StatAccum.nMaxEqZero is set to the maximum number of leading 0
|
||||
** values in the anEq[] array of any sample in StatAccum.a[]. In
|
||||
** other words, if nMaxEqZero is n, then it is guaranteed that there
|
||||
** are no samples with Stat4Sample.anEq[m]==0 for (m>=n). */
|
||||
** are no samples with StatSample.anEq[m]==0 for (m>=n). */
|
||||
if( nEqZero>p->nMaxEqZero ){
|
||||
p->nMaxEqZero = nEqZero;
|
||||
}
|
||||
if( pNew->isPSample==0 ){
|
||||
Stat4Sample *pUpgrade = 0;
|
||||
StatSample *pUpgrade = 0;
|
||||
assert( pNew->anEq[pNew->iCol]>0 );
|
||||
|
||||
/* This sample is being added because the prefix that ends in column
|
||||
@ -562,7 +564,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
** this one. Instead, upgrade the priority of the highest priority
|
||||
** existing sample that shares this prefix. */
|
||||
for(i=p->nSample-1; i>=0; i--){
|
||||
Stat4Sample *pOld = &p->a[i];
|
||||
StatSample *pOld = &p->a[i];
|
||||
if( pOld->anEq[pNew->iCol]==0 ){
|
||||
if( pOld->isPSample ) return;
|
||||
assert( pOld->iCol>pNew->iCol );
|
||||
@ -581,7 +583,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
|
||||
/* If necessary, remove sample iMin to make room for the new sample. */
|
||||
if( p->nSample>=p->mxSample ){
|
||||
Stat4Sample *pMin = &p->a[p->iMin];
|
||||
StatSample *pMin = &p->a[p->iMin];
|
||||
tRowcnt *anEq = pMin->anEq;
|
||||
tRowcnt *anLt = pMin->anLt;
|
||||
tRowcnt *anDLt = pMin->anDLt;
|
||||
@ -624,20 +626,20 @@ find_new_min:
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/*
|
||||
** Field iChng of the index being scanned has changed. So at this point
|
||||
** p->current contains a sample that reflects the previous row of the
|
||||
** index. The value of anEq[iChng] and subsequent anEq[] elements are
|
||||
** correct at this point.
|
||||
*/
|
||||
static void samplePushPrevious(Stat4Accum *p, int iChng){
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void samplePushPrevious(StatAccum *p, int iChng){
|
||||
int i;
|
||||
|
||||
/* Check if any samples from the aBest[] array should be pushed
|
||||
** into IndexSample.a[] at this point. */
|
||||
for(i=(p->nCol-2); i>=iChng; i--){
|
||||
Stat4Sample *pBest = &p->aBest[i];
|
||||
StatSample *pBest = &p->aBest[i];
|
||||
pBest->anEq[i] = p->current.anEq[i];
|
||||
if( p->nSample<p->mxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){
|
||||
sampleInsert(p, pBest, i);
|
||||
@ -661,25 +663,20 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
|
||||
}
|
||||
p->nMaxEqZero = iChng;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_ENABLE_STAT4
|
||||
UNUSED_PARAMETER( p );
|
||||
UNUSED_PARAMETER( iChng );
|
||||
#endif
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
/*
|
||||
** Implementation of the stat_push SQL function: stat_push(P,C,R)
|
||||
** Arguments:
|
||||
**
|
||||
** P Pointer to the Stat4Accum object created by stat_init()
|
||||
** P Pointer to the StatAccum object created by stat_init()
|
||||
** C Index of left-most column to differ from previous row
|
||||
** R Rowid for the current row. Might be a key record for
|
||||
** WITHOUT ROWID tables.
|
||||
**
|
||||
** This SQL function always returns NULL. It's purpose it to accumulate
|
||||
** statistical data and/or samples in the Stat4Accum object about the
|
||||
** statistical data and/or samples in the StatAccum object about the
|
||||
** index being analyzed. The stat_get() SQL function will later be used to
|
||||
** extract relevant information for constructing the sqlite_statN tables.
|
||||
**
|
||||
@ -693,7 +690,7 @@ static void statPush(
|
||||
int i;
|
||||
|
||||
/* The three function arguments */
|
||||
Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
|
||||
StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]);
|
||||
int iChng = sqlite3_value_int(argv[1]);
|
||||
|
||||
UNUSED_PARAMETER( argc );
|
||||
@ -706,7 +703,9 @@ static void statPush(
|
||||
for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
|
||||
}else{
|
||||
/* Second and subsequent calls get processed here */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
samplePushPrevious(p, iChng);
|
||||
#endif
|
||||
|
||||
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
|
||||
** to the current row of the index. */
|
||||
@ -775,15 +774,15 @@ static const FuncDef statPushFuncdef = {
|
||||
/*
|
||||
** Implementation of the stat_get(P,J) SQL function. This routine is
|
||||
** used to query statistical information that has been gathered into
|
||||
** the Stat4Accum object by prior calls to stat_push(). The P parameter
|
||||
** has type BLOB but it is really just a pointer to the Stat4Accum object.
|
||||
** the StatAccum object by prior calls to stat_push(). The P parameter
|
||||
** has type BLOB but it is really just a pointer to the StatAccum object.
|
||||
** The content to returned is determined by the parameter J
|
||||
** which is one of the STAT_GET_xxxx values defined above.
|
||||
**
|
||||
** The stat_get(P,J) function is not available to generic SQL. It is
|
||||
** inserted as part of a manually constructed bytecode program. (See
|
||||
** the callStatGet() routine below.) It is guaranteed that the P
|
||||
** parameter will always be a poiner to a Stat4Accum object, never a
|
||||
** parameter will always be a pointer to a StatAccum object, never a
|
||||
** NULL.
|
||||
**
|
||||
** If STAT4 is not enabled, then J is always
|
||||
@ -796,7 +795,7 @@ static void statGet(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
|
||||
StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]);
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/* STAT4 has a parameter on this routine. */
|
||||
int eCall = sqlite3_value_int(argv[1]);
|
||||
@ -817,7 +816,7 @@ static void statGet(
|
||||
** the index. The first integer in the list is the total number of
|
||||
** entries in the index. There is one additional integer in the list
|
||||
** for each indexed column. This additional integer is an estimate of
|
||||
** the number of rows matched by a stabbing query on the index using
|
||||
** the number of rows matched by a equality query on the index using
|
||||
** a key with the corresponding number of fields. In other words,
|
||||
** if the index is on columns (a,b) and the sqlite_stat1 value is
|
||||
** "100 10 2", then SQLite estimates that:
|
||||
@ -860,7 +859,7 @@ static void statGet(
|
||||
p->iGet = 0;
|
||||
}
|
||||
if( p->iGet<p->nSample ){
|
||||
Stat4Sample *pS = p->a + p->iGet;
|
||||
StatSample *pS = p->a + p->iGet;
|
||||
if( pS->nRowid==0 ){
|
||||
sqlite3_result_int64(context, pS->u.iRowid);
|
||||
}else{
|
||||
@ -951,7 +950,7 @@ static void analyzeOneTable(
|
||||
int iDb; /* Index of database containing pTab */
|
||||
u8 needTableCnt = 1; /* True to count the table */
|
||||
int regNewRowid = iMem++; /* Rowid for the inserted record */
|
||||
int regStat4 = iMem++; /* Register to hold Stat4Accum object */
|
||||
int regStat4 = iMem++; /* Register to hold StatAccum object */
|
||||
int regChng = iMem++; /* Index of changed index field */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int regRowid = iMem++; /* Rowid argument passed to stat_push() */
|
||||
|
Loading…
Reference in New Issue
Block a user