mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Fix issues in [/info/1e227ad9f413227f|LIMIT/OFFSET support for virtual tables].
The first problem was reported by [forum:/forumpost/c243b8f856|forum post c243b8f856]. That report prompted an enhancement to the generate_series() (also included in this merge) which in turn identified other similar issues. FossilOrigin-Name: 5f6c079d847e3664ec5acaf1b3e989efe0d548c211ae4a18936162b36df89065
This commit is contained in:
30
src/where.c
30
src/where.c
@ -4057,6 +4057,21 @@ static int isLimitTerm(WhereTerm *pTerm){
|
||||
&& pTerm->eMatchOp<=SQLITE_INDEX_CONSTRAINT_OFFSET;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the first nCons constraints in the pUsage array are
|
||||
** marked as in-use (have argvIndex>0). False otherwise.
|
||||
*/
|
||||
static int allConstraintsUsed(
|
||||
struct sqlite3_index_constraint_usage *aUsage,
|
||||
int nCons
|
||||
){
|
||||
int ii;
|
||||
for(ii=0; ii<nCons; ii++){
|
||||
if( aUsage[ii].argvIndex<=0 ) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Argument pIdxInfo is already populated with all constraints that may
|
||||
** be used by the virtual table identified by pBuilder->pNew->iTab. This
|
||||
@ -4197,13 +4212,20 @@ static int whereLoopAddVirtualOne(
|
||||
*pbIn = 1; assert( (mExclude & WO_IN)==0 );
|
||||
}
|
||||
|
||||
/* Unless pbRetryLimit is non-NULL, there should be no LIMIT/OFFSET
|
||||
** terms. And if there are any, they should follow all other terms. */
|
||||
assert( pbRetryLimit || !isLimitTerm(pTerm) );
|
||||
if( isLimitTerm(pTerm) && *pbIn ){
|
||||
assert( !isLimitTerm(pTerm) || i>=nConstraint-2 );
|
||||
assert( !isLimitTerm(pTerm) || i==nConstraint-1 || isLimitTerm(pTerm+1) );
|
||||
|
||||
if( isLimitTerm(pTerm) && (*pbIn || !allConstraintsUsed(pUsage, i)) ){
|
||||
/* If there is an IN(...) term handled as an == (separate call to
|
||||
** xFilter for each value on the RHS of the IN) and a LIMIT or
|
||||
** OFFSET term handled as well, the plan is unusable. Set output
|
||||
** variable *pbRetryLimit to true to tell the caller to retry with
|
||||
** LIMIT and OFFSET disabled. */
|
||||
** OFFSET term handled as well, the plan is unusable. Similarly,
|
||||
** if there is a LIMIT/OFFSET and there are other unused terms,
|
||||
** the plan cannot be used. In these cases set variable *pbRetryLimit
|
||||
** to true to tell the caller to retry with LIMIT and OFFSET
|
||||
** disabled. */
|
||||
if( pIdxInfo->needToFreeIdxStr ){
|
||||
sqlite3_free(pIdxInfo->idxStr);
|
||||
pIdxInfo->idxStr = 0;
|
||||
|
@ -1638,6 +1638,7 @@ void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
|
||||
continue;
|
||||
}
|
||||
if( pWC->a[ii].leftCursor!=iCsr ) return;
|
||||
if( pWC->a[ii].prereqRight!=0 ) return;
|
||||
}
|
||||
|
||||
/* Check condition (5). Return early if it is not met. */
|
||||
@ -1652,12 +1653,14 @@ void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
|
||||
|
||||
/* All conditions are met. Add the terms to the where-clause object. */
|
||||
assert( p->pLimit->op==TK_LIMIT );
|
||||
whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft,
|
||||
iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT);
|
||||
if( p->iOffset>0 ){
|
||||
if( p->iOffset!=0 && (p->selFlags & SF_Compound)==0 ){
|
||||
whereAddLimitExpr(pWC, p->iOffset, p->pLimit->pRight,
|
||||
iCsr, SQLITE_INDEX_CONSTRAINT_OFFSET);
|
||||
}
|
||||
if( p->iOffset==0 || (p->selFlags & SF_Compound)==0 ){
|
||||
whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft,
|
||||
iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user