aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordan <Dan Kennedy>2024-04-26 17:19:59 +0000
committerdan <Dan Kennedy>2024-04-26 17:19:59 +0000
commit297472a2fcae79eb2e531d8c93fdb7f36725afdb (patch)
tree2c4c1fd0c220f2e7fed73108a611c5223403cbf9 /src
parentd3a4dbe4b84732a57393a1966bae5ab56460478e (diff)
downloadsqlite-297472a2fcae79eb2e531d8c93fdb7f36725afdb.tar.gz
sqlite-297472a2fcae79eb2e531d8c93fdb7f36725afdb.zip
Have where.c ignore any plan from a virtual table that tries to use LIMIT/OFFSET without also using all WHERE constraints.
FossilOrigin-Name: 7d30596496c6a7a37b925f13d8d94d5de224ec31bb86594fa4cc07b10082e776
Diffstat (limited to 'src')
-rw-r--r--src/where.c30
1 files changed, 26 insertions, 4 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;