From afa1ecac9b6fba76861dca85b211ca1022f9e378 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 9 Mar 2020 18:26:11 +0000 Subject: [PATCH] Cleaner separation of the STAT4-specific logic in the implementation of ANALYZE. patch reference: https://www.sqlite.org/src/info/3df07e5a9a3781a4 FossilOrigin-Name: 3df07e5a9a3781a4cf866fc6ee0e5c6f9cd7ca35ce0a6eb3aa7f5f3502e0ffae --- src/analyze.c | 113 +++++++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 57 deletions(-) diff --git a/src/analyze.c b/src/analyze.c index 2a071ef..daf3af7 100644 --- a/src/analyze.c +++ b/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,30 @@ 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 +308,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 +324,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 +337,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; @@ -352,8 +355,8 @@ static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){ /* ** Reclaim all memory of a Stat4Accum 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; inCol; i++) sampleClear(p->db, p->aBest+i); @@ -381,8 +384,8 @@ 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 +** 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 Stat4Accum ** object. */ @@ -391,7 +394,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 +413,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 +448,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 +469,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 +496,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 +520,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 +542,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). */ 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 +565,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 +584,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; @@ -623,6 +626,7 @@ find_new_min: } } #endif /* SQLITE_ENABLE_STAT4 */ +#ifdef SQLITE_ENABLE_STAT4 /* ** Field iChng of the index being scanned has changed. So at this point @@ -630,14 +634,13 @@ find_new_min: ** 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->nSamplemxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){ sampleInsert(p, pBest, i); @@ -661,19 +664,14 @@ 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. @@ -693,7 +691,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,8 +704,9 @@ static void statPush( for(i=0; inCol; 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. */ for(i=0; iiGet = 0; } if( p->iGetnSample ){ - 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() */ -- 2.23.0