diff options
author | dan <Dan Kennedy> | 2024-04-26 17:19:59 +0000 |
---|---|---|
committer | dan <Dan Kennedy> | 2024-04-26 17:19:59 +0000 |
commit | 297472a2fcae79eb2e531d8c93fdb7f36725afdb (patch) | |
tree | 2c4c1fd0c220f2e7fed73108a611c5223403cbf9 /src | |
parent | d3a4dbe4b84732a57393a1966bae5ab56460478e (diff) | |
download | sqlite-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.c | 30 |
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; |