]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Do not let the multi-core sorter use lookaside memory, which is not threads-sort-ex1
authordrh <drh@noemail.net>
Wed, 22 Aug 2012 15:16:36 +0000 (15:16 +0000)
committerdrh <drh@noemail.net>
Wed, 22 Aug 2012 15:16:36 +0000 (15:16 +0000)
thread-safe.

FossilOrigin-Name: acdc7d1270b6aacf4612296a8d4dd596042b058c

manifest
manifest.uuid
src/threads.c
src/vdbe.c
src/vdbeInt.h
src/vdbeaux.c
src/vdbesort.c

index 38f14093c3abfa5501a78fcdc6003aef8032d2c5..8a00a3edc52b5a167f6da4e74cda62fdf023c5a2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Merge\sin\sall\sthe\slatest\strunk\schanges.
-D 2012-08-21T17:46:18.408
+C Do\snot\slet\sthe\smulti-core\ssorter\suse\slookaside\smemory,\swhich\sis\snot\nthread-safe.
+D 2012-08-22T15:16:36.722
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in adec39f15a9c7000f634b87a535b95279b0cbd09
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -231,21 +231,21 @@ F src/test_vfs.c c6260ef238c1142c8f8bd402db02216afd182ae3
 F src/test_vfstrace.c 6b28adb2a0e8ecd0f2e3581482e1f658b11b4067
 F src/test_wholenumber.c 3d2b9ed1505c40ad5c5ca2ad16ae7a289d6cc251
 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
-F src/threads.c 2b918d1f4f0b0831e8f41c49bcaa097f01490120
+F src/threads.c cde9d885fd562b5427f89a42a8829085f88b17df
 F src/tokenize.c 1e86210d3976717a19238ea7b047fac481fe8c12
 F src/trigger.c ee7e178fb9188f44b532cebd449a7c1df90fb684
 F src/update.c d3076782c887c10e882996550345da9c4c9f9dea
 F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
 F src/util.c 0af2e515dc0dabacec931bca39525f6c3f1c5455
 F src/vacuum.c 587a52bb8833d7ac15af8916f25437e2575028bd
-F src/vdbe.c 75da79cdcd58481825a06f045bc2f5ea3966eeae
+F src/vdbe.c 1a451790e5abd4df1c0ad0c39d5d6398888b473f
 F src/vdbe.h 18f581cac1f4339ec3299f3e0cc6e11aec654cdb
-F src/vdbeInt.h 986b6b11a13c517337355009e5438703ba5b0a40
+F src/vdbeInt.h 3c238336fc5b186b193553dbac4e1979d91e0c0d
 F src/vdbeapi.c 88ea823bbcb4320f5a6607f39cd7c2d3cc4c26b1
-F src/vdbeaux.c dce80038c3c41f2680e5ab4dd0f7e0d8b7ff9071
+F src/vdbeaux.c 84bd15358329f4005a7bceefafc1e798592e987d
 F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
 F src/vdbemem.c cb55e84b8e2c15704968ee05f0fae25883299b74
-F src/vdbesort.c 3945ae71fe43e52727ec52103a07492e9df1776f
+F src/vdbesort.c acaefad52f6345a06fcfe2ec7da0c7d7d2569c39
 F src/vdbetrace.c 8bd5da325fc90f28464335e4cc4ad1407fe30835
 F src/vtab.c bb8ea3a26608bb1357538a5d2fc72beba6638998
 F src/wal.c 9294df6f96aae5909ae1a9b733fd1e1b4736978b
@@ -1012,7 +1012,7 @@ F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9
-P 555fc07efd1a1bc597804dcacbbcd95e88e75e90 573770f5a66fa4d708931b30350149eb739da607
-R 6a248acc2b1ad3eddb9f82f26a87ebb7
+P 45cdc32f1e4d33959108dac94f551a4b8030424d
+R fe69bbfbdf0f9035e48cc3502476a4c4
 U drh
-Z eefdd7d4c689b509af3b4731cefe3c98
+Z cf3f449e5e4dc5f0a36f059aada3751c
index c3f2313a3af0a9f2f3f3383cfa9cbcb03a335d08..571cd821393f2b7edd2e7cce71ab23ec566d5f72 100644 (file)
@@ -1 +1 @@
-45cdc32f1e4d33959108dac94f551a4b8030424d
\ No newline at end of file
+acdc7d1270b6aacf4612296a8d4dd596042b058c
\ No newline at end of file
index 33781a7aace67cb58f17f5997ba98ae3947e3dad..7cc964250d8774ac48975d5898511eda17a0ad34 100644 (file)
@@ -47,7 +47,6 @@ int sqlite3ThreadCreate(
   void *pIn                 /* Argument passed into xTask() */
 ){
   SQLiteThread *p;
-  int rc;
 
   assert( ppThread!=0 );
   assert( xTask!=0 );
index 12e73251434f89c58b6416bec1c8ed3c66c2c406..8d512ed2f50be84cd5db52f231b3e7a00c473405 100644 (file)
@@ -4405,7 +4405,7 @@ case OP_Rewind: {        /* jump */
   assert( pC->isSorter==(pOp->opcode==OP_SorterSort) );
   res = 1;
   if( isSorter(pC) ){
-    rc = sqlite3VdbeSorterRewind(db, pC, &res);
+    rc = sqlite3VdbeSorterRewind(pC, &res);
   }else{
     pCrsr = pC->pCursor;
     assert( pCrsr );
@@ -4474,7 +4474,7 @@ case OP_Next: {        /* jump */
   assert( pC->isSorter==(pOp->opcode==OP_SorterNext) );
   if( isSorter(pC) ){
     assert( pOp->opcode==OP_SorterNext );
-    rc = sqlite3VdbeSorterNext(db, pC, &res);
+    rc = sqlite3VdbeSorterNext(pC, &res);
   }else{
     res = 1;
     assert( pC->deferredMoveto==0 );
@@ -4530,7 +4530,7 @@ case OP_IdxInsert: {        /* in2 */
     rc = ExpandBlob(pIn2);
     if( rc==SQLITE_OK ){
       if( isSorter(pC) ){
-        rc = sqlite3VdbeSorterWrite(db, pC, pIn2);
+        rc = sqlite3VdbeSorterWrite(pC, pIn2);
       }else{
         nKey = pIn2->n;
         zKey = pIn2->z;
index 1f5694a595f55c155c58b2575f563145d2a9710b..88a2eefd3121775adcaa149149bc5dd23e47b1ff 100644 (file)
@@ -422,19 +422,19 @@ int sqlite3VdbeTransferError(Vdbe *p);
 
 #ifdef SQLITE_OMIT_MERGE_SORT
 # define sqlite3VdbeSorterInit(Y,Z)      SQLITE_OK
-# define sqlite3VdbeSorterWrite(X,Y,Z)   SQLITE_OK
-# define sqlite3VdbeSorterClose(Y,Z)
+# define sqlite3VdbeSorterWrite(Y,Z)     SQLITE_OK
+# define sqlite3VdbeSorterClose(Z)
 # define sqlite3VdbeSorterRowkey(Y,Z)    SQLITE_OK
-# define sqlite3VdbeSorterRewind(X,Y,Z)  SQLITE_OK
-# define sqlite3VdbeSorterNext(X,Y,Z)    SQLITE_OK
-# define sqlite3VdbeSorterCompare(X,Y,Z) SQLITE_OK
+# define sqlite3VdbeSorterRewind(Y,Z)    SQLITE_OK
+# define sqlite3VdbeSorterNext(Y,Z)      SQLITE_OK
+# define sqlite3VdbeSorterCompare(Y,Z)   SQLITE_OK
 #else
 int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
-void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
+void sqlite3VdbeSorterClose(VdbeCursor *);
 int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
-int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
-int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *);
-int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *);
+int sqlite3VdbeSorterNext(const VdbeCursor *, int *);
+int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
+int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
 int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int *);
 #endif
 
index 3ccf7116192a2aeee8695787a81a875b46ea22d9..2551b9fb79eb398b2aa7dc260c58b4262f44a628 100644 (file)
@@ -1575,7 +1575,7 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
   if( pCx==0 ){
     return;
   }
-  sqlite3VdbeSorterClose(p->db, pCx);
+  sqlite3VdbeSorterClose(pCx);
   if( pCx->pBt ){
     sqlite3BtreeClose(pCx->pBt);
     /* The pCx->pCursor will be close automatically, if it exists, by
index 4b546e7a9033af668642b7476aaef157e3c0bc3a..0fd17ab40fb234f97f1d3a6b65a2c88f95075c8f 100644 (file)
@@ -107,6 +107,8 @@ struct VdbeSorter {
   SorterRecord *pRecord;          /* Head of in-memory record list */
   int nRecord;                    /* Number of elements on the pRecord list */
   UnpackedRecord *pUnpacked;      /* Used to unpack keys */
+  KeyInfo *pKeyInfo;              /* Copy of cursor KeyInfo without db ptr */
+  sqlite3 *db;                    /* Database connection */
 };
 
 /*
@@ -116,6 +118,7 @@ struct VdbeSorter {
 struct VdbeSorterIter {
   i64 iReadOff;                   /* Current read offset */
   i64 iEof;                       /* 1 byte past EOF for this iterator */
+  sqlite3 *db;                    /* Corresponding database connection */
   int nAlloc;                     /* Bytes of space at aAlloc */
   int nKey;                       /* Number of bytes in key */
   sqlite3_file *pFile;            /* File iterator is reading from */
@@ -178,7 +181,6 @@ static void vdbeSorterIterZero(sqlite3 *db, VdbeSorterIter *pIter){
 ** next call to this function.
 */
 static int vdbeSorterIterRead(
-  sqlite3 *db,                    /* Database handle (for malloc) */
   VdbeSorterIter *p,              /* Iterator */
   int nByte,                      /* Bytes of data to read */
   u8 **ppOut                      /* OUT: Pointer to buffer containing data */
@@ -223,7 +225,7 @@ static int vdbeSorterIterRead(
     if( p->nAlloc<nByte ){
       int nNew = p->nAlloc*2;
       while( nByte>nNew ) nNew = nNew*2;
-      p->aAlloc = sqlite3DbReallocOrFree(db, p->aAlloc, nNew);
+      p->aAlloc = sqlite3DbReallocOrFree(p->db, p->aAlloc, nNew);
       if( !p->aAlloc ) return SQLITE_NOMEM;
       p->nAlloc = nNew;
     }
@@ -243,7 +245,7 @@ static int vdbeSorterIterRead(
 
       nCopy = nRem;
       if( nRem>p->nBuffer ) nCopy = p->nBuffer;
-      rc = vdbeSorterIterRead(db, p, nCopy, &aNext);
+      rc = vdbeSorterIterRead(p, nCopy, &aNext);
       if( rc!=SQLITE_OK ) return rc;
       assert( aNext!=p->aAlloc );
       memcpy(&p->aAlloc[nByte - nRem], aNext, nCopy);
@@ -260,7 +262,7 @@ static int vdbeSorterIterRead(
 ** Read a varint from the stream of data accessed by p. Set *pnOut to
 ** the value read.
 */
-static int vdbeSorterIterVarint(sqlite3 *db, VdbeSorterIter *p, u64 *pnOut){
+static int vdbeSorterIterVarint(VdbeSorterIter *p, u64 *pnOut){
   int iBuf;
 
   iBuf = p->iReadOff % p->nBuffer;
@@ -270,7 +272,7 @@ static int vdbeSorterIterVarint(sqlite3 *db, VdbeSorterIter *p, u64 *pnOut){
     u8 aVarint[16], *a;
     int i = 0, rc;
     do{
-      rc = vdbeSorterIterRead(db, p, 1, &a);
+      rc = vdbeSorterIterRead(p, 1, &a);
       if( rc ) return rc;
       aVarint[(i++)&0xf] = a[0];
     }while( (a[0]&0x80)!=0 );
@@ -286,11 +288,11 @@ static int vdbeSorterIterVarint(sqlite3 *db, VdbeSorterIter *p, u64 *pnOut){
 ** no error occurs, or an SQLite error code if one does.
 */
 static int vdbeSorterIterNext(
-  sqlite3 *db,                    /* Database handle (for sqlite3DbMalloc() ) */
   VdbeSorterIter *pIter           /* Iterator to advance */
 ){
   int rc;                         /* Return Code */
   u64 nRec = 0;                   /* Size of record in bytes */
+  sqlite3 *db = pIter->db;        /* Database connection */
 
   if( pIter->iReadOff>=pIter->iEof ){
     /* This is an EOF condition */
@@ -298,10 +300,10 @@ static int vdbeSorterIterNext(
     return SQLITE_OK;
   }
 
-  rc = vdbeSorterIterVarint(db, pIter, &nRec);
+  rc = vdbeSorterIterVarint(pIter, &nRec);
   if( rc==SQLITE_OK ){
     pIter->nKey = (int)nRec;
-    rc = vdbeSorterIterRead(db, pIter, (int)nRec, &pIter->aKey);
+    rc = vdbeSorterIterRead(pIter, (int)nRec, &pIter->aKey);
   }
 
   return rc;
@@ -314,7 +316,6 @@ static int vdbeSorterIterNext(
 ** PMA is empty).
 */
 static int vdbeSorterIterInit(
-  sqlite3 *db,                    /* Database handle */
   const VdbeSorter *pSorter,      /* Sorter object */
   i64 iStart,                     /* Start offset in pFile */
   VdbeSorterIter *pIter,          /* Iterator to populate */
@@ -322,6 +323,7 @@ static int vdbeSorterIterInit(
 ){
   int rc = SQLITE_OK;
   int nBuf;
+  sqlite3 *db = pSorter->db;
 
   nBuf = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
 
@@ -330,6 +332,7 @@ static int vdbeSorterIterInit(
   assert( pIter->aBuffer==0 );
   pIter->pFile = pSorter->pTemp1;
   pIter->iReadOff = iStart;
+  pIter->db = db;
   pIter->nAlloc = 128;
   pIter->aAlloc = (u8 *)sqlite3DbMallocRaw(db, pIter->nAlloc);
   pIter->nBuffer = nBuf;
@@ -355,14 +358,14 @@ static int vdbeSorterIterInit(
     if( rc==SQLITE_OK ){
       u64 nByte;                       /* Size of PMA in bytes */
       pIter->iEof = pSorter->iWriteOff;
-      rc = vdbeSorterIterVarint(db, pIter, &nByte);
+      rc = vdbeSorterIterVarint(pIter, &nByte);
       pIter->iEof = pIter->iReadOff + nByte;
       *pnByte += nByte;
     }
   }
 
   if( rc==SQLITE_OK ){
-    rc = vdbeSorterIterNext(db, pIter);
+    rc = vdbeSorterIterNext(pIter);
   }
   return rc;
 }
@@ -384,14 +387,14 @@ static int vdbeSorterIterInit(
 ** has been allocated and contains an unpacked record that is used as key2.
 */
 static void vdbeSorterCompare(
-  const VdbeCursor *pCsr,         /* Cursor object (for pKeyInfo) */
+  VdbeSorter *pSorter,            /* The sorter */
   int bOmitRowid,                 /* Ignore rowid field at end of keys */
   const void *pKey1, int nKey1,   /* Left side of comparison */
   const void *pKey2, int nKey2,   /* Right side of comparison */
   int *pRes,                      /* OUT: Result of comparison */
   UnpackedRecord *r2              /* Space to hold the unpacked Key2 record */
 ){
-  KeyInfo *pKeyInfo = pCsr->pKeyInfo;
+  KeyInfo *pKeyInfo = pSorter->pKeyInfo;
   int i;
 
   if( pKey2 ){
@@ -419,8 +422,7 @@ static void vdbeSorterCompare(
 ** multiple b-tree segments. Parameter iOut is the index of the aTree[] 
 ** value to recalculate.
 */
-static int vdbeSorterDoCompare(const VdbeCursor *pCsr, int iOut){
-  VdbeSorter *pSorter = pCsr->pSorter;
+static int vdbeSorterDoCompare(VdbeSorter *pSorter, int iOut){
   int i1;
   int i2;
   int iRes;
@@ -447,7 +449,7 @@ static int vdbeSorterDoCompare(const VdbeCursor *pCsr, int iOut){
   }else{
     int res;
     vdbeSorterCompare(
-        pCsr, 0, p1->aKey, p1->nKey, p2->aKey, p2->nKey, &res, 
+        pSorter, 0, p1->aKey, p1->nKey, p2->aKey, p2->nKey, &res,
         pSorter->pUnpacked
     );
     if( res<=0 ){
@@ -469,17 +471,32 @@ int sqlite3VdbeSorterInit(sqlite3 *db, VdbeCursor *pCsr){
   int mxCache;                    /* Cache size */
   VdbeSorter *pSorter;            /* The new sorter */
   char *d;                        /* Dummy */
+  int nByte;                      /* Bytes in pKeyInfo */
 
   assert( pCsr->pKeyInfo && pCsr->pBt==0 );
   pCsr->pSorter = pSorter = sqlite3DbMallocZero(db, sizeof(VdbeSorter));
   if( pSorter==0 ){
     return SQLITE_NOMEM;
   }
+  pSorter->db = db;
   
   pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pCsr->pKeyInfo, 0, 0, &d);
   if( pSorter->pUnpacked==0 ) return SQLITE_NOMEM;
   assert( pSorter->pUnpacked==(UnpackedRecord *)d );
 
+  /* pSorter->pKeyInfo is a copy of pCsr->pKeyInfo with the db field set to
+  ** zero.  We use this modified pKeyInfo for sorting so that no lookaside
+  ** memory will be used, so that sorting can proceed in parallel in multiple
+  ** threads.
+  */
+  nByte = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField - 1)*sizeof(CollSeq*);
+  pSorter->pKeyInfo = sqlite3DbMallocRaw(db, nByte);
+  if( pSorter->pKeyInfo==0 ){
+    return SQLITE_NOMEM;
+  }
+  memcpy(pSorter->pKeyInfo, pCsr->pKeyInfo, nByte);
+  pSorter->pKeyInfo->db = 0;  
+
   if( !sqlite3TempInMemory(db) ){
     pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
     pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz;
@@ -506,9 +523,10 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){
 /*
 ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
 */
-void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
+void sqlite3VdbeSorterClose(VdbeCursor *pCsr){
   VdbeSorter *pSorter = pCsr->pSorter;
   if( pSorter ){
+    sqlite3 *db = pSorter->db;
     if( pSorter->aIter ){
       int i;
       for(i=0; i<pSorter->nTree; i++){
@@ -521,6 +539,7 @@ void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
     }
     vdbeSorterRecordFree(db, pSorter->pRecord);
     sqlite3DbFree(db, pSorter->pUnpacked);
+    sqlite3DbFree(db, pSorter->pKeyInfo);
     sqlite3DbFree(db, pSorter);
     pCsr->pSorter = 0;
   }
@@ -545,7 +564,7 @@ static int vdbeSorterOpenTempFile(sqlite3 *db, sqlite3_file **ppFile){
 ** Set *ppOut to the head of the new list.
 */
 static void vdbeSorterMerge(
-  const VdbeCursor *pCsr,         /* For pKeyInfo */
+  VdbeSorter *pSorter,            /* The sorter object */
   SorterRecord *p1,               /* First list to merge */
   SorterRecord *p2,               /* Second list to merge */
   SorterRecord **ppOut,           /* OUT: Head of merged list */
@@ -557,7 +576,7 @@ static void vdbeSorterMerge(
 
   while( p1 && p2 ){
     int res;
-    vdbeSorterCompare(pCsr, 0, p1->pVal, p1->nVal, pVal2, p2->nVal, &res,
+    vdbeSorterCompare(pSorter, 0, p1->pVal, p1->nVal, pVal2, p2->nVal, &res,
                       pUnpacked);
     if( res<=0 ){
       *pp = p1;
@@ -580,9 +599,9 @@ static void vdbeSorterMerge(
 ** Background sorting task
 */
 typedef struct SortTask {
-  SorterRecord *pList;          /* List of elements to be sorted */
-  const VdbeCursor *pCsr;       /* Cursor.  Needed for pCur->pKeyInfo */
+  VdbeSorter *pSorter;          /* The sorter for which this task works */
   UnpackedRecord *pUnpacked;    /* Space to hold an unpacked key */
+  SorterRecord *pList;          /* List of elements to be sorted */
   SorterRecord **apSlot;        /* Temp memory for the merge sort */
 } SortTask;
 
@@ -599,7 +618,7 @@ void *vdbeSorterBackgroundSort(SortTask *pTask){
     p->pNext = 0;
     for(i=0; a[i]; i++){
       if( a[i]==0 ) break;
-      vdbeSorterMerge(pTask->pCsr, a[i], p, &p, pTask->pUnpacked);
+      vdbeSorterMerge(pTask->pSorter, a[i], p, &p, pTask->pUnpacked);
       a[i] = 0;
     }
     a[i] = p;
@@ -607,7 +626,7 @@ void *vdbeSorterBackgroundSort(SortTask *pTask){
   }
   p = 0;
   for(i=0; i<64; i++){
-    vdbeSorterMerge(pTask->pCsr, a[i], p, &p, pTask->pUnpacked);
+    vdbeSorterMerge(pTask->pSorter, a[i], p, &p, pTask->pUnpacked);
   }
   pTask->pList = p;
   return p;
@@ -644,10 +663,8 @@ static void vdbeSorterDivideList(
 ** if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if an error
 ** occurs.
 */
-static int vdbeSorterSort(const VdbeCursor *pCsr){
+static int vdbeSorterSort(VdbeSorter *pSorter){
   int rc;
-  SorterRecord *p;
-  VdbeSorter *pSorter = pCsr->pSorter;
   char *pDummy = 0;
   int nByteA, nByteB;
   SortTask aTask[2];
@@ -655,19 +672,19 @@ static int vdbeSorterSort(const VdbeCursor *pCsr){
 
   nByteA = 64*sizeof(SorterRecord*);
   nByteB = ROUND8(sizeof(UnpackedRecord));
-  nByteB += sizeof(Mem)*(pCsr->pKeyInfo->nField+1);
+  nByteB += sizeof(Mem)*(pSorter->pKeyInfo->nField+1);
 
   aTask[0].apSlot = (SorterRecord **)sqlite3MallocZero(2*(nByteA + nByteB));
   if( !aTask[0].apSlot ){
     return SQLITE_NOMEM;
   }
-  aTask[0].pCsr = pCsr;
-  aTask[0].pUnpacked = sqlite3VdbeAllocUnpackedRecord(pCsr->pKeyInfo,
+  aTask[0].pSorter = pSorter;
+  aTask[0].pUnpacked = sqlite3VdbeAllocUnpackedRecord(pSorter->pKeyInfo,
                           (char*)&aTask[0].apSlot[64], nByteB, &pDummy);
   assert( pDummy==0 );
-  aTask[1].apSlot = (nByteA+nByteB)+(char*)aTask[0].apSlot;
-  aTask[1].pCsr = pCsr;
-  aTask[1].pUnpacked = sqlite3VdbeAllocUnpackedRecord(pCsr->pKeyInfo,
+  aTask[1].apSlot = (SorterRecord**)((nByteA+nByteB)+(char*)aTask[0].apSlot);
+  aTask[1].pSorter = pSorter;
+  aTask[1].pUnpacked = sqlite3VdbeAllocUnpackedRecord(pSorter->pKeyInfo,
                           (char*)&aTask[1].apSlot[64], nByteB, &pDummy);
   assert( pDummy==0 );
 
@@ -678,10 +695,10 @@ static int vdbeSorterSort(const VdbeCursor *pCsr){
   if( rc==SQLITE_NOMEM ){
     vdbeSorterBackgroundSort(&aTask[0]);
   }else{
-    rc = sqlite3ThreadJoin(pThread, &pDummy);
+    rc = sqlite3ThreadJoin(pThread, (void**)&pDummy);
   }
-  vdbeSorterMerge(pCsr, aTask[0].pList, aTask[1].pList, &pSorter->pRecord,
-                  aTask[0].pUnpacked);
+  vdbeSorterMerge(pSorter, aTask[0].pList, aTask[1].pList, &pSorter->pRecord,
+                  pSorter->pUnpacked);
   sqlite3_free(aTask[0].apSlot);
   return rc;
 }
@@ -785,10 +802,10 @@ static void fileWriterWriteVarint(FileWriter *p, u64 iVal){
 **       Each record consists of a varint followed by a blob of data (the 
 **       key). The varint is the number of bytes in the blob of data.
 */
-static int vdbeSorterListToPMA(sqlite3 *db, const VdbeCursor *pCsr){
+static int vdbeSorterListToPMA(VdbeSorter *pSorter){
   int rc = SQLITE_OK;             /* Return code */
-  VdbeSorter *pSorter = pCsr->pSorter;
   FileWriter writer;
+  sqlite3 *db = pSorter->db;
 
   memset(&writer, 0, sizeof(FileWriter));
 
@@ -798,7 +815,7 @@ static int vdbeSorterListToPMA(sqlite3 *db, const VdbeCursor *pCsr){
     return rc;
   }
 
-  rc = vdbeSorterSort(pCsr);
+  rc = vdbeSorterSort(pSorter);
 
   /* If the first temporary PMA file has not been opened, open it now. */
   if( rc==SQLITE_OK && pSorter->pTemp1==0 ){
@@ -833,11 +850,11 @@ static int vdbeSorterListToPMA(sqlite3 *db, const VdbeCursor *pCsr){
 ** Add a record to the sorter.
 */
 int sqlite3VdbeSorterWrite(
-  sqlite3 *db,                    /* Database handle */
-  const VdbeCursor *pCsr,               /* Sorter cursor */
+  const VdbeCursor *pCsr,         /* Sorter cursor */
   Mem *pVal                       /* Memory cell containing record */
 ){
   VdbeSorter *pSorter = pCsr->pSorter;
+  sqlite3 *db = pSorter->db;
   int rc = SQLITE_OK;             /* Return Code */
   SorterRecord *pNew;             /* New list element */
 
@@ -874,7 +891,7 @@ int sqlite3VdbeSorterWrite(
                 + sqlite3VarintLen(pSorter->nInMemory)
                 + pSorter->nInMemory;
 #endif
-    rc = vdbeSorterListToPMA(db, pCsr);
+    rc = vdbeSorterListToPMA(pSorter);
     pSorter->nInMemory = 0;
     assert( rc!=SQLITE_OK || (nExpect==pSorter->iWriteOff) );
   }
@@ -886,11 +903,9 @@ int sqlite3VdbeSorterWrite(
 ** Helper function for sqlite3VdbeSorterRewind(). 
 */
 static int vdbeSorterInitMerge(
-  sqlite3 *db,                    /* Database handle */
-  const VdbeCursor *pCsr,         /* Cursor handle for this sorter */
+  VdbeSorter *pSorter,            /* The sorter */
   i64 *pnByte                     /* Sum of bytes in all opened PMAs */
 ){
-  VdbeSorter *pSorter = pCsr->pSorter;
   int rc = SQLITE_OK;             /* Return code */
   int i;                          /* Used to iterator through aIter[] */
   i64 nByte = 0;                  /* Total bytes in all opened PMAs */
@@ -898,7 +913,7 @@ static int vdbeSorterInitMerge(
   /* Initialize the iterators. */
   for(i=0; i<SORTER_MAX_MERGE_COUNT; i++){
     VdbeSorterIter *pIter = &pSorter->aIter[i];
-    rc = vdbeSorterIterInit(db, pSorter, pSorter->iReadOff, pIter, &nByte);
+    rc = vdbeSorterIterInit(pSorter, pSorter->iReadOff, pIter, &nByte);
     pSorter->iReadOff = pIter->iEof;
     assert( rc!=SQLITE_OK || pSorter->iReadOff<=pSorter->iWriteOff );
     if( rc!=SQLITE_OK || pSorter->iReadOff>=pSorter->iWriteOff ) break;
@@ -906,7 +921,7 @@ static int vdbeSorterInitMerge(
 
   /* Initialize the aTree[] array. */
   for(i=pSorter->nTree-1; rc==SQLITE_OK && i>0; i--){
-    rc = vdbeSorterDoCompare(pCsr, i);
+    rc = vdbeSorterDoCompare(pSorter, i);
   }
 
   *pnByte = nByte;
@@ -917,8 +932,9 @@ static int vdbeSorterInitMerge(
 ** Once the sorter has been populated, this function is called to prepare
 ** for iterating through its contents in sorted order.
 */
-int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
+int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
   VdbeSorter *pSorter = pCsr->pSorter;
+  sqlite3 *db = pSorter->db;
   int rc;                         /* Return code */
   sqlite3_file *pTemp2 = 0;       /* Second temp file to use */
   i64 iWrite2 = 0;                /* Write offset for pTemp2 */
@@ -934,11 +950,11 @@ int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
   if( pSorter->nPMA==0 ){
     *pbEof = !pSorter->pRecord;
     assert( pSorter->aTree==0 );
-    return vdbeSorterSort(pCsr);
+    return vdbeSorterSort(pSorter);
   }
 
   /* Write the current in-memory list to a PMA. */
-  rc = vdbeSorterListToPMA(db, pCsr);
+  rc = vdbeSorterListToPMA(pSorter);
   if( rc!=SQLITE_OK ) return rc;
 
   /* Allocate space for aIter[] and aTree[]. */
@@ -974,7 +990,7 @@ int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
       ** initialize interators for SORTER_MAX_MERGE_COUNT of them. These PMAs
       ** are merged into a single PMA that is written to file pTemp2.
       */
-      rc = vdbeSorterInitMerge(db, pCsr, &nWrite);
+      rc = vdbeSorterInitMerge(pSorter, &nWrite);
       assert( rc!=SQLITE_OK || pSorter->aIter[ pSorter->aTree[1] ].pFile );
       if( rc!=SQLITE_OK || pSorter->nPMA<=SORTER_MAX_MERGE_COUNT ){
         break;
@@ -996,7 +1012,7 @@ int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
 
           fileWriterWriteVarint(&writer, pIter->nKey);
           fileWriterWrite(&writer, pIter->aKey, pIter->nKey);
-          rc = sqlite3VdbeSorterNext(db, pCsr, &bEof);
+          rc = sqlite3VdbeSorterNext(pCsr, &bEof);
         }
         rc2 = fileWriterFinish(db, &writer, &iWrite2);
         if( rc==SQLITE_OK ) rc = rc2;
@@ -1026,17 +1042,18 @@ int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
 /*
 ** Advance to the next element in the sorter.
 */
-int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
+int sqlite3VdbeSorterNext(const VdbeCursor *pCsr, int *pbEof){
   VdbeSorter *pSorter = pCsr->pSorter;
+  sqlite3 *db = pSorter->db;
   int rc;                         /* Return code */
 
   if( pSorter->aTree ){
     int iPrev = pSorter->aTree[1];/* Index of iterator to advance */
     int i;                        /* Index of aTree[] to recalculate */
 
-    rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]);
+    rc = vdbeSorterIterNext(&pSorter->aIter[iPrev]);
     for(i=(pSorter->nTree+iPrev)/2; rc==SQLITE_OK && i>0; i=i/2){
-      rc = vdbeSorterDoCompare(pCsr, i);
+      rc = vdbeSorterDoCompare(pSorter, i);
     }
 
     *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0);
@@ -1110,7 +1127,7 @@ int sqlite3VdbeSorterCompare(
   void *pKey; int nKey;           /* Sorter key to compare pVal with */
 
   pKey = vdbeSorterRowkey(pSorter, &nKey);
-  vdbeSorterCompare(pCsr, 1, pVal->z, pVal->n, pKey, nKey, pRes,
+  vdbeSorterCompare(pSorter, 1, pVal->z, pVal->n, pKey, nKey, pRes,
                     pSorter->pUnpacked);
   return SQLITE_OK;
 }