aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <>2024-04-26 19:10:15 +0000
committerdrh <>2024-04-26 19:10:15 +0000
commitb11daa50f9ea11c332bb5913a071c5a0fd6c9993 (patch)
tree5180eef064d4faaa8d6c0e9924ea49ad6a2610f5 /src
parentb95c1d0ac9d020a9abd51c221194e188f25b69a9 (diff)
parent4c3ab545a91d50fd13e711dc250cce6927407ca2 (diff)
downloadsqlite-b11daa50f9ea11c332bb5913a071c5a0fd6c9993.tar.gz
sqlite-b11daa50f9ea11c332bb5913a071c5a0fd6c9993.zip
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
Diffstat (limited to 'src')
-rw-r--r--src/where.c30
-rw-r--r--src/whereexpr.c9
2 files changed, 32 insertions, 7 deletions
diff --git a/src/where.c b/src/where.c
index 39210ddb2..820e92249 100644
--- a/src/where.c
+++ b/src/where.c
@@ -4058,6 +4058,21 @@ static int isLimitTerm(WhereTerm *pTerm){
}
/*
+** 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
** function marks a subset of those constraints usable, invokes the
@@ -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;
diff --git a/src/whereexpr.c b/src/whereexpr.c
index 9d1f947a0..5465dc953 100644
--- a/src/whereexpr.c
+++ b/src/whereexpr.c
@@ -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);
+ }
}
}