aboutsummaryrefslogtreecommitdiff
path: root/src/analyze.c
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2013-10-10 20:13:18 +0000
committerdrh <drh@noemail.net>2013-10-10 20:13:18 +0000
commita63b85299290b7eca076ea6e031e7f43d4feadcf (patch)
treee925eb05965ec76f37b6483581d5bd8f8ea9e53b /src/analyze.c
parent59255f9a98381960cfede9253277f128895531f6 (diff)
parent7e65c94bdc689bebd222321dec5c034194267ac9 (diff)
downloadsqlite-a63b85299290b7eca076ea6e031e7f43d4feadcf.tar.gz
sqlite-a63b85299290b7eca076ea6e031e7f43d4feadcf.zip
Synchronize with the trunk.
FossilOrigin-Name: 136445ba020c9475d3f5a7843d7d0add98477138
Diffstat (limited to 'src/analyze.c')
-rw-r--r--src/analyze.c149
1 files changed, 90 insertions, 59 deletions
diff --git a/src/analyze.c b/src/analyze.c
index 89dc84f2c..c83133a4d 100644
--- a/src/analyze.c
+++ b/src/analyze.c
@@ -347,7 +347,7 @@ static void statInit(
p->mxSample = mxSample;
p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[1])/(mxSample/3+1) + 1);
p->current.anLt = &p->current.anEq[nColUp];
- sqlite3_randomness(sizeof(p->iPrn), &p->iPrn);
+ p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[1])*0xd0944565;
/* Set up the Stat4Accum.a[] and aBest[] arrays */
p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
@@ -371,8 +371,7 @@ static void statInit(
}
static const FuncDef statInitFuncdef = {
1+IsStat34, /* nArg */
- SQLITE_UTF8, /* iPrefEnc */
- 0, /* flags */
+ SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
statInit, /* xFunc */
@@ -383,24 +382,63 @@ static const FuncDef statInitFuncdef = {
0 /* pDestructor */
};
+#ifdef SQLITE_ENABLE_STAT4
+/*
+** pNew and pOld are both candidate non-periodic samples selected for
+** the same column (pNew->iCol==pOld->iCol). Ignoring this column and
+** considering only any trailing columns and the sample hash value, this
+** function returns true if sample pNew is to be preferred over pOld.
+** In other words, if we assume that the cardinalities of the selected
+** column for pNew and pOld are equal, is pNew to be preferred over pOld.
+**
+** This function assumes that for each argument sample, the contents of
+** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid.
+*/
+static int sampleIsBetterPost(
+ Stat4Accum *pAccum,
+ Stat4Sample *pNew,
+ Stat4Sample *pOld
+){
+ int nCol = pAccum->nCol;
+ int i;
+ assert( pNew->iCol==pOld->iCol );
+ for(i=pNew->iCol+1; i<nCol; i++){
+ if( pNew->anEq[i]>pOld->anEq[i] ) return 1;
+ if( pNew->anEq[i]<pOld->anEq[i] ) return 0;
+ }
+ if( pNew->iHash>pOld->iHash ) return 1;
+ return 0;
+}
+#endif
+
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
/*
** Return true if pNew is to be preferred over pOld.
+**
+** This function assumes that for each argument sample, the contents of
+** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid.
*/
-static int sampleIsBetter(Stat4Sample *pNew, Stat4Sample *pOld){
+static int sampleIsBetter(
+ Stat4Accum *pAccum,
+ Stat4Sample *pNew,
+ Stat4Sample *pOld
+){
tRowcnt nEqNew = pNew->anEq[pNew->iCol];
tRowcnt nEqOld = pOld->anEq[pOld->iCol];
assert( pOld->isPSample==0 && pNew->isPSample==0 );
assert( IsStat4 || (pNew->iCol==0 && pOld->iCol==0) );
- if( (nEqNew>nEqOld)
- || (nEqNew==nEqOld && pNew->iCol<pOld->iCol)
- || (nEqNew==nEqOld && pNew->iCol==pOld->iCol && pNew->iHash>pOld->iHash)
- ){
- return 1;
+ if( (nEqNew>nEqOld) ) return 1;
+#ifdef SQLITE_ENABLE_STAT4
+ if( nEqNew==nEqOld ){
+ if( pNew->iCol<pOld->iCol ) return 1;
+ return (pNew->iCol==pOld->iCol && sampleIsBetterPost(pAccum, pNew, pOld));
}
return 0;
+#else
+ return (nEqNew==nEqOld && pNew->iHash>pOld->iHash);
+#endif
}
/*
@@ -423,11 +461,10 @@ void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
Stat4Sample *pSample;
int i;
- i64 iSeq;
- int iPos;
assert( IsStat4 || nEqZero==0 );
+#ifdef SQLITE_ENABLE_STAT4
if( pNew->isPSample==0 ){
Stat4Sample *pUpgrade = 0;
assert( pNew->anEq[pNew->iCol]>0 );
@@ -441,8 +478,9 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
Stat4Sample *pOld = &p->a[i];
if( pOld->anEq[pNew->iCol]==0 ){
if( pOld->isPSample ) return;
- assert( sampleIsBetter(pNew, pOld) );
- if( pUpgrade==0 || sampleIsBetter(pOld, pUpgrade) ){
+ assert( pOld->iCol>pNew->iCol );
+ assert( sampleIsBetter(p, pNew, pOld) );
+ if( pUpgrade==0 || sampleIsBetter(p, pOld, pUpgrade) ){
pUpgrade = pOld;
}
}
@@ -453,6 +491,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
goto find_new_min;
}
}
+#endif
/* If necessary, remove sample iMin to make room for the new sample. */
if( p->nSample>=p->mxSample ){
@@ -481,34 +520,17 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
sampleCopy(p, pSample, pNew);
p->nSample++;
-#if 0
- iSeq = pNew->anLt[p->nCol-1];
- for(iPos=p->nSample; iPos>0; iPos--){
- if( iSeq>p->a[iPos-1].anLt[p->nCol-1] ) break;
- }
-
- if( iPos!=p->nSample ){
- Stat4Sample *pEnd = &p->a[p->nSample];
- tRowcnt *anEq = pEnd->anEq;
- tRowcnt *anLt = pEnd->anLt;
- tRowcnt *anDLt = pEnd->anDLt;
- memmove(&p->a[iPos], &p->a[iPos+1], (p->nSample-iPos)*sizeof(p->a[0]));
- pSample->anEq = anEq;
- pSample->anDLt = anDLt;
- pSample->anLt = anLt;
- }
-#endif
-
-
/* Zero the first nEqZero entries in the anEq[] array. */
memset(pSample->anEq, 0, sizeof(tRowcnt)*nEqZero);
+#ifdef SQLITE_ENABLE_STAT4
find_new_min:
+#endif
if( p->nSample>=p->mxSample ){
int iMin = -1;
for(i=0; i<p->mxSample; i++){
if( p->a[i].isPSample ) continue;
- if( iMin<0 || sampleIsBetter(&p->a[iMin], &p->a[i]) ){
+ if( iMin<0 || sampleIsBetter(p, &p->a[iMin], &p->a[i]) ){
iMin = i;
}
}
@@ -532,9 +554,8 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
** into IndexSample.a[] at this point. */
for(i=(p->nCol-2); i>=iChng; i--){
Stat4Sample *pBest = &p->aBest[i];
- if( p->nSample<p->mxSample
- || sampleIsBetter(pBest, &p->a[p->iMin])
- ){
+ pBest->anEq[i] = p->current.anEq[i];
+ if( p->nSample<p->mxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){
sampleInsert(p, pBest, i);
}
}
@@ -561,7 +582,9 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
}else
/* Or if it is a non-periodic sample. Add it in this case too. */
- if( p->nSample<p->mxSample || sampleIsBetter(&p->current, &p->a[p->iMin]) ){
+ if( p->nSample<p->mxSample
+ || sampleIsBetter(p, &p->current, &p->a[p->iMin])
+ ){
sampleInsert(p, &p->current, 0);
}
}
@@ -635,7 +658,7 @@ static void statPush(
/* Update the aBest[] array. */
for(i=0; i<(p->nCol-1); i++){
p->current.iCol = i;
- if( i>=iChng || sampleIsBetter(&p->current, &p->aBest[i]) ){
+ if( i>=iChng || sampleIsBetterPost(p, &p->current, &p->aBest[i]) ){
sampleCopy(p, &p->aBest[i], &p->current);
}
}
@@ -644,8 +667,7 @@ static void statPush(
}
static const FuncDef statPushFuncdef = {
2+IsStat34, /* nArg */
- SQLITE_UTF8, /* iPrefEnc */
- 0, /* flags */
+ SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
statPush, /* xFunc */
@@ -721,12 +743,12 @@ static void statGet(
return;
}
- sqlite3_snprintf(24, zRet, "%lld", p->nRow);
+ sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow);
z = zRet + sqlite3Strlen30(zRet);
for(i=0; i<(p->nCol-1); i++){
- i64 nDistinct = p->current.anDLt[i] + 1;
- i64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
- sqlite3_snprintf(24, z, " %lld", iVal);
+ u64 nDistinct = p->current.anDLt[i] + 1;
+ u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
+ sqlite3_snprintf(24, z, " %llu", iVal);
z += sqlite3Strlen30(z);
assert( p->current.anEq[i] );
}
@@ -767,7 +789,7 @@ static void statGet(
int i;
char *z = zRet;
for(i=0; i<p->nCol; i++){
- sqlite3_snprintf(24, z, "%lld ", aCnt[i]);
+ sqlite3_snprintf(24, z, "%llu ", (u64)aCnt[i]);
z += sqlite3Strlen30(z);
}
assert( z[0]=='\0' && z>zRet );
@@ -780,8 +802,7 @@ static void statGet(
}
static const FuncDef statGetFuncdef = {
1+IsStat34, /* nArg */
- SQLITE_UTF8, /* iPrefEnc */
- 0, /* flags */
+ SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
statGet, /* xFunc */
@@ -1229,18 +1250,16 @@ struct analysisInfo {
** the array aOut[].
*/
static void decodeIntArray(
- char *zIntArray,
- int nOut,
- tRowcnt *aOut,
- int *pbUnordered
+ char *zIntArray, /* String containing int array to decode */
+ int nOut, /* Number of slots in aOut[] */
+ tRowcnt *aOut, /* Store integers here */
+ Index *pIndex /* Handle extra flags for this index, if not NULL */
){
char *z = zIntArray;
int c;
int i;
tRowcnt v;
- assert( pbUnordered==0 || *pbUnordered==0 );
-
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( z==0 ) z = "";
#else
@@ -1255,8 +1274,19 @@ static void decodeIntArray(
aOut[i] = v;
if( *z==' ' ) z++;
}
- if( pbUnordered && strcmp(z, "unordered")==0 ){
- *pbUnordered = 1;
+#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
+ assert( pIndex!=0 );
+#else
+ if( pIndex )
+#endif
+ {
+ if( strcmp(z, "unordered")==0 ){
+ pIndex->bUnordered = 1;
+ }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
+ int v32 = 0;
+ sqlite3GetInt32(z+3, &v32);
+ pIndex->szIdxRow = sqlite3LogEst(v32);
+ }
}
}
@@ -1295,12 +1325,13 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
z = argv[2];
if( pIndex ){
- int bUnordered = 0;
- decodeIntArray((char*)z, pIndex->nColumn+1, pIndex->aiRowEst,&bUnordered);
+ decodeIntArray((char*)z, pIndex->nColumn+1, pIndex->aiRowEst, pIndex);
if( pIndex->pPartIdxWhere==0 ) pTable->nRowEst = pIndex->aiRowEst[0];
- pIndex->bUnordered = bUnordered;
}else{
- decodeIntArray((char*)z, 1, &pTable->nRowEst, 0);
+ Index fakeIdx;
+ fakeIdx.szIdxRow = pTable->szTabRow;
+ decodeIntArray((char*)z, 1, &pTable->nRowEst, &fakeIdx);
+ pTable->szTabRow = fakeIdx.szIdxRow;
}
return 0;