/ Check-in [d63fa039]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merge updates from trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | toTypeFuncs
Files: files | file ages | folders
SHA1: d63fa039a01330f5300c3a936d2f9ffb018952b9
User & Date: mistachkin 2013-03-13 20:52:11
Context
2013-05-15
08:00
Merge updates from trunk. check-in: 6fbad957 user: mistachkin tags: toTypeFuncs
2013-03-13
20:52
Merge updates from trunk. check-in: d63fa039 user: mistachkin tags: toTypeFuncs
07:02
Enhance tests for ticket [4dd95f6943]. check-in: 0b452734 user: dan tags: trunk
06:48
Rename the experimental todouble() function to toreal(), update comments. check-in: 12c318ef user: mistachkin tags: toTypeFuncs
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

    39     39   ** This routine is used to extract the "offset to cell content area" value
    40     40   ** from the header of a btree page.  If the page size is 65536 and the page
    41     41   ** is empty, the offset should be 65536, but the 2-byte value stores zero.
    42     42   ** This routine makes the necessary adjustment to 65536.
    43     43   */
    44     44   #define get2byteNotZero(X)  (((((int)get2byte(X))-1)&0xffff)+1)
    45     45   
           46  +/*
           47  +** Values passed as the 5th argument to allocateBtreePage()
           48  +*/
           49  +#define BTALLOC_ANY   0           /* Allocate any page */
           50  +#define BTALLOC_EXACT 1           /* Allocate exact page if possible */
           51  +#define BTALLOC_LE    2           /* Allocate any page <= the parameter */
           52  +
           53  +/*
           54  +** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not 
           55  +** defined, or 0 if it is. For example:
           56  +**
           57  +**   bIncrVacuum = IfNotOmitAV(pBtShared->incrVacuum);
           58  +*/
           59  +#ifndef SQLITE_OMIT_AUTOVACUUM
           60  +#define IfNotOmitAV(expr) (expr)
           61  +#else
           62  +#define IfNotOmitAV(expr) 0
           63  +#endif
           64  +
    46     65   #ifndef SQLITE_OMIT_SHARED_CACHE
    47     66   /*
    48     67   ** A list of BtShared objects that are eligible for participation
    49     68   ** in shared cache.  This variable has file scope during normal builds,
    50     69   ** but the test harness needs to access it so we make it global for 
    51     70   ** test builds.
    52     71   **
................................................................................
  2591   2610     /* If the btree is already in a write-transaction, or it
  2592   2611     ** is already in a read-transaction and a read-transaction
  2593   2612     ** is requested, this is a no-op.
  2594   2613     */
  2595   2614     if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
  2596   2615       goto trans_begun;
  2597   2616     }
  2598         -  assert( pBt->bDoTruncate==0 );
         2617  +  assert( IfNotOmitAV(pBt->bDoTruncate)==0 );
  2599   2618   
  2600   2619     /* Write transactions are not possible on a read-only database */
  2601   2620     if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
  2602   2621       rc = SQLITE_READONLY;
  2603   2622       goto trans_begun;
  2604   2623     }
  2605   2624   
................................................................................
  2906   2925       }
  2907   2926     }
  2908   2927     return rc;
  2909   2928   }
  2910   2929   
  2911   2930   /* Forward declaration required by incrVacuumStep(). */
  2912   2931   static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
  2913         -#define BTALLOC_ANY   0           /* Allocate any page */
  2914         -#define BTALLOC_EXACT 1           /* Allocate exact page if possible */
  2915         -#define BTALLOC_LE    2           /* Allocate any page <= the parameter */
  2916   2932   
  2917   2933   /*
  2918   2934   ** Perform a single step of an incremental-vacuum. If successful, return
  2919   2935   ** SQLITE_OK. If there is no work to do (and therefore no point in 
  2920   2936   ** calling this function again), return SQLITE_DONE. Or, if an error 
  2921   2937   ** occurs, return some other error code.
  2922   2938   **
................................................................................
  4898   4914     u32 n;     /* Number of pages on the freelist */
  4899   4915     u32 k;     /* Number of leaves on the trunk of the freelist */
  4900   4916     MemPage *pTrunk = 0;
  4901   4917     MemPage *pPrevTrunk = 0;
  4902   4918     Pgno mxPage;     /* Total size of the database file */
  4903   4919   
  4904   4920     assert( sqlite3_mutex_held(pBt->mutex) );
  4905         -  assert( eMode==BTALLOC_ANY || (nearby>0 && pBt->autoVacuum) );
         4921  +  assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) );
  4906   4922     pPage1 = pBt->pPage1;
  4907   4923     mxPage = btreePagecount(pBt);
  4908   4924     n = get4byte(&pPage1->aData[36]);
  4909   4925     testcase( n==mxPage-1 );
  4910   4926     if( n>=mxPage ){
  4911   4927       return SQLITE_CORRUPT_BKPT;
  4912   4928     }
................................................................................
  5131   5147       **
  5132   5148       ** Note that the pager will not actually attempt to load or journal 
  5133   5149       ** content for any page that really does lie past the end of the database
  5134   5150       ** file on disk. So the effects of disabling the no-content optimization
  5135   5151       ** here are confined to those pages that lie between the end of the
  5136   5152       ** database image and the end of the database file.
  5137   5153       */
  5138         -    int bNoContent = (0==pBt->bDoTruncate);
         5154  +    int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate));
  5139   5155   
  5140   5156       rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
  5141   5157       if( rc ) return rc;
  5142   5158       pBt->nPage++;
  5143   5159       if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ) pBt->nPage++;
  5144   5160   
  5145   5161   #ifndef SQLITE_OMIT_AUTOVACUUM

Changes to src/expr.c.

  1452   1452   ** all members of the RHS set, skipping duplicates.
  1453   1453   **
  1454   1454   ** A cursor is opened on the b-tree object that the RHS of the IN operator
  1455   1455   ** and pX->iTable is set to the index of that cursor.
  1456   1456   **
  1457   1457   ** The returned value of this function indicates the b-tree type, as follows:
  1458   1458   **
  1459         -**   IN_INDEX_ROWID - The cursor was opened on a database table.
  1460         -**   IN_INDEX_INDEX - The cursor was opened on a database index.
  1461         -**   IN_INDEX_EPH -   The cursor was opened on a specially created and
  1462         -**                    populated epheremal table.
         1459  +**   IN_INDEX_ROWID      - The cursor was opened on a database table.
         1460  +**   IN_INDEX_INDEX_ASC  - The cursor was opened on an ascending index.
         1461  +**   IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
         1462  +**   IN_INDEX_EPH        - The cursor was opened on a specially created and
         1463  +**                         populated epheremal table.
  1463   1464   **
  1464   1465   ** An existing b-tree might be used if the RHS expression pX is a simple
  1465   1466   ** subquery such as:
  1466   1467   **
  1467   1468   **     SELECT <column> FROM <table>
  1468   1469   **
  1469   1470   ** If the RHS of the IN operator is a list or a more complex subquery, then
................................................................................
  1578   1579     
  1579   1580             pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx);
  1580   1581             iAddr = sqlite3CodeOnce(pParse);
  1581   1582     
  1582   1583             sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
  1583   1584                                  pKey,P4_KEYINFO_HANDOFF);
  1584   1585             VdbeComment((v, "%s", pIdx->zName));
  1585         -          eType = IN_INDEX_INDEX;
         1586  +          assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
         1587  +          eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
  1586   1588   
  1587   1589             sqlite3VdbeJumpHere(v, iAddr);
  1588   1590             if( prNotFound && !pTab->aCol[iCol].notNull ){
  1589   1591               *prNotFound = ++pParse->nMem;
  1590   1592               sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
  1591   1593             }
  1592   1594           }

Changes to src/pragma.c.

  1126   1126           }
  1127   1127         }
  1128   1128       }
  1129   1129     }else
  1130   1130   #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
  1131   1131   
  1132   1132   #ifndef SQLITE_OMIT_FOREIGN_KEY
         1133  +#ifndef SQLITE_OMIT_TRIGGER
  1133   1134     if( sqlite3StrICmp(zLeft, "foreign_key_check")==0 ){
  1134   1135       FKey *pFK;             /* A foreign key constraint */
  1135   1136       Table *pTab;           /* Child table contain "REFERENCES" keyword */
  1136   1137       Table *pParent;        /* Parent table that child points to */
  1137   1138       Index *pIdx;           /* Index in the parent table */
  1138   1139       int i;                 /* Loop counter:  Foreign key number for pTab */
  1139   1140       int j;                 /* Loop counter:  Field of the foreign key */
................................................................................
  1237   1238           sqlite3VdbeResolveLabel(v, addrOk);
  1238   1239           sqlite3DbFree(db, aiCols);
  1239   1240         }
  1240   1241         sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1);
  1241   1242         sqlite3VdbeJumpHere(v, addrTop);
  1242   1243       }
  1243   1244     }else
         1245  +#endif /* !defined(SQLITE_OMIT_TRIGGER) */
  1244   1246   #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
  1245   1247   
  1246   1248   #ifndef NDEBUG
  1247   1249     if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
  1248   1250       if( zRight ){
  1249   1251         if( sqlite3GetBoolean(zRight, 0) ){
  1250   1252           sqlite3ParserTrace(stderr, "parser: ");

Changes to src/sqlite.h.in.

   279    279   ** host languages that are garbage collected, and where the order in which
   280    280   ** destructors are called is arbitrary.
   281    281   **
   282    282   ** Applications should [sqlite3_finalize | finalize] all [prepared statements],
   283    283   ** [sqlite3_blob_close | close] all [BLOB handles], and 
   284    284   ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
   285    285   ** with the [sqlite3] object prior to attempting to close the object.  ^If
   286         -** sqlite3_close() is called on a [database connection] that still has
          286  +** sqlite3_close_v2() is called on a [database connection] that still has
   287    287   ** outstanding [prepared statements], [BLOB handles], and/or
   288    288   ** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
   289    289   ** of resources is deferred until all [prepared statements], [BLOB handles],
   290    290   ** and [sqlite3_backup] objects are also destroyed.
   291    291   **
   292    292   ** ^If an [sqlite3] object is destroyed while a transaction is open,
   293    293   ** the transaction is automatically rolled back.

Changes to src/sqliteInt.h.

    62     62   #endif
    63     63   
    64     64   /* Needed for various definitions... */
    65     65   #ifndef _GNU_SOURCE
    66     66   # define _GNU_SOURCE
    67     67   #endif
    68     68   
           69  +#if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
           70  +# define _BSD_SOURCE
           71  +#endif
           72  +
    69     73   /*
    70     74   ** Include standard header files as necessary
    71     75   */
    72     76   #ifdef HAVE_STDINT_H
    73     77   #include <stdint.h>
    74     78   #endif
    75     79   #ifdef HAVE_INTTYPES_H
................................................................................
  3257   3261   #else
  3258   3262     #define sqlite3BeginBenignMalloc()
  3259   3263     #define sqlite3EndBenignMalloc()
  3260   3264   #endif
  3261   3265   
  3262   3266   #define IN_INDEX_ROWID           1
  3263   3267   #define IN_INDEX_EPH             2
  3264         -#define IN_INDEX_INDEX           3
         3268  +#define IN_INDEX_INDEX_ASC       3
         3269  +#define IN_INDEX_INDEX_DESC      4
  3265   3270   int sqlite3FindInIndex(Parse *, Expr *, int*);
  3266   3271   
  3267   3272   #ifdef SQLITE_ENABLE_ATOMIC_WRITE
  3268   3273     int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
  3269   3274     int sqlite3JournalSize(sqlite3_vfs *);
  3270   3275     int sqlite3JournalCreate(sqlite3_file *);
  3271   3276     int sqlite3JournalExists(sqlite3_file *p);

Changes to src/where.c.

  3771   3771   ** For a constraint of the form X=expr, the expression is evaluated and its
  3772   3772   ** result is left on the stack.  For constraints of the form X IN (...)
  3773   3773   ** this routine sets up a loop that will iterate over all values of X.
  3774   3774   */
  3775   3775   static int codeEqualityTerm(
  3776   3776     Parse *pParse,      /* The parsing context */
  3777   3777     WhereTerm *pTerm,   /* The term of the WHERE clause to be coded */
  3778         -  WhereLevel *pLevel, /* When level of the FROM clause we are working on */
         3778  +  WhereLevel *pLevel, /* The level of the FROM clause we are working on */
         3779  +  int iEq,            /* Index of the equality term within this level */
  3779   3780     int iTarget         /* Attempt to leave results in this register */
  3780   3781   ){
  3781   3782     Expr *pX = pTerm->pExpr;
  3782   3783     Vdbe *v = pParse->pVdbe;
  3783   3784     int iReg;                  /* Register holding results */
  3784   3785   
  3785   3786     assert( iTarget>0 );
................................................................................
  3791   3792   #ifndef SQLITE_OMIT_SUBQUERY
  3792   3793     }else{
  3793   3794       int eType;
  3794   3795       int iTab;
  3795   3796       struct InLoop *pIn;
  3796   3797       u8 bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0;
  3797   3798   
         3799  +    if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 
         3800  +      && pLevel->plan.u.pIdx->aSortOrder[iEq]
         3801  +    ){
         3802  +      testcase( iEq==0 );
         3803  +      testcase( iEq==pLevel->plan.u.pIdx->nColumn-1 );
         3804  +      testcase( iEq>0 && iEq+1<pLevel->plan.u.pIdx->nColumn );
         3805  +      testcase( bRev );
         3806  +      bRev = !bRev;
         3807  +    }
  3798   3808       assert( pX->op==TK_IN );
  3799   3809       iReg = iTarget;
  3800   3810       eType = sqlite3FindInIndex(pParse, pX, 0);
         3811  +    if( eType==IN_INDEX_INDEX_DESC ){
         3812  +      testcase( bRev );
         3813  +      bRev = !bRev;
         3814  +    }
  3801   3815       iTab = pX->iTable;
  3802   3816       sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
  3803   3817       assert( pLevel->plan.wsFlags & WHERE_IN_ABLE );
  3804   3818       if( pLevel->u.in.nIn==0 ){
  3805   3819         pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
  3806   3820       }
  3807   3821       pLevel->u.in.nIn++;
................................................................................
  3908   3922       int k = pIdx->aiColumn[j];
  3909   3923       pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx);
  3910   3924       if( pTerm==0 ) break;
  3911   3925       /* The following true for indices with redundant columns. 
  3912   3926       ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
  3913   3927       testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
  3914   3928       testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
  3915         -    r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
         3929  +    r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, regBase+j);
  3916   3930       if( r1!=regBase+j ){
  3917   3931         if( nReg==1 ){
  3918   3932           sqlite3ReleaseTempReg(pParse, regBase);
  3919   3933           regBase = r1;
  3920   3934         }else{
  3921   3935           sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j);
  3922   3936         }
................................................................................
  4185   4199       addrNotFound = pLevel->addrBrk;
  4186   4200       for(j=1; j<=nConstraint; j++){
  4187   4201         for(k=0; k<nConstraint; k++){
  4188   4202           if( aUsage[k].argvIndex==j ){
  4189   4203             int iTarget = iReg+j+1;
  4190   4204             pTerm = &pWC->a[aConstraint[k].iTermOffset];
  4191   4205             if( pTerm->eOperator & WO_IN ){
  4192         -            codeEqualityTerm(pParse, pTerm, pLevel, iTarget);
         4206  +            codeEqualityTerm(pParse, pTerm, pLevel, k, iTarget);
  4193   4207               addrNotFound = pLevel->addrNxt;
  4194   4208             }else{
  4195   4209               sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
  4196   4210             }
  4197   4211             break;
  4198   4212           }
  4199   4213         }
................................................................................
  4226   4240       */
  4227   4241       iReleaseReg = sqlite3GetTempReg(pParse);
  4228   4242       pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0);
  4229   4243       assert( pTerm!=0 );
  4230   4244       assert( pTerm->pExpr!=0 );
  4231   4245       assert( omitTable==0 );
  4232   4246       testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
  4233         -    iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
         4247  +    iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, iReleaseReg);
  4234   4248       addrNxt = pLevel->addrNxt;
  4235   4249       sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
  4236   4250       sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
  4237   4251       sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1);
  4238   4252       sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
  4239   4253       VdbeComment((v, "pk"));
  4240   4254       pLevel->op = OP_Noop;

Changes to test/descidx3.test.

   128    128   } {9 7 6 8 3 4 2 5}
   129    129   
   130    130   ifcapable subquery {
   131    131     # If the subquery capability is not compiled in to the binary, then
   132    132     # the IN(...) operator is not available. Hence these tests cannot be 
   133    133     # run.
   134    134     do_test descidx3-4.1 {
   135         -    execsql {
          135  +    lsort [execsql {
   136    136         UPDATE t1 SET a=2 WHERE i<6;
   137    137         SELECT i FROM t1 WHERE a IN (1,2) AND b>0 AND b<'zzz';
   138         -    }
   139         -  } {8 6 2 4 3}
          138  +    }]
          139  +  } {2 3 4 6 8}
   140    140     do_test descidx3-4.2 {
   141    141       execsql {
   142    142         UPDATE t1 SET a=1;
   143    143         SELECT i FROM t1 WHERE a IN (1,2) AND b>0 AND b<'zzz';
   144    144       }
   145    145     } {2 4 3 8 6}
   146    146     do_test descidx3-4.3 {

Added test/tkt-4dd95f6943.test.

            1  +# 2013 March 13
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library. 
           12  +#
           13  +
           14  +set testdir [file dirname $argv0]
           15  +source $testdir/tester.tcl
           16  +set ::testprefix tkt-4dd95f6943
           17  +
           18  +do_execsql_test 1.0 {
           19  +  CREATE TABLE t1(x);
           20  +  INSERT INTO t1 VALUES (3), (4), (2), (1), (5), (6);
           21  +}
           22  +
           23  +foreach {tn1 idx} {
           24  +  1 { CREATE INDEX i1 ON t1(x ASC) }
           25  +  2 { CREATE INDEX i1 ON t1(x DESC) }
           26  +} {
           27  +  do_execsql_test 1.$tn1.1 { DROP INDEX IF EXISTS i1; }
           28  +  do_execsql_test 1.$tn1.2 $idx
           29  +
           30  +  do_execsql_test 1.$tn1.3 {
           31  +    SELECT x FROM t1 WHERE x IN(2, 4, 5) ORDER BY x ASC;
           32  +  } {2 4 5}
           33  +
           34  +  do_execsql_test 1.$tn1.4 {
           35  +    SELECT x FROM t1 WHERE x IN(2, 4, 5) ORDER BY x DESC;
           36  +  } {5 4 2}
           37  +}
           38  +
           39  +
           40  +do_execsql_test 2.0 {
           41  +  CREATE TABLE t2(x, y);
           42  +  INSERT INTO t2 VALUES (5, 3), (5, 4), (5, 2), (5, 1), (5, 5), (5, 6);
           43  +  INSERT INTO t2 VALUES (1, 3), (1, 4), (1, 2), (1, 1), (1, 5), (1, 6);
           44  +  INSERT INTO t2 VALUES (3, 3), (3, 4), (3, 2), (3, 1), (3, 5), (3, 6);
           45  +  INSERT INTO t2 VALUES (2, 3), (2, 4), (2, 2), (2, 1), (2, 5), (2, 6);
           46  +  INSERT INTO t2 VALUES (4, 3), (4, 4), (4, 2), (4, 1), (4, 5), (4, 6);
           47  +  INSERT INTO t2 VALUES (6, 3), (6, 4), (6, 2), (6, 1), (6, 5), (6, 6);
           48  +
           49  +  CREATE TABLE t3(a, b);
           50  +  INSERT INTO t3 VALUES (2, 2), (4, 4), (5, 5);
           51  +  CREATE UNIQUE INDEX t3i1 ON t3(a ASC);
           52  +  CREATE UNIQUE INDEX t3i2 ON t3(b DESC);
           53  +}
           54  +
           55  +foreach {tn1 idx} {
           56  +  1 { CREATE INDEX i1 ON t2(x ASC,  y ASC) }
           57  +  2 { CREATE INDEX i1 ON t2(x ASC,  y DESC) }
           58  +  3 { CREATE INDEX i1 ON t2(x DESC, y ASC) }
           59  +  4 { CREATE INDEX i1 ON t2(x DESC, y DESC) }
           60  +
           61  +  5 { CREATE INDEX i1 ON t2(y ASC,  x ASC) }
           62  +  6 { CREATE INDEX i1 ON t2(y ASC,  x DESC) }
           63  +  7 { CREATE INDEX i1 ON t2(y DESC, x ASC) }
           64  +  8 { CREATE INDEX i1 ON t2(y DESC, x DESC) }
           65  +} {
           66  +  do_execsql_test 2.$tn1.1 { DROP INDEX IF EXISTS i1; }
           67  +  do_execsql_test 2.$tn1.2 $idx
           68  +
           69  +  foreach {tn2 inexpr} {
           70  +    3  "(2, 4, 5)"
           71  +    4  "(SELECT a FROM t3)"
           72  +    5  "(SELECT b FROM t3)"
           73  +  } {
           74  +    do_execsql_test 2.$tn1.$tn2.1 "
           75  +      SELECT x, y FROM t2 WHERE x = 1 AND y IN $inexpr ORDER BY x ASC, y ASC;
           76  +    " {1 2  1 4  1 5}
           77  +
           78  +    do_execsql_test 2.$tn1.$tn2.2 "
           79  +      SELECT x, y FROM t2 WHERE x = 2 AND y IN $inexpr ORDER BY x ASC, y DESC;
           80  +    " {2 5  2 4  2 2}
           81  +
           82  +    do_execsql_test 2.$tn1.$tn2.3 "
           83  +      SELECT x, y FROM t2 WHERE x = 3 AND y IN $inexpr ORDER BY x DESC, y ASC;
           84  +    " {3 2  3 4  3 5}
           85  +
           86  +    do_execsql_test 2.$tn1.$tn2.4 "
           87  +      SELECT x, y FROM t2 WHERE x = 4 AND y IN $inexpr ORDER BY x DESC, y DESC;
           88  +    " {4 5  4 4  4 2}
           89  +    
           90  +    do_execsql_test 2.$tn1.$tn2.5 "
           91  +      SELECT a, x, y FROM t2, t3 WHERE a = 4 AND x = 1 AND y IN $inexpr 
           92  +      ORDER BY a, x ASC, y ASC;
           93  +    " {4 1 2  4 1 4  4 1 5}
           94  +    do_execsql_test 2.$tn1.$tn2.6 "
           95  +      SELECT a, x, y FROM t2, t3 WHERE a = 2 AND x = 1 AND y IN $inexpr 
           96  +      ORDER BY x ASC, y ASC;
           97  +    " {2 1 2  2 1 4  2 1 5}
           98  +
           99  +    do_execsql_test 2.$tn1.$tn2.7 "
          100  +      SELECT a, x, y FROM t2, t3 WHERE a = 4 AND x = 1 AND y IN $inexpr 
          101  +      ORDER BY a, x ASC, y DESC;
          102  +    " {4 1 5  4 1 4  4 1 2}
          103  +    do_execsql_test 2.$tn1.8 "
          104  +      SELECT a, x, y FROM t2, t3 WHERE a = 2 AND x = 1 AND y IN $inexpr 
          105  +      ORDER BY x ASC, y DESC;
          106  +    " {2 1 5  2 1 4  2 1 2}
          107  +
          108  +    do_execsql_test 2.$tn1.$tn2.9 "
          109  +      SELECT a, x, y FROM t2, t3 WHERE a = 4 AND x = 1 AND y IN $inexpr 
          110  +      ORDER BY a, x DESC, y ASC;
          111  +    " {4 1 2  4 1 4  4 1 5}
          112  +    do_execsql_test 2.$tn1.10 "
          113  +      SELECT a, x, y FROM t2, t3 WHERE a = 2 AND x = 1 AND y IN $inexpr 
          114  +      ORDER BY x DESC, y ASC;
          115  +    " {2 1 2  2 1 4  2 1 5}
          116  +
          117  +    do_execsql_test 2.$tn1.$tn2.11 "
          118  +      SELECT a, x, y FROM t2, t3 WHERE a = 4 AND x = 1 AND y IN $inexpr 
          119  +      ORDER BY a, x DESC, y DESC;
          120  +    " {4 1 5  4 1 4  4 1 2}
          121  +    do_execsql_test 2.$tn1.$tn2.12 "
          122  +      SELECT a, x, y FROM t2, t3 WHERE a = 2 AND x = 1 AND y IN $inexpr 
          123  +      ORDER BY x DESC, y DESC;
          124  +    " {2 1 5  2 1 4  2 1 2}
          125  +  }
          126  +}
          127  +
          128  +do_execsql_test 3.0 {
          129  +  CREATE TABLE t7(x);
          130  +  INSERT INTO t7 VALUES (1), (2), (3);
          131  +  CREATE INDEX i7 ON t7(x);
          132  +
          133  +  CREATE TABLE t8(y);
          134  +  INSERT INTO t8 VALUES (1), (2), (3);
          135  +}
          136  +
          137  +foreach {tn idxdir sortdir sortdata} {
          138  +  1 ASC  ASC  {1 2 3}
          139  +  2 ASC  DESC {3 2 1}
          140  +  3 DESC ASC  {1 2 3}
          141  +  4 ASC  DESC {3 2 1}
          142  +} {
          143  +
          144  +  do_execsql_test 3.$tn "
          145  +    DROP INDEX IF EXISTS i8;
          146  +    CREATE UNIQUE INDEX i8 ON t8(y $idxdir);
          147  +    SELECT x FROM t7 WHERE x IN (SELECT y FROM t8) ORDER BY x $sortdir;
          148  +  " $sortdata
          149  +}
          150  +
          151  +finish_test