Fix a bug in the KEYINFO handling within select.c.  Change the OP_Move
opcode to take a count and to move multiple registers.  Initial code for
the compound-select merge optimization is added but is incomplete
and is commented out. (CVS 5272)

FossilOrigin-Name: 663a590e3086145a57af7569d8f798b6b6a8b76c
diff --git a/src/expr.c b/src/expr.c
index 298dbac..ef88cfe 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -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.373 2008/06/05 16:47:39 danielk1977 Exp $
+** $Id: expr.c,v 1.374 2008/06/22 12:37:58 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -2112,16 +2112,17 @@
 }
 
 /*
-** Generate code to moves content from one register to another.
-** Keep the column cache up-to-date.
+** Generate code to move content from registers iFrom...iFrom+nReg-1
+** over to iTo..iTo+nReg-1. Keep the column cache up-to-date.
 */
-void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo){
+void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
   int i;
   if( iFrom==iTo ) return;
-  sqlite3VdbeAddOp2(pParse->pVdbe, OP_Move, iFrom, iTo);
+  sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
   for(i=0; i<pParse->nColCache; i++){
-    if( pParse->aColCache[i].iReg==iFrom ){
-      pParse->aColCache[i].iReg = iTo;
+    int x = pParse->aColCache[i].iReg;
+    if( x>=iFrom && x<iFrom+nReg ){
+      pParse->aColCache[i].iReg += iTo-iFrom;
     }
   }
 }
diff --git a/src/fault.c b/src/fault.c
index b75dc66..5ede8b9 100644
--- a/src/fault.c
+++ b/src/fault.c
@@ -10,7 +10,7 @@
 **
 *************************************************************************
 **
-** $Id: fault.c,v 1.9 2008/06/20 14:59:51 danielk1977 Exp $
+** $Id: fault.c,v 1.10 2008/06/22 12:37:58 drh Exp $
 */
 
 /*
@@ -69,4 +69,3 @@
 }
 
 #endif   /* #ifndef SQLITE_OMIT_BUILTIN_TEST */
-
diff --git a/src/pragma.c b/src/pragma.c
index 616c1f1..c4c0709 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to implement the PRAGMA command.
 **
-** $Id: pragma.c,v 1.179 2008/06/05 11:39:11 danielk1977 Exp $
+** $Id: pragma.c,v 1.180 2008/06/22 12:37:58 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1004,7 +1004,7 @@
       sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
          sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
          P4_DYNAMIC);
-      sqlite3VdbeAddOp2(v, OP_Move, 2, 4);
+      sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
       sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
       sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
       sqlite3VdbeJumpHere(v, addr);
diff --git a/src/select.c b/src/select.c
index 2de5b94..d072b20 100644
--- a/src/select.c
+++ b/src/select.c
@@ -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.432 2008/06/20 18:13:25 drh Exp $
+** $Id: select.c,v 1.433 2008/06/22 12:37:58 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -425,7 +425,7 @@
   int regRecord = sqlite3GetTempReg(pParse);
   sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0);
   sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
-  sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1);
+  sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
   sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord);
   sqlite3VdbeAddOp2(v, OP_IdxInsert, pOrderBy->iECursor, regRecord);
   sqlite3ReleaseTempReg(pParse, regRecord);
@@ -693,7 +693,7 @@
       if( pOrderBy ){
         pushOntoSorter(pParse, pOrderBy, p, regResult);
       }else{
-        sqlite3ExprCodeMove(pParse, regResult, iParm);
+        sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
         /* The LIMIT clause will jump out of the loop for us */
       }
       break;
@@ -841,7 +841,7 @@
     }
     case SRT_Mem: {
       assert( nColumn==1 );
-      sqlite3ExprCodeMove(pParse, regRow, iParm);
+      sqlite3ExprCodeMove(pParse, regRow, iParm, 1);
       /* The LIMIT clause will terminate the loop for us */
       break;
     }
@@ -1668,12 +1668,6 @@
 ** Analyze and ORDER BY or GROUP BY clause in a SELECT statement.  Return
 ** the number of errors seen.
 **
-** The processing depends on whether the SELECT is simple or compound.
-** For a simple SELECT statement, evry term of the ORDER BY or GROUP BY
-** clause needs to be an expression.  If any expression is an integer
-** constant, then that expression is replaced by the corresponding 
-** expression from the result set.
-**
 ** 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.
@@ -1873,6 +1867,15 @@
 }
 #endif /* SQLITE_OMIT_COMPOUND_SELECT */
 
+/* Forward reference */
+static int multiSelectOrderBy(
+  Parse *pParse,        /* Parsing context */
+  Select *p,            /* The right-most of SELECTs to be coded */
+  SelectDest *pDest,    /* What to do with query results */
+  char *aff             /* If eDest is SRT_Union, the affinity string */
+);
+
+
 #ifndef SQLITE_OMIT_COMPOUND_SELECT
 /*
 ** This routine is called to process a compound query form from
@@ -1920,8 +1923,6 @@
   int nSetP2 = 0;       /* Number of slots in aSetP2[] used */
   SelectDest dest;      /* Alternative data destination */
 
-  dest = *pDest;
-
   /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs.  Only
   ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
   */
@@ -1953,8 +1954,15 @@
     goto multi_select_end;
   }
 
+#if 0
+  if( p->pOrderBy ){
+    return multiSelectOrderBy(pParse, p, pDest, aff);
+  }
+#endif
+
   /* Create the destination temporary table if necessary
   */
+  dest = *pDest;
   if( dest.eDest==SRT_EphemTab ){
     assert( p->pEList );
     assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) );
@@ -2305,6 +2313,349 @@
 }
 #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
+){
+  Vdbe *v = pParse->pVdbe;
+  if( v==0 ) return;
+
+  if( pDest->iMem==0 ){
+    pDest->iMem = sqlite3GetTempRange(pParse, pIn->nMem);
+    pDest->nMem = nResultCol;
+  }
+
+  switch( pDest->eDest ){
+    /* Store the result as data using a unique key.
+    */
+    case SRT_Table:
+    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);
+      sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
+      sqlite3ReleaseTempReg(pParse, r2);
+      sqlite3ReleaseTempReg(pParse, r1);
+      break;
+    }
+
+#ifndef SQLITE_OMIT_SUBQUERY
+    /* If we are creating a set for an "expr IN (SELECT ...)" construct,
+    ** then there should be a single item on the stack.  Write this
+    ** item into the set table with bogus data.
+    */
+    case SRT_Set: {
+      int addr2, r1;
+      assert( nColumn==1 );
+      addr2 = sqlite3VdbeAddOp1(v, OP_IsNull, regResult);
+      p->affinity = sqlite3CompareAffinity(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);
+      sqlite3ReleaseTempReg(pParse, r1);
+      sqlite3VdbeJumpHere(v, addr2);
+      break;
+    }
+
+    /* If any row exist in the result set, record that fact and abort.
+    */
+    case SRT_Exists: {
+      sqlite3VdbeAddOp2(v, OP_Integer, 1, iParm);
+      /* The LIMIT clause will terminate the loop for us */
+      break;
+    }
+
+    /* If this is a scalar select that is part of an expression, then
+    ** store the results in the appropriate memory cell and break out
+    ** of the scan loop.
+    */
+    case SRT_Mem: {
+      assert( nColumn==1 );
+      sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
+      /* The LIMIT clause will jump out of the loop for us */
+      break;
+    }
+#endif /* #ifndef SQLITE_OMIT_SUBQUERY */
+
+    /* Send the data to the callback function or to a subroutine.  In the
+    ** 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);
+      }
+      break;
+    }
+
+#if !defined(SQLITE_OMIT_TRIGGER)
+    /* Discard the results.  This is used for SELECT statements inside
+    ** the body of a TRIGGER.  The purpose of such selects is to call
+    ** user-defined functions that have side effects.  We do not care
+    ** about the actual results of the select.
+    */
+    default: {
+      break;
+    }
+#endif
+  }
+}
+
+/*
+** Alternative compound select code generator for cases when there
+** is an ORDER BY clause.
+**
+** We assume a query of the following form:
+**
+**      <selectA>  <operator>  <selectB>  ORDER BY <orderbylist>
+**
+** <operator> is one of UNION ALL, UNION, EXCEPT, or INTERSECT.  The idea
+** is to code both <selectA> and <selectB> with the ORDER BY clause as
+** co-routines.  Then run the co-routines in parallel and merge the results
+** into the output.  In addition to the two coroutines (called selectA and
+** selectB) there are 7 subroutines:
+**
+**    outA:    Move the output of the selectA coroutine into the output
+**             of the compound query.
+**
+**    outB:    Move the output of the selectB coroutine into the output
+**             of the compound query.  (Only generated for UNION and
+**             UNION ALL.  EXCEPT and INSERTSECT never output a row that
+**             appears only in B.)
+**
+**    AltB:    Called when there is data from both coroutines and A<B.
+**
+**    AeqB:    Called when there is data from both coroutines and A==B.
+**
+**    AgtB:    Called when there is data from both coroutines and A>B.
+**
+**    EofA:    Called when data is exhausted from selectA.
+**
+**    EofB:    Called when data is exhausted from selectB.
+**
+** The implementation of the latter five subroutines depend on which 
+** <operator> is used:
+**
+**
+**             UNION ALL         UNION            EXCEPT          INTERSECT
+**          -------------  -----------------  --------------  -----------------
+**   AltB:   outA, nextA      outA, nextA       outA, nextA        nextA
+**
+**   AeqB:   outA, nextA         nextA             nextA           outA
+**                                                            nextA while A==B
+**
+**   AgtB:   outB, nextB      outB, nextB          nextB           nextB
+**
+**   EofA:   outB, nextB      A<-B, outB,          halt            halt
+**                          nextB while A==B
+**
+**   EofB:   outA, nextA      B<-A, outA        outA, nextA        halt
+**                          nextA while A==B
+**
+** The implementation plan is to implement the two coroutines and seven
+** subroutines first, then put the control logic at the bottom.  Like this:
+**
+**          goto Init
+**     coA: coroutine for left query (A)
+**     coB: coroutine for right query (B)
+**    outA: output one row of A
+**    outB: output one row of B (UNION and UNION ALL only)
+**    EofA: ...
+**    EofB: ...
+**    AltB: ...
+**    AeqB: ...
+**    AgtB: ...
+**    Init: initialize coroutine registers
+**          yield coA
+**          if eof(A) goto EofA
+**          yield coB
+**          if eof(B) goto EofB
+**    Cmpr: Compare A, B
+**          Jump AltB, AeqB, AgtB
+**     End: ...
+**
+** We call AltB, AeqB, AgtB, EofA, and EofB "subroutines" but they are not
+** actually called using Gosub and they do not Return.  EofA and EofB loop
+** until all data is exhausted then jump to the "end" labe.  AltB, AeqB,
+** and AgtB jump to either L2 or to one of EofA or EofB.
+*/
+static int multiSelectOrderBy(
+  Parse *pParse,        /* Parsing context */
+  Select *p,            /* The right-most of SELECTs to be coded */
+  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 */
+
+  pPrior = p->pPrior;
+  regAddrA = ++pParse->nMem;
+  regEofA = ++pParse->nMem;
+  regAddrB = ++pParse->nMem;
+  regEofB = ++pParse->nMem;
+  regOutA = ++pParse->nMem;
+  regOutB = ++pParse->nMem;
+  sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA);
+  sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB);
+
+  j1 = sqlite3VdbeAddOp0(v, OP_Goto);
+  addrSelectA = sqlite3VdbeCurrentAddr(v);
+  VdbeNoopComment((v, "Begin coroutine for left SELECT"));
+  sqlite3SelectDestInit(&destA, SRT_Coroutine, 0);
+  sqlite3Select();
+  sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofA);
+  sqlite3VdbeAddOp2(v, OP_Yield, regAddrA);
+  VdbeNoopComment((v, "End coroutine for left SELECT"));
+
+  addrSelectB = sqlite3VdbeCurrentAddr(v);
+  VdbeNoopComment((v, "Begin coroutine for right SELECT"));
+  sqlite3SelectDestInit(&destB, SRT_Coroutine, 0);
+  sqlite3Select();
+  sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofB);
+  sqlite3VdbeAddOp2(v, OP_Yield, regAddrB);
+  VdbeNoopComment((v, "End coroutine for right SELECT"));
+
+  VdbeNoopComment((v, "Output routine for A"));
+  addrOutA = outputSubroutine(pParse, &destA, pDest);
+  
+  VdbeNoopComment((v, "Output routine for B"));
+  addrOutB = outputSubroutine(pParse, &destB, pDest);
+
+  if( op==TK_EXCEPT || op==TK_INTERSECT ){
+    addrEofA = iEnd;
+  }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);
+      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);
+    }
+  }
+
+
+  if( op==TK_INTERSECT ){
+    addrEofA = iEnd;
+  }else{  
+    VdbeNoopCommment((v, "eof-B subroutine"));
+    addrEofA = 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);
+      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);
+    }
+  }
+
+  VdbeNoopComment((v, "A-lt-B subroutine"));
+  addrAltB = sqlite3VdbeCurrentAddr(v);
+  if( op!=TK_INTERSECT ){
+    sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
+  }
+  addrAeqB = sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
+  sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
+  sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCompare);
+
+  if( op==TK_ALL ){
+    addrAeqB = addrAltB;
+  }else if( op==TK_INTERSECT ){
+    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);
+  }
+
+  VdbeNoopComment((v, "A-gt-B subroutine"));
+  addrAgtB = sqlite3VdbeCurrentAddr(v);
+  if( op==TK_ALL || op==TK_UNION ){
+    sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
+  }
+  sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
+  sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
+  sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCompare);
+
+  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_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);
+  sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB);
+  sqlite3VdbeResolveLabel(v, labelEnd);
+  
+}
+#endif /***** ########### *****/
+
 #ifndef SQLITE_OMIT_VIEW
 /* Forward Declarations */
 static void substExprList(sqlite3*, ExprList*, int, ExprList*);
@@ -3472,7 +3823,7 @@
         }
       }
       sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr,
-                          (char*)pKeyInfo, P4_KEYINFO_STATIC);
+                          (char*)pKeyInfo, P4_KEYINFO);
       j1 = sqlite3VdbeCurrentAddr(v);
       sqlite3VdbeAddOp3(v, OP_Jump, j1+1, 0, j1+1);
 
@@ -3485,9 +3836,7 @@
       ** and resets the aggregate accumulator registers in preparation
       ** for the next GROUP BY batch.
       */
-      for(j=0; j<pGroupBy->nExpr; j++){
-        sqlite3ExprCodeMove(pParse, iBMem+j, iAMem+j);
-      }
+      sqlite3ExprCodeMove(pParse, iBMem, iAMem, pGroupBy->nExpr);
       sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow);
       VdbeComment((v, "output one row"));
       sqlite3VdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd);
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index d91383d..2f37042 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.721 2008/06/20 15:24:02 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.722 2008/06/22 12:37:58 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1911,7 +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);
+void sqlite3ExprCodeMove(Parse*, int, int, int);
 void sqlite3ExprClearColumnCache(Parse*, int);
 void sqlite3ExprCacheAffinityChange(Parse*, int, int);
 int sqlite3ExprWritableRegister(Parse*,int,int);
diff --git a/src/test_mutex.c b/src/test_mutex.c
index ee3037e..b24bd2e 100644
--- a/src/test_mutex.c
+++ b/src/test_mutex.c
@@ -10,7 +10,7 @@
 **
 *************************************************************************
 ** 
-** $Id: test_mutex.c,v 1.3 2008/06/19 08:51:25 danielk1977 Exp $
+** $Id: test_mutex.c,v 1.4 2008/06/22 12:37:58 drh Exp $
 */
 
 #include "tcl.h"
@@ -303,4 +303,3 @@
   memset(&g, 0, sizeof(g));
   return SQLITE_OK;
 }
-
diff --git a/src/vdbe.c b/src/vdbe.c
index eec7b37..5bfe1f5 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.752 2008/06/20 18:13:25 drh Exp $
+** $Id: vdbe.c,v 1.753 2008/06/22 12:37:58 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -458,7 +458,7 @@
 #endif
 
 #ifdef SQLITE_DEBUG
-#  define REGISTER_TRACE(R,M) if(p->trace&&R>0)registerTrace(p->trace,R,M)
+#  define REGISTER_TRACE(R,M) if(p->trace)registerTrace(p->trace,R,M)
 #else
 #  define REGISTER_TRACE(R,M)
 #endif
@@ -976,27 +976,36 @@
   break;
 }
 
-/* Opcode: Move P1 P2 * * *
+/* Opcode: Move P1 P2 P3 * *
 **
-** Move the value in register P1 over into register P2.  Register P1
-** is left holding a NULL.  It is an error for P1 and P2 to be the
-** same register.
+** Move the values in register P1..P1+P3-1 over into
+** registers P2..P2+P3-1.  Registers P1..P1+P1-1 are
+** left holding a NULL.  It is an error for register ranges
+** P1..P1+P3-1 and P2..P2+P3-1 to overlap.
 */
 case OP_Move: {
   char *zMalloc;
-  assert( pOp->p1>0 );
-  assert( pOp->p1<=p->nMem );
-  pIn1 = &p->aMem[pOp->p1];
-  REGISTER_TRACE(pOp->p1, pIn1);
-  assert( pOp->p2>0 );
-  assert( pOp->p2<=p->nMem );
-  pOut = &p->aMem[pOp->p2];
-  assert( pOut!=pIn1 );
-  zMalloc = pOut->zMalloc;
-  pOut->zMalloc = 0;
-  sqlite3VdbeMemMove(pOut, pIn1);
-  pIn1->zMalloc = zMalloc;
-  REGISTER_TRACE(pOp->p2, pOut);
+  int n = pOp->p3;
+  int p1 = pOp->p1;
+  int p2 = pOp->p2;
+  assert( n>0 );
+  assert( p1>0 );
+  assert( p1+n<p->nMem );
+  pIn1 = &p->aMem[p1];
+  assert( p2>0 );
+  assert( p2+n<p->nMem );
+  pOut = &p->aMem[p2];
+  assert( p1+n<=p2 || p2+n<=p1 );
+  while( n-- ){
+    REGISTER_TRACE(p1++, pIn1);
+    zMalloc = pOut->zMalloc;
+    pOut->zMalloc = 0;
+    sqlite3VdbeMemMove(pOut, pIn1);
+    pIn1->zMalloc = zMalloc;
+    REGISTER_TRACE(p2++, pOut);
+    pIn1++;
+    pOut++;
+  }
   break;
 }
 
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index e139fa9..a89a960 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -14,7 +14,7 @@
 ** to version 2.8.7, all this code was combined into the vdbe.c source file.
 ** But that file was getting too big so this subroutines were split out.
 **
-** $Id: vdbeaux.c,v 1.390 2008/06/20 18:13:25 drh Exp $
+** $Id: vdbeaux.c,v 1.391 2008/06/22 12:37:58 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -548,19 +548,13 @@
     pKeyInfo = sqlite3Malloc( nByte );
     pOp->p4.pKeyInfo = pKeyInfo;
     if( pKeyInfo ){
+      u8 *aSortOrder;
       memcpy(pKeyInfo, zP4, nByte);
-      /* In the current implementation, P4_KEYINFO is only ever used on
-      ** KeyInfo structures that have no aSortOrder component.  Elements
-      ** with an aSortOrder always use P4_KEYINFO_HANDOFF.  So we do not
-      ** need to bother with duplicating the aSortOrder. */
-      assert( pKeyInfo->aSortOrder==0 );
-#if 0
       aSortOrder = pKeyInfo->aSortOrder;
       if( aSortOrder ){
         pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
         memcpy(pKeyInfo->aSortOrder, aSortOrder, nField);
       }
-#endif
       pOp->p4type = P4_KEYINFO;
     }else{
       p->db->mallocFailed = 1;