aboutsummaryrefslogtreecommitdiff
path: root/ext/misc/series.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/misc/series.c')
-rw-r--r--ext/misc/series.c61
1 files changed, 30 insertions, 31 deletions
diff --git a/ext/misc/series.c b/ext/misc/series.c
index 3df0a37e6..03b54d3ce 100644
--- a/ext/misc/series.c
+++ b/ext/misc/series.c
@@ -313,44 +313,44 @@ static int seriesBestIndex(
sqlite3_vtab *tab,
sqlite3_index_info *pIdxInfo
){
- int i; /* Loop over constraints */
+ int i, j; /* Loop over constraints */
int idxNum = 0; /* The query plan bitmask */
- int startIdx = -1; /* Index of the start= constraint, or -1 if none */
- int stopIdx = -1; /* Index of the stop= constraint, or -1 if none */
- int stepIdx = -1; /* Index of the step= constraint, or -1 if none */
+ int unusableMask = 0; /* Mask of unusable constraints */
int nArg = 0; /* Number of arguments that seriesFilter() expects */
-
+ int aIdx[3]; /* Constraints on start, stop, and step */
const struct sqlite3_index_constraint *pConstraint;
+
+ /* This implementation assumes that the start, stop, and step columns
+ ** are the last three columns in the virtual table. */
+ assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
+ assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
+ aIdx[0] = aIdx[1] = aIdx[2] = -1;
pConstraint = pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
- if( pConstraint->usable==0 ) continue;
- if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
- switch( pConstraint->iColumn ){
- case SERIES_COLUMN_START:
- startIdx = i;
- idxNum |= 1;
- break;
- case SERIES_COLUMN_STOP:
- stopIdx = i;
- idxNum |= 2;
- break;
- case SERIES_COLUMN_STEP:
- stepIdx = i;
- idxNum |= 4;
- break;
+ int iCol; /* 0 for start, 1 for stop, 2 for step */
+ int iMask; /* bitmask for those column */
+ if( pConstraint->iColumn<SERIES_COLUMN_START ) continue;
+ iCol = pConstraint->iColumn - SERIES_COLUMN_START;
+ iMask = 1 << iCol;
+ if( pConstraint->usable==0 ){
+ unusableMask |= iMask;
+ continue;
+ }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ idxNum |= iMask;
+ aIdx[iCol] = i;
}
}
- if( startIdx>=0 ){
- pIdxInfo->aConstraintUsage[startIdx].argvIndex = ++nArg;
- pIdxInfo->aConstraintUsage[startIdx].omit= !SQLITE_SERIES_CONSTRAINT_VERIFY;
- }
- if( stopIdx>=0 ){
- pIdxInfo->aConstraintUsage[stopIdx].argvIndex = ++nArg;
- pIdxInfo->aConstraintUsage[stopIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
+ for(i=0; i<3; i++){
+ if( (j = aIdx[i])>=0 ){
+ pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg;
+ pIdxInfo->aConstraintUsage[j].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
+ }
}
- if( stepIdx>=0 ){
- pIdxInfo->aConstraintUsage[stepIdx].argvIndex = ++nArg;
- pIdxInfo->aConstraintUsage[stepIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
+ if( (unusableMask & ~idxNum)!=0 ){
+ /* The start, stop, and step columns are inputs. Therefore if there
+ ** are unusable constraints on any of start, stop, or step then
+ ** this plan is unusable */
+ return SQLITE_CONSTRAINT;
}
if( (idxNum & 3)==3 ){
/* Both start= and stop= boundaries are available. This is the
@@ -365,7 +365,6 @@ static int seriesBestIndex(
/* If either boundary is missing, we have to generate a huge span
** of numbers. Make this case very expensive so that the query
** planner will work hard to avoid it. */
- pIdxInfo->estimatedCost = (double)2147483647;
pIdxInfo->estimatedRows = 2147483647;
}
pIdxInfo->idxNum = idxNum;