Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch desc-orderby-fix-1 Excluding Merge-Ins
This is equivalent to a diff from f9027cb47b to 7e7356f155
2013-03-13
| ||
00:13 | 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]. (check-in: 839aa91faf user: drh tags: trunk) | |
2013-03-12
| ||
23:58 | Add a single new test case to the ORDER BY with IN logic verify that if the RHS of the IN is a descending index that it still works. Add testcase() macros to the ORDER BY with IN logic to help verify that corner cases are tested. (Closed-Leaf check-in: 7e7356f155 user: drh tags: desc-orderby-fix-1) | |
23:03 | Fix typo in sqlite3_close() function documentation reported on the mailing list. (check-in: c9a75d890f user: mistachkin tags: trunk) | |
22:13 | Fix a test case that had an ambiguous result. (check-in: 38c6bddf8c user: drh tags: desc-orderby-fix-1) | |
20:58 | Fix typo in sqlite3_close() function documentation reported on the mailing list. (Closed-Leaf check-in: 7232093d6c user: mistachkin tags: docTypo) | |
18:34 | A proposed fix for the DESC ORDER BY bug of ticket [4dd95f6943fbd18]. Seems to work, but lots more testing is needed prior to moving to trunk. (check-in: 614a038ad2 user: drh tags: desc-orderby-fix-1) | |
11:38 | Merge recent changes to trunk into sessions branch. (check-in: 62adb0e0d7 user: dan tags: sessions) | |
2013-03-11
| ||
13:37 | Define _BSD_SOURCE when building on OpenBSD. This is required for fchmod(). (check-in: f9027cb47b user: dan tags: trunk) | |
11:57 | Fixes for compiling with SQLITE_OMIT_AUTOVACUUM and/or SQLITE_OMIT_TRIGGER defined. (check-in: 1da15adba8 user: dan tags: trunk) | |
Changes to src/expr.c.
︙ | ︙ | |||
1452 1453 1454 1455 1456 1457 1458 | ** all members of the RHS set, skipping duplicates. ** ** A cursor is opened on the b-tree object that the RHS of the IN operator ** and pX->iTable is set to the index of that cursor. ** ** The returned value of this function indicates the b-tree type, as follows: ** | | > | | | | 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 | ** all members of the RHS set, skipping duplicates. ** ** A cursor is opened on the b-tree object that the RHS of the IN operator ** and pX->iTable is set to the index of that cursor. ** ** 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_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: ** ** SELECT <column> FROM <table> ** ** If the RHS of the IN operator is a list or a more complex subquery, then |
︙ | ︙ | |||
1578 1579 1580 1581 1582 1583 1584 | pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx); iAddr = sqlite3CodeOnce(pParse); sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb, pKey,P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); | > | | 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 | pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx); iAddr = sqlite3CodeOnce(pParse); sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb, pKey,P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); 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 ){ *prNotFound = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); } } |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
3259 3260 3261 3262 3263 3264 3265 | #else #define sqlite3BeginBenignMalloc() #define sqlite3EndBenignMalloc() #endif #define IN_INDEX_ROWID 1 #define IN_INDEX_EPH 2 | | > | 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 | #else #define sqlite3BeginBenignMalloc() #define sqlite3EndBenignMalloc() #endif #define IN_INDEX_ROWID 1 #define IN_INDEX_EPH 2 #define IN_INDEX_INDEX_ASC 3 #define IN_INDEX_INDEX_DESC 4 int sqlite3FindInIndex(Parse *, Expr *, int*); #ifdef SQLITE_ENABLE_ATOMIC_WRITE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); int sqlite3JournalSize(sqlite3_vfs *); int sqlite3JournalCreate(sqlite3_file *); int sqlite3JournalExists(sqlite3_file *p); |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
3771 3772 3773 3774 3775 3776 3777 | ** For a constraint of the form X=expr, the expression is evaluated and its ** result is left on the stack. For constraints of the form X IN (...) ** this routine sets up a loop that will iterate over all values of X. */ static int codeEqualityTerm( Parse *pParse, /* The parsing context */ WhereTerm *pTerm, /* The term of the WHERE clause to be coded */ | | > > > > > > > > > > > > > > | 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 | ** For a constraint of the form X=expr, the expression is evaluated and its ** result is left on the stack. For constraints of the form X IN (...) ** this routine sets up a loop that will iterate over all values of X. */ static int codeEqualityTerm( Parse *pParse, /* The parsing context */ WhereTerm *pTerm, /* The term of the WHERE clause to be coded */ 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; Vdbe *v = pParse->pVdbe; int iReg; /* Register holding results */ assert( iTarget>0 ); if( pX->op==TK_EQ ){ iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget); }else if( pX->op==TK_ISNULL ){ iReg = iTarget; sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); #ifndef SQLITE_OMIT_SUBQUERY }else{ int eType; int iTab; 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 ); if( pLevel->u.in.nIn==0 ){ pLevel->addrNxt = sqlite3VdbeMakeLabel(v); } pLevel->u.in.nIn++; |
︙ | ︙ | |||
3908 3909 3910 3911 3912 3913 3914 | int k = pIdx->aiColumn[j]; pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx); if( pTerm==0 ) break; /* The following true for indices with redundant columns. ** 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 */ | | | 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 | int k = pIdx->aiColumn[j]; pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx); if( pTerm==0 ) break; /* The following true for indices with redundant columns. ** 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, j, regBase+j); if( r1!=regBase+j ){ if( nReg==1 ){ sqlite3ReleaseTempReg(pParse, regBase); regBase = r1; }else{ sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j); } |
︙ | ︙ | |||
4185 4186 4187 4188 4189 4190 4191 | addrNotFound = pLevel->addrBrk; for(j=1; j<=nConstraint; j++){ for(k=0; k<nConstraint; k++){ if( aUsage[k].argvIndex==j ){ int iTarget = iReg+j+1; pTerm = &pWC->a[aConstraint[k].iTermOffset]; if( pTerm->eOperator & WO_IN ){ | | | 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 | addrNotFound = pLevel->addrBrk; for(j=1; j<=nConstraint; j++){ for(k=0; k<nConstraint; k++){ if( aUsage[k].argvIndex==j ){ int iTarget = iReg+j+1; pTerm = &pWC->a[aConstraint[k].iTermOffset]; if( pTerm->eOperator & WO_IN ){ codeEqualityTerm(pParse, pTerm, pLevel, k, iTarget); addrNotFound = pLevel->addrNxt; }else{ sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget); } break; } } |
︙ | ︙ | |||
4226 4227 4228 4229 4230 4231 4232 | */ iReleaseReg = sqlite3GetTempReg(pParse); pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0); assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ | | | 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 | */ iReleaseReg = sqlite3GetTempReg(pParse); pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0); assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, iReleaseReg); addrNxt = pLevel->addrNxt; sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg); sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); VdbeComment((v, "pk")); pLevel->op = OP_Noop; |
︙ | ︙ |
Changes to test/descidx3.test.
︙ | ︙ | |||
128 129 130 131 132 133 134 | } {9 7 6 8 3 4 2 5} ifcapable subquery { # If the subquery capability is not compiled in to the binary, then # the IN(...) operator is not available. Hence these tests cannot be # run. do_test descidx3-4.1 { | | | | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | } {9 7 6 8 3 4 2 5} ifcapable subquery { # If the subquery capability is not compiled in to the binary, then # the IN(...) operator is not available. Hence these tests cannot be # run. do_test descidx3-4.1 { lsort [execsql { UPDATE t1 SET a=2 WHERE i<6; SELECT i FROM t1 WHERE a IN (1,2) AND b>0 AND b<'zzz'; }] } {2 3 4 6 8} do_test descidx3-4.2 { execsql { UPDATE t1 SET a=1; SELECT i FROM t1 WHERE a IN (1,2) AND b>0 AND b<'zzz'; } } {2 4 3 8 6} do_test descidx3-4.3 { |
︙ | ︙ |
Added test/tkt-4dd95f6943.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | # 2013 March 13 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix tkt-4dd95f6943 do_execsql_test 1.0 { CREATE TABLE t1(x); INSERT INTO t1 VALUES (3), (4), (2), (1), (5), (6); } foreach {tn1 idx} { 1 { CREATE INDEX i1 ON t1(x ASC) } 2 { CREATE INDEX i1 ON t1(x DESC) } } { do_execsql_test 1.$tn1.1 { DROP INDEX IF EXISTS i1; } do_execsql_test 1.$tn1.2 $idx do_execsql_test 1.$tn1.3 { SELECT x FROM t1 WHERE x IN(2, 4, 5) ORDER BY x ASC; } {2 4 5} do_execsql_test 1.$tn1.4 { SELECT x FROM t1 WHERE x IN(2, 4, 5) ORDER BY x DESC; } {5 4 2} } do_execsql_test 2.0 { CREATE TABLE t2(x, y); INSERT INTO t2 VALUES (5, 3), (5, 4), (5, 2), (5, 1), (5, 5), (5, 6); INSERT INTO t2 VALUES (1, 3), (1, 4), (1, 2), (1, 1), (1, 5), (1, 6); INSERT INTO t2 VALUES (3, 3), (3, 4), (3, 2), (3, 1), (3, 5), (3, 6); INSERT INTO t2 VALUES (2, 3), (2, 4), (2, 2), (2, 1), (2, 5), (2, 6); INSERT INTO t2 VALUES (4, 3), (4, 4), (4, 2), (4, 1), (4, 5), (4, 6); INSERT INTO t2 VALUES (6, 3), (6, 4), (6, 2), (6, 1), (6, 5), (6, 6); CREATE TABLE t3(a, b); INSERT INTO t3 VALUES (2, 2), (4, 4), (5, 5); CREATE INDEX t3i1 ON t3(a ASC); CREATE INDEX t3i2 ON t3(b DESC); } foreach {tn1 idx} { 1 { CREATE INDEX i1 ON t2(x ASC, y ASC) } 2 { CREATE INDEX i1 ON t2(x ASC, y DESC) } 3 { CREATE INDEX i1 ON t2(x DESC, y ASC) } 4 { CREATE INDEX i1 ON t2(x DESC, y DESC) } 5 { CREATE INDEX i1 ON t2(y ASC, x ASC) } 6 { CREATE INDEX i1 ON t2(y ASC, x DESC) } 7 { CREATE INDEX i1 ON t2(y DESC, x ASC) } 8 { CREATE INDEX i1 ON t2(y DESC, x DESC) } } { do_execsql_test 2.$tn1.1 { DROP INDEX IF EXISTS i1; } do_execsql_test 2.$tn1.2 $idx foreach {tn2 inexpr} { 1 "(2, 4, 5)" 2 "(SELECT a FROM t3)" 3 "(SELECT b FROM t3)" } { do_execsql_test 2.$tn1.3 " SELECT x, y FROM t2 WHERE x = 1 AND y IN $inexpr ORDER BY x ASC, y ASC; " {1 2 1 4 1 5} do_execsql_test 2.$tn1.4 " SELECT x, y FROM t2 WHERE x = 2 AND y IN $inexpr ORDER BY x ASC, y DESC; " {2 5 2 4 2 2} do_execsql_test 2.$tn1.5 " SELECT x, y FROM t2 WHERE x = 3 AND y IN $inexpr ORDER BY x DESC, y ASC; " {3 2 3 4 3 5} do_execsql_test 2.$tn1.6 " SELECT x, y FROM t2 WHERE x = 4 AND y IN $inexpr ORDER BY x DESC, y DESC; " {4 5 4 4 4 2} } } do_execsql_test 3.0 { CREATE TABLE t7(x); INSERT INTO t7 VALUES (1), (2), (3); CREATE INDEX i7 ON t7(x); CREATE TABLE t8(y); INSERT INTO t8 VALUES (1), (2), (3); CREATE UNIQUE INDEX i8 ON t8(y DESC); SELECT x FROM t7 WHERE x IN (SELECT y FROM t8) ORDER BY x ASC; } {1 2 3} finish_test |