1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-12-03 08:01:19 +03:00

Fix the ORDER BY with IN constraint logic so that it works with all

combinations of DESC on the ORDER BY clause, on the RHS of the IN operator,
and in the index used by ORDER BY and IN.  
Fix for ticket [4dd95f6943fbd18].

FossilOrigin-Name: 839aa91faf1db7025d90fa3c65e50efb829b053b
This commit is contained in:
drh
2013-03-13 00:13:25 +00:00
7 changed files with 143 additions and 24 deletions

View File

@@ -1456,10 +1456,11 @@ int sqlite3CodeOnce(Parse *pParse){
**
** The returned value of this function indicates the b-tree type, as follows:
**
** IN_INDEX_ROWID - The cursor was opened on a database table.
** IN_INDEX_INDEX - The cursor was opened on a database index.
** IN_INDEX_EPH - The cursor was opened on a specially created and
** populated epheremal table.
** IN_INDEX_ROWID - The cursor was opened on a database table.
** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index.
** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
** IN_INDEX_EPH - The cursor was opened on a specially created and
** populated epheremal table.
**
** An existing b-tree might be used if the RHS expression pX is a simple
** subquery such as:
@@ -1582,7 +1583,8 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
pKey,P4_KEYINFO_HANDOFF);
VdbeComment((v, "%s", pIdx->zName));
eType = IN_INDEX_INDEX;
assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
sqlite3VdbeJumpHere(v, iAddr);
if( prNotFound && !pTab->aCol[iCol].notNull ){

View File

@@ -3263,7 +3263,8 @@ const char *sqlite3JournalModename(int);
#define IN_INDEX_ROWID 1
#define IN_INDEX_EPH 2
#define IN_INDEX_INDEX 3
#define IN_INDEX_INDEX_ASC 3
#define IN_INDEX_INDEX_DESC 4
int sqlite3FindInIndex(Parse *, Expr *, int*);
#ifdef SQLITE_ENABLE_ATOMIC_WRITE

View File

@@ -3775,7 +3775,8 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
static int codeEqualityTerm(
Parse *pParse, /* The parsing context */
WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
WhereLevel *pLevel, /* When level of the FROM clause we are working on */
WhereLevel *pLevel, /* The level of the FROM clause we are working on */
int iEq, /* Index of the equality term within this level */
int iTarget /* Attempt to leave results in this register */
){
Expr *pX = pTerm->pExpr;
@@ -3795,9 +3796,22 @@ static int codeEqualityTerm(
struct InLoop *pIn;
u8 bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0;
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0
&& pLevel->plan.u.pIdx->aSortOrder[iEq]
){
testcase( iEq==0 );
testcase( iEq==pLevel->plan.u.pIdx->nColumn-1 );
testcase( iEq>0 && iEq+1<pLevel->plan.u.pIdx->nColumn );
testcase( bRev );
bRev = !bRev;
}
assert( pX->op==TK_IN );
iReg = iTarget;
eType = sqlite3FindInIndex(pParse, pX, 0);
if( eType==IN_INDEX_INDEX_DESC ){
testcase( bRev );
bRev = !bRev;
}
iTab = pX->iTable;
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
assert( pLevel->plan.wsFlags & WHERE_IN_ABLE );
@@ -3912,7 +3926,7 @@ static int codeAllEqualityTerms(
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, regBase+j);
if( r1!=regBase+j ){
if( nReg==1 ){
sqlite3ReleaseTempReg(pParse, regBase);
@@ -4189,7 +4203,7 @@ static Bitmask codeOneLoopStart(
int iTarget = iReg+j+1;
pTerm = &pWC->a[aConstraint[k].iTermOffset];
if( pTerm->eOperator & WO_IN ){
codeEqualityTerm(pParse, pTerm, pLevel, iTarget);
codeEqualityTerm(pParse, pTerm, pLevel, k, iTarget);
addrNotFound = pLevel->addrNxt;
}else{
sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
@@ -4230,7 +4244,7 @@ static Bitmask codeOneLoopStart(
assert( pTerm->pExpr!=0 );
assert( omitTable==0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, iReleaseReg);
addrNxt = pLevel->addrNxt;
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);