]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
The compound-select merge optimization is mostly working with this check-in.
authordrh <drh@noemail.net>
Tue, 24 Jun 2008 00:32:35 +0000 (00:32 +0000)
committerdrh <drh@noemail.net>
Tue, 24 Jun 2008 00:32:35 +0000 (00:32 +0000)
But there are still a few problems and so the optimization is disabled by
and "#if 0".  This check-in is to synchronize with the other changes happening
in parallel. (CVS 5291)

FossilOrigin-Name: e2ba324cbcac0ba35bbde50048677e085abb092b

manifest
manifest.uuid
src/expr.c
src/insert.c
src/select.c
src/sqliteInt.h
test/select1.test

index 9b35a095f823491af11bf8b1ee76f7ed03d78809..02b29aa0a433d39896763f70af226ab08adfdda9 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Update\sOS/2\smutex\simplementation:\smake\smethods\sstatic\sand\sdon't\suse\sthem\sby\sthe\sold\snames\sany\smore.\sHeld/Notheld\sshould\sbe\sdebug\sonly.\s(CVS\s5290)
-D 2008-06-23T22:13:28
+C The\scompound-select\smerge\soptimization\sis\smostly\sworking\swith\sthis\scheck-in.\nBut\sthere\sare\sstill\sa\sfew\sproblems\sand\sso\sthe\soptimization\sis\sdisabled\sby\nand\s"#if\s0".\s\sThis\scheck-in\sis\sto\ssynchronize\swith\sthe\sother\schanges\shappening\nin\sparallel.\s(CVS\s5291)
+D 2008-06-24T00:32:35
 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
 F Makefile.in ff6f90048555a0088f6a4b7406bed5e55a7c4eff
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -103,14 +103,14 @@ F src/callback.c 3ba98ae46f60aa7c2c40eac7d18fe5ba9b706b83
 F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
 F src/date.c e841168e5520bbbb2a1cbcdce7531d8b23017b4d
 F src/delete.c d3fc5987f2eb88f7b9549d58a5dfea079a83fe8b
-F src/expr.c bb0b5ff5fa81e2fb7563d17fb16d457bc60bd44f
+F src/expr.c 18af707c4346de39c25d0c30a7db4c3ea449d3df
 F src/fault.c 3638519d1e0b82bccfafcb9f5ff491918b28f8e1
 F src/func.c 1e7d9569570134ac0771a00382d9d4b41c4aa052
 F src/global.c 2304cfa3288763bd2fed10caf8c6fbaa2b383f4e
 F src/hash.c eb64e48f3781100e5934f759fbe72a63a8fe78cb
 F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
 F src/hwtime.h 745961687a65ef8918cd551c02e5ccb4b8e772de
-F src/insert.c 93231fd0199f044bcefda3d857420f4d377e4056
+F src/insert.c 4656c5231059d8f40a5bbe21a28a9344c07a49bd
 F src/journal.c cffd2cd214e58c0e99c3ff632b3bee6c7cbb260e
 F src/legacy.c 3626c71fb70912abec9a4312beba753a9ce800df
 F src/loadext.c 40024a0f476c1279494876b9a002001b29e5d3e3
@@ -140,11 +140,11 @@ F src/pragma.c e6c55362d164e4bc8ebc83a9a01635552d854800
 F src/prepare.c aba51dad52308e3d9d2074d8ff4e612e7f1cab51
 F src/printf.c 8b063da9dcde26b7c500a01444b718d86f21bc6e
 F src/random.c 5c754319d38abdd6acd74601ee0105504adc508a
-F src/select.c ea3e5e233cf16f4cb43f6ec35972683ae7bc03f3
+F src/select.c 1ebcd83ab51be47f31b2ec93daad844baf3b0788
 F src/shell.c 61fa61932ed52825720ebfd3f8381b8d550ef766
 F src/sqlite.h.in 6a80d00621a43271f01c77eb42bbf57e0f52051b
 F src/sqlite3ext.h f162a72daef5ebf8b211fe8c0ec96e85d22fbf9b
-F src/sqliteInt.h 0129e546b43a06844d1d66fd9d9b3090676d0873
+F src/sqliteInt.h ec8e71249994b8a5b23b1a098a576c02e8548244
 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
 F src/status.c 6cb10377992505bd69f1ca1d75c1240a65f25a58
 F src/table.c 1fa8f8113ac9cbc09ae4801c6d2a7f0af82c5822
@@ -438,7 +438,7 @@ F test/rtree.test a8404a59bbc3a7827db9bfb334790c852f0391b3
 F test/safety.test b69e2b2dd5d52a3f78e216967086884bbc1a09c6
 F test/schema.test a8b000723375fd42c68d310091bdbd744fde647c
 F test/schema2.test 35e1c9696443d6694c8980c411497c2b5190d32e
-F test/select1.test 2f011e7aa0accada53795bc95f00d268a3811bd4
+F test/select1.test 64f6231c75b01ec30c88dd9d45d0979169ee4d95
 F test/select2.test 06a2660de57673e2d076c29c0fd73f961a930f87
 F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
 F test/select4.test 7cc135c8343e6e433bdad185de6a720b112c40e7
@@ -592,7 +592,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P bf2e283d6fd40cabe55864b06b502524eb8a3b07
-R bfadbc404a2d8b31ffee6a81899b30a6
-U pweilbacher
-Z 4ec4b9feb6cdd59c7ef6420f4a9a5810
+P d92418ca502f5f58dc968668e11c42955a7b1e52
+R f88ace7929fab768ff8007a473e6b665
+U drh
+Z 9ed7972d77404d7a52eef908bd3410d8
index 54a9197172fc2957ebf9bc4d3595f905b814b76c..83bcd7c61ad712cb3885c1bbfe6e4dd65d91a36a 100644 (file)
@@ -1 +1 @@
-d92418ca502f5f58dc968668e11c42955a7b1e52
\ No newline at end of file
+e2ba324cbcac0ba35bbde50048677e085abb092b
\ No newline at end of file
index ef88cfecc00c40aa0c84b4cdc81a3fa1d2d0fa91..da051c75eb96ded0b09304abe20a35129a18df4f 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains routines used for analyzing expressions and
 ** for generating VDBE code that evaluates expressions in SQLite.
 **
-** $Id: expr.c,v 1.374 2008/06/22 12:37:58 drh Exp $
+** $Id: expr.c,v 1.375 2008/06/24 00:32:35 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -756,8 +756,8 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p){
   pNew->pPrior = sqlite3SelectDup(db, p->pPrior);
   pNew->pLimit = sqlite3ExprDup(db, p->pLimit);
   pNew->pOffset = sqlite3ExprDup(db, p->pOffset);
-  pNew->iLimit = -1;
-  pNew->iOffset = -1;
+  pNew->iLimit = 0;
+  pNew->iOffset = 0;
   pNew->isResolved = p->isResolved;
   pNew->isAgg = p->isAgg;
   pNew->usesEphm = 0;
@@ -1018,27 +1018,35 @@ int sqlite3ExprIsConstantOrFunction(Expr *p){
 ** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged.
 */
 int sqlite3ExprIsInteger(Expr *p, int *pValue){
+  int rc = 0;
+  if( p->flags & EP_IntValue ){
+    *pValue = p->iTable;
+    return 1;
+  }
   switch( p->op ){
     case TK_INTEGER: {
-      if( sqlite3GetInt32((char*)p->token.z, pValue) ){
-        return 1;
-      }
+      rc = sqlite3GetInt32((char*)p->token.z, pValue);
       break;
     }
     case TK_UPLUS: {
-      return sqlite3ExprIsInteger(p->pLeft, pValue);
+      rc = sqlite3ExprIsInteger(p->pLeft, pValue);
     }
     case TK_UMINUS: {
       int v;
       if( sqlite3ExprIsInteger(p->pLeft, &v) ){
         *pValue = -v;
-        return 1;
+        rc = 1;
       }
       break;
     }
     default: break;
   }
-  return 0;
+  if( rc ){
+    p->op = TK_INTEGER;
+    p->flags |= EP_IntValue;
+    p->iTable = *pValue;
+  }
+  return rc;
 }
 
 /*
@@ -1986,10 +1994,15 @@ static void codeReal(Vdbe *v, const char *z, int n, int negateFlag, int iMem){
 ** z[n] character is guaranteed to be something that does not look
 ** like the continuation of the number.
 */
-static void codeInteger(Vdbe *v, const char *z, int n, int negFlag, int iMem){
-  assert( z || v==0 || sqlite3VdbeDb(v)->mallocFailed );
-  if( z ){
+static void codeInteger(Vdbe *v, Expr *pExpr, int negFlag, int iMem){
+  const char *z;
+  if( pExpr->flags & EP_IntValue ){
+    int i = pExpr->iTable;
+    if( negFlag ) i = -i;
+    sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
+  }else if( (z = (char*)pExpr->token.z)!=0 ){
     int i;
+    int n = pExpr->token.n;
     assert( !isdigit(z[n]) );
     if( sqlite3GetInt32(z, &i) ){
       if( negFlag ) i = -i;
@@ -2127,6 +2140,18 @@ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
   }
 }
 
+/*
+** Generate code to copy content from registers iFrom...iFrom+nReg-1
+** over to iTo..iTo+nReg-1.
+*/
+void sqlite3ExprCodeCopy(Parse *pParse, int iFrom, int iTo, int nReg){
+  int i;
+  if( iFrom==iTo ) return;
+  for(i=0; i<nReg; i++){
+    sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, iFrom+i, iTo+i);
+  }
+}
+
 /*
 ** Return true if any register in the range iFrom..iTo (inclusive)
 ** is used as part of the column cache.
@@ -2246,7 +2271,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
       break;
     }
     case TK_INTEGER: {
-      codeInteger(v, (char*)pExpr->token.z, pExpr->token.n, 0, target);
+      codeInteger(v, pExpr, 0, target);
       break;
     }
     case TK_FLOAT: {
@@ -2384,11 +2409,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
       Expr *pLeft = pExpr->pLeft;
       assert( pLeft );
       if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){
-        Token *p = &pLeft->token;
         if( pLeft->op==TK_FLOAT ){
-          codeReal(v, (char*)p->z, p->n, 1, target);
+          codeReal(v, (char*)pLeft->token.z, pLeft->token.n, 1, target);
         }else{
-          codeInteger(v, (char*)p->z, p->n, 1, target);
+          codeInteger(v, pLeft, 1, target);
         }
       }else{
         regFree1 = r1 = sqlite3GetTempReg(pParse);
index 856228352f973b4be0ed515335b41b04aa55ba4c..14f86e695eb0a0c18558939a63a77a96b7a60cf7 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.241 2008/06/20 15:24:02 drh Exp $
+** $Id: insert.c,v 1.242 2008/06/24 00:32:35 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -523,10 +523,9 @@ void sqlite3Insert(
     regEof = ++pParse->nMem;
     sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof);      /* EOF <- 0 */
     VdbeComment((v, "SELECT eof flag"));
-    sqlite3SelectDestInit(&dest, SRT_Coroutine, 0);
-    dest.regCoroutine = ++pParse->nMem;
+    sqlite3SelectDestInit(&dest, SRT_Coroutine, ++pParse->nMem);
     addrSelect = sqlite3VdbeCurrentAddr(v)+2;
-    sqlite3VdbeAddOp2(v, OP_Integer, addrSelect-1, dest.regCoroutine);
+    sqlite3VdbeAddOp2(v, OP_Integer, addrSelect-1, dest.iParm);
     j1 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
     VdbeComment((v, "Jump over SELECT coroutine"));
 
@@ -536,7 +535,7 @@ void sqlite3Insert(
       goto insert_cleanup;
     }
     sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof);         /* EOF <- 1 */
-    sqlite3VdbeAddOp1(v, OP_Yield, dest.regCoroutine);   /* yield X */
+    sqlite3VdbeAddOp1(v, OP_Yield, dest.iParm);   /* yield X */
     sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
     VdbeComment((v, "End of SELECT coroutine"));
     sqlite3VdbeJumpHere(v, j1);                          /* label B: */
@@ -580,7 +579,7 @@ void sqlite3Insert(
       regRec = sqlite3GetTempReg(pParse);
       regRowid = sqlite3GetTempReg(pParse);
       sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
-      addrTop = sqlite3VdbeAddOp1(v, OP_Yield, dest.regCoroutine);
+      addrTop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iParm);
       addrIf = sqlite3VdbeAddOp1(v, OP_If, regEof);
       sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
       sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regRowid);
@@ -725,7 +724,7 @@ void sqlite3Insert(
     **         goto C
     **      D: ...
     */
-    addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.regCoroutine);
+    addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iParm);
     addrInsTop = sqlite3VdbeAddOp1(v, OP_If, regEof);
   }
 
index d072b2042ab6e70e5797bdda8a07479763e341ae..02bbff7a6d6dfbbdc49338cf83a95c0db25e93b3 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements in SQLite.
 **
-** $Id: select.c,v 1.433 2008/06/22 12:37:58 drh Exp $
+** $Id: select.c,v 1.434 2008/06/24 00:32:36 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -39,7 +39,6 @@ static void clearSelect(Select *p){
 void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
   pDest->eDest = eDest;
   pDest->iParm = iParm;
-  pDest->regCoroutine = 0;
   pDest->affinity = 0;
   pDest->iMem = 0;
   pDest->nMem = 0;
@@ -85,8 +84,6 @@ Select *sqlite3SelectNew(
   assert( pOffset==0 || pLimit!=0 );
   pNew->pLimit = pLimit;
   pNew->pOffset = pOffset;
-  pNew->iLimit = -1;
-  pNew->iOffset = -1;
   pNew->addrOpenEphm[0] = -1;
   pNew->addrOpenEphm[1] = -1;
   pNew->addrOpenEphm[2] = -1;
@@ -430,7 +427,7 @@ static void pushOntoSorter(
   sqlite3VdbeAddOp2(v, OP_IdxInsert, pOrderBy->iECursor, regRecord);
   sqlite3ReleaseTempReg(pParse, regRecord);
   sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
-  if( pSelect->iLimit>=0 ){
+  if( pSelect->iLimit ){
     int addr1, addr2;
     int iLimit;
     if( pSelect->pOffset ){
@@ -445,7 +442,7 @@ static void pushOntoSorter(
     sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
     sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor);
     sqlite3VdbeJumpHere(v, addr2);
-    pSelect->iLimit = -1;
+    pSelect->iLimit = 0;
   }
 }
 
@@ -457,7 +454,7 @@ static void codeOffset(
   Select *p,        /* The SELECT statement being coded */
   int iContinue     /* Jump here to skip the current record */
 ){
-  if( p->iOffset>=0 && iContinue!=0 ){
+  if( p->iOffset && iContinue!=0 ){
     int addr;
     sqlite3VdbeAddOp2(v, OP_AddImm, p->iOffset, -1);
     addr = sqlite3VdbeAddOp1(v, OP_IfNeg, p->iOffset);
@@ -712,7 +709,7 @@ static void selectInnerLoop(
         pushOntoSorter(pParse, pOrderBy, p, r1);
         sqlite3ReleaseTempReg(pParse, r1);
       }else if( eDest==SRT_Coroutine ){
-        sqlite3VdbeAddOp1(v, OP_Yield, pDest->regCoroutine);
+        sqlite3VdbeAddOp1(v, OP_Yield, pDest->iParm);
       }else{
         sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nColumn);
         sqlite3ExprCacheAffinityChange(pParse, regResult, nColumn);
@@ -735,7 +732,7 @@ static void selectInnerLoop(
 
   /* Jump to the end of the loop if the LIMIT is reached.
   */
-  if( p->iLimit>=0 && pOrderBy==0 ){
+  if( p->iLimit && pOrderBy==0 ){
     sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
     sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, iBreak);
   }
@@ -859,7 +856,7 @@ static void generateSortTail(
         sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iMem, nColumn);
         sqlite3ExprCacheAffinityChange(pParse, pDest->iMem, nColumn);
       }else if( eDest==SRT_Coroutine ){
-        sqlite3VdbeAddOp1(v, OP_Yield, pDest->regCoroutine);
+        sqlite3VdbeAddOp1(v, OP_Yield, pDest->iParm);
       }
       break;
     }
@@ -873,7 +870,7 @@ static void generateSortTail(
 
   /* Jump to the end of the loop when the LIMIT is reached
   */
-  if( p->iLimit>=0 ){
+  if( p->iLimit ){
     sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
     sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, brk);
   }
@@ -1508,9 +1505,9 @@ static int prepSelectStmt(Parse *pParse, Select *p){
 ** pE is a pointer to an expression which is a single term in
 ** ORDER BY or GROUP BY clause.
 **
-** If pE evaluates to an integer constant i, then return i.
-** This is an indication to the caller that it should sort
-** by the i-th column of the result set.
+** At the point this routine is called, we already know that the
+** ORDER BY term is not an integer index into the result set.  That
+** casee is handled by the calling routine.
 **
 ** If pE is a well-formed expression and the SELECT statement
 ** is not compound, then return 0.  This indicates to the
@@ -1535,20 +1532,8 @@ static int matchOrderByTermToExprList(
   ExprList *pEList;  /* The columns of the result set */
   NameContext nc;    /* Name context for resolving pE */
 
-
-  /* If the term is an integer constant, return the value of that
-  ** constant */
+  assert( sqlite3ExprIsInteger(pE, &i)==0 );
   pEList = pSelect->pEList;
-  if( sqlite3ExprIsInteger(pE, &i) ){
-    if( i<=0 ){
-      /* If i is too small, make it too big.  That way the calling
-      ** function still sees a value that is out of range, but does
-      ** not confuse the column number with 0 or -1 result code.
-      */
-      i = pEList->nExpr+1;
-    }
-    return i;
-  }
 
   /* If the term is a simple identifier that try to match that identifier
   ** against a column name in the result set.
@@ -1638,16 +1623,19 @@ static int processOrderGroupBy(
   for(i=0; i<pOrderBy->nExpr; i++){
     int iCol;
     Expr *pE = pOrderBy->a[i].pExpr;
-    iCol = matchOrderByTermToExprList(pParse, pSelect, pE, i+1, 0, pHasAgg);
-    if( iCol<0 ){
-      return 1;
-    }
-    if( iCol>pEList->nExpr ){
-      const char *zType = isOrder ? "ORDER" : "GROUP";
-      sqlite3ErrorMsg(pParse, 
-         "%r %s BY term out of range - should be "
-         "between 1 and %d", i+1, zType, pEList->nExpr);
-      return 1;
+    if( sqlite3ExprIsInteger(pE, &iCol) ){
+      if( iCol<=0 || iCol>pEList->nExpr ){
+        const char *zType = isOrder ? "ORDER" : "GROUP";
+        sqlite3ErrorMsg(pParse, 
+           "%r %s BY term out of range - should be "
+           "between 1 and %d", i+1, zType, pEList->nExpr);
+        return 1;
+      }
+    }else{
+      iCol = matchOrderByTermToExprList(pParse, pSelect, pE, i+1, 0, pHasAgg);
+      if( iCol<0 ){
+        return 1;
+      }
     }
     if( iCol>0 ){
       CollSeq *pColl = pE->pColl;
@@ -1668,11 +1656,11 @@ static int processOrderGroupBy(
 ** Analyze and ORDER BY or GROUP BY clause in a SELECT statement.  Return
 ** the number of errors seen.
 **
-** For compound SELECT statements, every expression needs to be of
-** type TK_COLUMN with a iTable value as given in the 4th parameter.
-** If any expression is an integer, that becomes the column number.
-** Otherwise, match the expression against result set columns from
-** the left-most SELECT.
+** If iTable>0 then make the N-th term of the ORDER BY clause refer to
+** the N-th column of table iTable.
+**
+** If iTable==0 then transform each term of the ORDER BY clause to refer
+** to a column of the result set by number.
 */
 static int processCompoundOrderBy(
   Parse *pParse,        /* Parsing context.  Leave error messages here */
@@ -1702,36 +1690,45 @@ static int processCompoundOrderBy(
   }
   while( pSelect && moreToDo ){
     moreToDo = 0;
+    pEList = pSelect->pEList;
+    if( pEList==0 ){
+      return 1;
+    }
     for(i=0; i<pOrderBy->nExpr; i++){
       int iCol = -1;
       Expr *pE, *pDup;
       if( pOrderBy->a[i].done ) continue;
       pE = pOrderBy->a[i].pExpr;
-      pDup = sqlite3ExprDup(db, pE);
-      if( !db->mallocFailed ){
-        assert(pDup);
-        iCol = matchOrderByTermToExprList(pParse, pSelect, pDup, i+1, 1, 0);
-      }
-      sqlite3ExprDelete(pDup);
-      if( iCol<0 ){
-        return 1;
-      }
-      pEList = pSelect->pEList;
-      if( pEList==0 ){
-        return 1;
-      }
-      if( iCol>pEList->nExpr ){
-        sqlite3ErrorMsg(pParse, 
-           "%r ORDER BY term out of range - should be "
-           "between 1 and %d", i+1, pEList->nExpr);
-        return 1;
+      if( sqlite3ExprIsInteger(pE, &iCol) ){
+        if( iCol<0 || iCol>pEList->nExpr ){
+          sqlite3ErrorMsg(pParse, 
+             "%r ORDER BY term out of range - should be "
+             "between 1 and %d", i+1, pEList->nExpr);
+          return 1;
+        }
+      }else{
+        pDup = sqlite3ExprDup(db, pE);
+        if( !db->mallocFailed ){
+          assert(pDup);
+          iCol = matchOrderByTermToExprList(pParse, pSelect, pDup, i+1, 1, 0);
+        }
+        sqlite3ExprDelete(pDup);
+        if( iCol<0 ){
+          return 1;
+        }
       }
       if( iCol>0 ){
-        pE->op = TK_COLUMN;
-        pE->iTable = iTable;
-        pE->iAgg = -1;
-        pE->iColumn = iCol-1;
-        pE->pTab = 0;
+        if( iTable ){
+          pE->op = TK_COLUMN;
+          pE->iTable = iTable;
+          pE->iAgg = -1;
+          pE->iColumn = iCol-1;
+          pE->pTab = 0;
+        }else{
+          pE->op = TK_INTEGER;
+          pE->flags |= EP_IntValue;
+          pE->iTable = iCol;
+        }
         pOrderBy->a[i].done = 1;
       }else{
         moreToDo = 1;
@@ -1989,7 +1986,7 @@ static int multiSelect(
         p->pPrior = 0;
         p->iLimit = pPrior->iLimit;
         p->iOffset = pPrior->iOffset;
-        if( p->iLimit>=0 ){
+        if( p->iLimit ){
           addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit);
           VdbeComment((v, "Jump ahead if LIMIT reached"));
         }
@@ -2075,8 +2072,8 @@ static int multiSelect(
       sqlite3ExprDelete(p->pLimit);
       p->pLimit = pLimit;
       p->pOffset = pOffset;
-      p->iLimit = -1;
-      p->iOffset = -1;
+      p->iLimit = 0;
+      p->iOffset = 0;
       if( rc ){
         goto multi_select_end;
       }
@@ -2313,23 +2310,26 @@ multi_select_end:
 }
 #endif /* SQLITE_OMIT_COMPOUND_SELECT */
 
-#if 0 /****** ################ ******/
 /*
 ** Code an output subroutine for a coroutine implementation of a
 ** SELECT statment.
 */
 static int outputSubroutine(
-  Parse *pParse,
-  SelectDest *pIn
-  SelectDest *pDest
+  Parse *pParse,          /* Parsing context */
+  Select *p,              /* The SELECT statement */
+  SelectDest *pIn,        /* Coroutine supplying data */
+  SelectDest *pDest,      /* Where to send the data */
+  int regReturn,          /* The return address register */
+  int iBreak              /* Jump here if we hit the LIMIT */
 ){
   Vdbe *v = pParse->pVdbe;
-  if( v==0 ) return;
+  int iContinue;
+  int addr;
+  if( v==0 ) return 0;
 
-  if( pDest->iMem==0 ){
-    pDest->iMem = sqlite3GetTempRange(pParse, pIn->nMem);
-    pDest->nMem = nResultCol;
-  }
+  addr = sqlite3VdbeCurrentAddr(v);
+  iContinue = sqlite3VdbeMakeLabel(v);
+  codeOffset(v, p, iContinue);
 
   switch( pDest->eDest ){
     /* Store the result as data using a unique key.
@@ -2338,9 +2338,9 @@ static int outputSubroutine(
     case SRT_EphemTab: {
       int r1 = sqlite3GetTempReg(pParse);
       int r2 = sqlite3GetTempReg(pParse);
-      sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1);
-      sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
-      sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2);
+      sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iMem, pIn->nMem, r1);
+      sqlite3VdbeAddOp2(v, OP_NewRowid, pDest->iParm, r2);
+      sqlite3VdbeAddOp3(v, OP_Insert, pDest->iParm, r1, r2);
       sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
       sqlite3ReleaseTempReg(pParse, r2);
       sqlite3ReleaseTempReg(pParse, r1);
@@ -2354,13 +2354,14 @@ static int outputSubroutine(
     */
     case SRT_Set: {
       int addr2, r1;
-      assert( nColumn==1 );
-      addr2 = sqlite3VdbeAddOp1(v, OP_IsNull, regResult);
-      p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affinity);
+      assert( pIn->nMem==1 );
+      addr2 = sqlite3VdbeAddOp1(v, OP_IsNull, pIn->iMem);
+      p->affinity = 
+         sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affinity);
       r1 = sqlite3GetTempReg(pParse);
-      sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, 1, r1, &p->affinity, 1);
-      sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
-      sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
+      sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iMem, 1, r1, &p->affinity, 1);
+      sqlite3ExprCacheAffinityChange(pParse, pIn->iMem, 1);
+      sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iParm, r1);
       sqlite3ReleaseTempReg(pParse, r1);
       sqlite3VdbeJumpHere(v, addr2);
       break;
@@ -2369,7 +2370,7 @@ static int outputSubroutine(
     /* If any row exist in the result set, record that fact and abort.
     */
     case SRT_Exists: {
-      sqlite3VdbeAddOp2(v, OP_Integer, 1, iParm);
+      sqlite3VdbeAddOp2(v, OP_Integer, 1, pDest->iParm);
       /* The LIMIT clause will terminate the loop for us */
       break;
     }
@@ -2379,8 +2380,8 @@ static int outputSubroutine(
     ** of the scan loop.
     */
     case SRT_Mem: {
-      assert( nColumn==1 );
-      sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
+      assert( pIn->nMem==1 );
+      sqlite3ExprCodeMove(pParse, pIn->iMem, pDest->iParm, 1);
       /* The LIMIT clause will jump out of the loop for us */
       break;
     }
@@ -2390,14 +2391,19 @@ static int outputSubroutine(
     ** case of a subroutine, the subroutine itself is responsible for
     ** popping the data from the stack.
     */
-    case SRT_Coroutine:
-    case SRT_Callback: {
-      if( eDest==SRT_Coroutine ){
-        sqlite3VdbeAddOp1(v, OP_Yield, pDest->regCoroutine);
-      }else{
-        sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nColumn);
-        sqlite3ExprCacheAffinityChange(pParse, regResult, nColumn);
+    case SRT_Coroutine: {
+      if( pDest->iMem==0 ){
+        pDest->iMem = sqlite3GetTempRange(pParse, pIn->nMem);
+        pDest->nMem = pIn->nMem;
       }
+      sqlite3ExprCodeMove(pParse, pIn->iMem, pDest->iMem, pDest->nMem);
+      sqlite3VdbeAddOp1(v, OP_Yield, pDest->iParm);
+      break;
+    }
+
+    case SRT_Callback: {
+      sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iMem, pIn->nMem);
+      sqlite3ExprCacheAffinityChange(pParse, pIn->iMem, pIn->nMem);
       break;
     }
 
@@ -2412,6 +2418,24 @@ static int outputSubroutine(
     }
 #endif
   }
+
+  /* Jump to the end of the loop if the LIMIT is reached.
+  */
+  if( p->iLimit ){
+    sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
+    sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, iBreak);
+  }
+
+  /* Advance the coroutine to its next value.
+  */
+  sqlite3VdbeResolveLabel(v, iContinue);
+  sqlite3VdbeAddOp1(v, OP_Yield, pIn->iParm);
+
+  /* Generate the subroutine return
+  */
+  sqlite3VdbeAddOp1(v, OP_Return, regReturn);
+
+  return addr;
 }
 
 /*
@@ -2498,37 +2522,74 @@ static int multiSelectOrderBy(
   SelectDest *pDest,    /* What to do with query results */
   char *aff             /* If eDest is SRT_Union, the affinity string */
 ){
-  int rc = SQLITE_OK;   /* Success code from a subroutine */
   Select *pPrior;       /* Another SELECT immediately to our left */
   Vdbe *v;              /* Generate code to this VDBE */
-  int nCol;             /* Number of columns in the result set */
-  ExprList *pOrderBy;   /* The ORDER BY clause on p */
-  int aSetP2[2];        /* Set P2 value of these op to number of columns */
-  int nSetP2 = 0;       /* Number of slots in aSetP2[] used */
   SelectDest destA;     /* Destination for coroutine A */
   SelectDest destB;     /* Destination for coroutine B */
-  int regAddrA;
-  int regEofA;
-  int regAddrB;
-  int regEofB;
-  int addrSelectA;
-  int addrSelectB;
-  int regOutA;
-  int regOutB;
-  int addrOutA;
-  int addrOutB;
-  int addrEofA;
-  int addrEofB;
-  int addrAltB;
-  int addrAeqB;
-  int addrAgtB;
-  int labelCmpr;
-  int labelEnd;
-  int j1, j2, j3;
-  
-  /* Patch up the ORDER BY clause */
+  int regAddrA;         /* Address register for select-A coroutine */
+  int regEofA;          /* Flag to indicate when select-A is complete */
+  int regAddrB;         /* Address register for select-B coroutine */
+  int regEofB;          /* Flag to indicate when select-B is complete */
+  int addrSelectA;      /* Address of the select-A coroutine */
+  int addrSelectB;      /* Address of the select-B coroutine */
+  int regOutA;          /* Address register for the output-A subroutine */
+  int regOutB;          /* Address register for the output-B subroutine */
+  int addrOutA;         /* Address of the output-A subroutine */
+  int addrOutB;         /* Address of the output-B subroutine */
+  int addrEofA;         /* Address of the select-A-exhausted subroutine */
+  int addrEofB;         /* Address of the select-B-exhausted subroutine */
+  int addrAltB;         /* Address of the A<B subroutine */
+  int addrAeqB;         /* Address of the A==B subroutine */
+  int addrAgtB;         /* Address of the A>B subroutine */
+  int regLimitA;        /* Limit register for select-A */
+  int regLimitB;        /* Limit register for select-A */
+  int savedLimit;       /* Saved value of p->iLimit */
+  int savedOffset;      /* Saved value of p->iOffset */
+  int labelCmpr;        /* Label for the start of the merge algorithm */
+  int labelEnd;         /* Label for the end of the overall SELECT stmt */
+  int j1, j2, j3;       /* Jump instructions that get retargetted */
+  int op;               /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */
+  KeyInfo *pKeyInfo;    /* Type data for comparisons */
+  int p4type;           /* P4 type used for pKeyInfo */
+  u8 NotUsed;           /* Dummy variable */
+
+  assert( p->pOrderBy!=0 );
+  v = pParse->pVdbe;
+  if( v==0 ) return SQLITE_NOMEM;
+  labelEnd = sqlite3VdbeMakeLabel(v);
+  labelCmpr = sqlite3VdbeMakeLabel(v);
+  pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
+  p4type = P4_KEYINFO_HANDOFF;
 
+  /* Patch up the ORDER BY clause
+  */
+  op = p->op;  
   pPrior = p->pPrior;
+  assert( pPrior->pOrderBy==0 );
+  if( processCompoundOrderBy(pParse, p, 0) ){
+    return SQLITE_ERROR;
+  }
+  pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, p->pOrderBy);
+  /* Separate the left and the right query from one another
+  */
+  p->pPrior = 0;
+  pPrior->pRightmost = 0;
+  processOrderGroupBy(pParse, p, p->pOrderBy, 1, &NotUsed);
+  processOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, 1, &NotUsed);
+  
+  /* Compute the limit registers */
+  computeLimitRegisters(pParse, p, labelEnd);
+  if( p->iLimit ){
+    regLimitA = ++pParse->nMem;
+    regLimitB = ++pParse->nMem;
+    sqlite3VdbeAddOp2(v, OP_Copy, p->iOffset ? p->iOffset+1 : p->iLimit,
+                                  regLimitA);
+    sqlite3VdbeAddOp2(v, OP_Copy, regLimitA, regLimitB);
+  }else{
+    regLimitA = regLimitB = 0;
+  }
+
   regAddrA = ++pParse->nMem;
   regEofA = ++pParse->nMem;
   regAddrB = ++pParse->nMem;
@@ -2538,123 +2599,194 @@ static int multiSelectOrderBy(
   sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA);
   sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB);
 
+  /* Jump past the various subroutines and coroutines to the main
+  ** merge loop
+  */
   j1 = sqlite3VdbeAddOp0(v, OP_Goto);
   addrSelectA = sqlite3VdbeCurrentAddr(v);
+
+  /* Generate a coroutine to evaluate the SELECT statement to the
+  ** left of the compound operator - the "A" select. */
   VdbeNoopComment((v, "Begin coroutine for left SELECT"));
-  sqlite3SelectDestInit(&destA, SRT_Coroutine, 0);
-  sqlite3Select();
+  pPrior->iLimit = regLimitA;
+  sqlite3Select(pParse, pPrior, &destA, 0, 0, 0, 0);
   sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofA);
-  sqlite3VdbeAddOp2(v, OP_Yield, regAddrA);
+  sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
   VdbeNoopComment((v, "End coroutine for left SELECT"));
 
+  /* Generate a coroutine to evaluate the SELECT statement on 
+  ** the right - the "B" select
+  */
   addrSelectB = sqlite3VdbeCurrentAddr(v);
   VdbeNoopComment((v, "Begin coroutine for right SELECT"));
-  sqlite3SelectDestInit(&destB, SRT_Coroutine, 0);
-  sqlite3Select();
+  savedLimit = p->iLimit;
+  savedOffset = p->iOffset;
+  p->iLimit = regLimitB;
+  p->iOffset = 0;  
+  sqlite3Select(pParse, p, &destB, 0, 0, 0, 0);
+  p->iLimit = savedLimit;
+  p->iOffset = savedOffset;
   sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofB);
-  sqlite3VdbeAddOp2(v, OP_Yield, regAddrB);
+  sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
   VdbeNoopComment((v, "End coroutine for right SELECT"));
 
+  /* Generate a subroutine that outputs the current row of the A
+  ** select as the next output row of the compound select and then
+  ** advances the A select to its next row
+  */
   VdbeNoopComment((v, "Output routine for A"));
-  addrOutA = outputSubroutine(pParse, &destA, pDest);
+  addrOutA = outputSubroutine(pParse, p, &destA, pDest, regOutA, labelEnd);
   
+  /* Generate a subroutine that outputs the current row of the B
+  ** select as the next output row of the compound select and then
+  ** advances the B select to its next row
+  */
   VdbeNoopComment((v, "Output routine for B"));
-  addrOutB = outputSubroutine(pParse, &destB, pDest);
+  addrOutB = outputSubroutine(pParse, p, &destB, pDest, regOutB, labelEnd);
 
+  /* Generate a subroutine to run when the results from select A
+  ** are exhausted and only data in select B remains.
+  */
+  VdbeNoopComment((v, "eof-A subroutine"));
+  addrEofA = sqlite3VdbeCurrentAddr(v);
   if( op==TK_EXCEPT || op==TK_INTERSECT ){
-    addrEofA = iEnd;
+    sqlite3VdbeAddOp2(v, OP_Goto, 0, labelEnd);
   }else{  
-    VdbeNoopCommment((v, "eof-A subroutine"));
-    addrEofA = sqlite3VdbeCurrentAddr(v);
     if( op==TK_ALL ){
       j2 = sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd);
       sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
-      sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
       sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
     }else{
       assert( op==TK_UNION );
-      sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd);
-      sqlite3ExprCodeMove(pParse, destB.iMem, destA.iMem, destB.nMem);
+      sqlite3ExprCodeCopy(pParse, destB.iMem, destA.iMem, destB.nMem);
       j2 = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
-      sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
       sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd);
-      sqlite3VdbeAddOp3(v, OP_Compare, destA.iMem, destB.iMem, destB.nMem);
-      sqlite3VdbeAddOp3(v, OP_Jump, j2, j2+1, j2);
+      sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destB.nMem,
+                           (char*)pKeyInfo, p4type);
+      p4type = P4_KEYINFO_STATIC;
+      sqlite3VdbeAddOp3(v, OP_Jump, j2, j2+4, j2);
+      sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
+      sqlite3VdbeAddOp2(v, OP_Goto, 0, j2+1);
     }
   }
 
-
+  /* Generate a subroutine to run when the results from select B
+  ** are exhausted and only data in select A remains.
+  */
   if( op==TK_INTERSECT ){
-    addrEofA = iEnd;
+    addrEofB = addrEofA;
   }else{  
-    VdbeNoopCommment((v, "eof-B subroutine"));
-    addrEofA = sqlite3VdbeCurrentAddr(v);
+    VdbeNoopComment((v, "eof-B subroutine"));
+    addrEofB = sqlite3VdbeCurrentAddr(v);
     if( op==TK_ALL || op==TK_EXCEPT ){
       j2 = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
       sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
-      sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
       sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
     }else{
       assert( op==TK_UNION );
       sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
-      sqlite3ExprCodeMove(pParse, destA.iMem, destB.iMem, destA.nMem);
+      sqlite3ExprCodeCopy(pParse, destA.iMem, destB.iMem, destA.nMem);
       j2 = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
-      sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
       sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
-      sqlite3VdbeAddOp3(v, OP_Compare, destA.iMem, destB.iMem, destB.nMem);
-      sqlite3VdbeAddOp3(v, OP_Jump, j2, j2+1, j2);
+      sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destB.nMem,
+                           (char*)pKeyInfo, p4type);
+      p4type = P4_KEYINFO_STATIC;
+      sqlite3VdbeAddOp3(v, OP_Jump, j2, j2+4, j2);
+      sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
+      sqlite3VdbeAddOp2(v, OP_Goto, 0, j2+1);
     }
   }
 
+  /* Generate code to handle the case of A<B
+  */
   VdbeNoopComment((v, "A-lt-B subroutine"));
   addrAltB = sqlite3VdbeCurrentAddr(v);
-  if( op!=TK_INTERSECT ){
+  if( op==TK_INTERSECT ){
+    sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
+  }else{
     sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
   }
-  addrAeqB = sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
   sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
-  sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCompare);
+  sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
 
+  /* Generate code to handle the case of A==B
+  */
   if( op==TK_ALL ){
     addrAeqB = addrAltB;
-  }else if( op==TK_INTERSECT ){
+  }else{
     VdbeNoopComment((v, "A-eq-B subroutine"));
-    sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
-    j2 = sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
-    sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
-    sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destA.iMem,
-                         pKeyInfo, P4_KEYINFO_STATIC);
-    j3 = sqlite3VdbeCurrentAddr(v)+1;
-    sqlite3VdbeAddOp3(v, OP_Jump, j3, j2, j3);
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCompare);
+    addrAeqB = sqlite3VdbeCurrentAddr(v);
+    if( op==TK_INTERSECT ){
+      sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
+      j2 = sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
+      sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
+      sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destA.nMem,
+                           (char*)pKeyInfo, p4type);
+      p4type = P4_KEYINFO_STATIC;
+      j3 = sqlite3VdbeCurrentAddr(v)+1;
+      sqlite3VdbeAddOp3(v, OP_Jump, j3, j2, j3);
+      sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
+    }else{
+      sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
+      sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
+      sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
+    }
   }
 
+  /* Generate code to handle the case of A>B
+  */
   VdbeNoopComment((v, "A-gt-B subroutine"));
   addrAgtB = sqlite3VdbeCurrentAddr(v);
   if( op==TK_ALL || op==TK_UNION ){
     sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
+  }else{
+    sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
   }
-  sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
   sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
-  sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCompare);
+  sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
 
+  /* This code runs once to initialize everything.
+  */
   sqlite3VdbeJumpHere(v, j1);
   sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofA);
   sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofB);
-  sqlite3VdbeAddOp2(v, OP_Integer, addrSelectA, regAddrA);
   sqlite3VdbeAddOp2(v, OP_Integer, addrSelectB, regAddrB);
-  sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
+  sqlite3VdbeAddOp2(v, OP_Gosub, regAddrA, addrSelectA);
   sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
   sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
   sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
-  sqlite3VdbeResolve(v, labelCompare);
-  sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destA.iMem,
-                         pKeyInfo, P4_KEYINFO_HANDOFF);
+
+  /* Implement the main merge loop
+  */
+  sqlite3VdbeResolveLabel(v, labelCmpr);
+  sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destA.nMem,
+                         (char*)pKeyInfo, p4type);
+  p4type = P4_KEYINFO_STATIC;
   sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB);
+
+  /* Jump to the this point in order to terminate the query.
+  */
   sqlite3VdbeResolveLabel(v, labelEnd);
-  
+
+  /* Set the number of output columns
+  */
+  if( pDest->eDest==SRT_Callback ){
+    Select *pFirst = p;
+    while( pFirst->pPrior ) pFirst = pFirst->pPrior;
+    generateColumnNames(pParse, 0, pFirst->pEList);
+  }
+
+  /* Free the KeyInfo if unused.
+  */
+  if( p4type==P4_KEYINFO_HANDOFF ){
+    sqlite3_free(pKeyInfo);
+  }
+
+
+  /*** TBD:  Insert subroutine calls to close cursors on incomplete
+  **** subqueries ****/
+  return SQLITE_OK;
 }
-#endif /***** ########### *****/
 
 #ifndef SQLITE_OMIT_VIEW
 /* Forward Declarations */
index 999d855def6eaa0c14a311bfdfd4469b332f718c..a23c6b11db6441d2304af78010a9b0167ee90e1d 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.724 2008/06/23 14:03:45 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.725 2008/06/24 00:32:36 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1161,7 +1161,7 @@ struct Expr {
 #define EP_ExpCollate 0x0100  /* Collating sequence specified explicitly */
 #define EP_AnyAff     0x0200  /* Can take a cached column of any affinity */
 #define EP_FixedDest  0x0400  /* Result needed in a specific register */
-
+#define EP_IntValue   0x0800  /* Integer value contained in iTable */
 /*
 ** These macros can be used to test, set, or clear bits in the 
 ** Expr.flags field.
@@ -1449,10 +1449,8 @@ struct SelectDest {
   u8 eDest;         /* How to dispose of the results */
   u8 affinity;      /* Affinity used when eDest==SRT_Set */
   int iParm;        /* A parameter used by the eDest disposal method */
-  int regCoroutine; /* Program counter register for SRT_Coroutine */
   int iMem;         /* Base register where results are written */
   int nMem;         /* Number of registers allocated */
-  int eofMem;       /* Register holding EOF flag */
 };
 
 /*
@@ -1913,6 +1911,7 @@ WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8);
 void sqlite3WhereEnd(WhereInfo*);
 int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
 void sqlite3ExprCodeMove(Parse*, int, int, int);
+void sqlite3ExprCodeCopy(Parse*, int, int, int);
 void sqlite3ExprClearColumnCache(Parse*, int);
 void sqlite3ExprCacheAffinityChange(Parse*, int, int);
 int sqlite3ExprWritableRegister(Parse*,int,int);
index caadda86c664e664b4c110af4e5a5ba4a24bc811..dea5643260f5aa6175f8887bdb1c14506d003c8d 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the SELECT statement.
 #
-# $Id: select1.test,v 1.58 2008/06/23 18:49:45 danielk1977 Exp $
+# $Id: select1.test,v 1.59 2008/06/24 00:32:36 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -544,6 +544,7 @@ do_test select1-6.21 {
    }
 } {d}
 do_test select1-6.22 {
+breakpoint
    execsql {
      SELECT a FROM t6 WHERE b IN 
         (SELECT b FROM t6 WHERE a<='b' UNION SELECT '3' AS x
@@ -932,4 +933,3 @@ do_test select1-14.2 {
 } {0}
 
 finish_test
-