]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix many problems with manifest types and column affinity. Most things are
authordanielk1977 <danielk1977@noemail.net>
Tue, 18 May 2004 09:58:06 +0000 (09:58 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Tue, 18 May 2004 09:58:06 +0000 (09:58 +0000)
working now. (CVS 1392)

FossilOrigin-Name: a62872aacd544a1465b06e007153168663f3c83a

manifest
manifest.uuid
src/build.c
src/delete.c
src/insert.c
src/pragma.c
src/select.c
src/update.c
src/vdbe.c
src/vdbeaux.c

index b470d8842aee8969cd6e3da73834445395817d6c..35ceb50b4024e95b1da651f1166ad9adb677fa74 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Bugfix\sfor\srow\sformat.\s(CVS\s1391)
-D 2004-05-18T01:31:14
+C Fix\smany\sproblems\swith\smanifest\stypes\sand\scolumn\saffinity.\sMost\sthings\sare\nworking\snow.\s(CVS\s1392)
+D 2004-05-18T09:58:07
 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -26,16 +26,16 @@ F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
 F src/btree.c bf8d9592b66fb9ba89a5be13fd99a7d8b8a67d7f
 F src/btree.h 6f51ad0ffebfba71295fcacdbe86007512200050
 F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5
-F src/build.c ddb0384afd2c82599b7d2bdefc4878850854931c
+F src/build.c 84a9b37700a18db370b9dbb77f1636df5cdf0290
 F src/copy.c 4d2038602fd0549d80c59bda27d96f13ea9b5e29
 F src/date.c 0eb0a89960bb45c7f7e768748605a7a97b0c8064
-F src/delete.c 8cb317fbba81b428301bccf04be1bea22203508b
+F src/delete.c a069dcc2ec0cc3487c8ababebc59a429b4556144
 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
 F src/expr.c d39afb30c76c2f67fb5ffdfe530ed709c5009786
 F src/func.c cfbb7096efb58e2857e3b312a8958a12774b625a
 F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
 F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
-F src/insert.c 72d9dd0b2543420a905ada68f098bc6754b8a1ea
+F src/insert.c 60cc57b8468749d7e023798b9d7f91eeb4cd279a
 F src/main.c 4b82d7e78f4c9799343b02740a5ba9768d5e464d
 F src/md5.c 8e39fdae6d8776b87558e91dcc94740c9b635a9c
 F src/os.c ddcda92f7fd71b4513c57c1ec797917f206d504e
@@ -43,10 +43,10 @@ F src/os.h fbb2f6595fc34fa351830d88fe1c6b85118f0383
 F src/pager.c 6ff6b906427d4824099140776cb8768f922f3dc5
 F src/pager.h 78a00ac280899bcba1a89dc51585dcae6b7b3253
 F src/parse.y d0258aa3cc8b0c5742b07b699d10fa98f3caea7d
-F src/pragma.c 2c65f46a520cd3bab49623d68bec0a5afaae5b52
+F src/pragma.c fcbd8bc7f2cc1429758a042920e13c8738a6050c
 F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53
 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
-F src/select.c 62431fb1a1021301e35f12f64c325d5f20371393
+F src/select.c f376f3beade0e1e4808b3a393c13f5b30baecf74
 F src/shell.c 0c4662e13bfbfd3d13b066c5859cc97ad2f95d21
 F src/sqlite.h.in 799c5e726296ec7bc20e6407cdf4df0e0bc00c0c
 F src/sqliteInt.h ac5fe07df6cf0a4c935e5a88bc14bc620e4f1591
@@ -59,14 +59,14 @@ F src/test4.c b3fab9aea7a8940a8a7386ce1c7e2157b09bd296
 F src/test5.c eb39aac8fed61bd930b92613cd705c145244074a
 F src/tokenize.c e7536dd31205d5afb76c1bdc832dea009c7a3847
 F src/trigger.c 8df308e09113410bb895e88a2db65b55490268db
-F src/update.c d14a0b0f3b35ea2469dda375e59a1064f02c7c0e
+F src/update.c 0cc7291dd0e0f82cf93085e49c973e8ef9e51fd5
 F src/utf.c fc799748d43fe1982d157b871e3e420a19c85d4f
 F src/util.c f9511ffba78e6cf71a28774c2820d7750b5bacdf
 F src/vacuum.c c134702e023db8778e6be59ac0ea7b02315b5476
-F src/vdbe.c 8a6b971c130227fc90a6e899afe218277aa29fdd
+F src/vdbe.c 5cc6e41f2c9f24bbbf591ca538c097c0f7b41a3d
 F src/vdbe.h 94457ca73bae972dc61bca33a4dccc2e6e14e2f8
 F src/vdbeInt.h 311c2a046ea419781d0ef331198b7b0a65eebc92
-F src/vdbeaux.c 618861394df84d475e574e22b95e6ed1c9453b1d
+F src/vdbeaux.c 760105ceedb7bcfcd3f4dbba7a5500321612669b
 F src/where.c 5f480219a943b0fed1f6922d2fdbfba8616a9148
 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
 F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83
@@ -192,7 +192,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P 202a470f2c1804a96e69f16709d1a92e405971f0
-R ffc409e8b16e570dc32c405b3b469d03
+P c1745f47ae6597953426c852559c3ba559b5ecd4
+R 02c7a45ac0cf509a83f0308e5e2e8fde
 U danielk1977
-Z 5eff88f75ed7e1dd3ba47379b0123d5b
+Z 6d5d78b2c759d8987f601a926f92d5bb
index 02e88e32a76fd722d89cc7d2161b3d7281f5087b..fcc051209394e00d0f5739a3dacb800c1cb44110 100644 (file)
@@ -1 +1 @@
-c1745f47ae6597953426c852559c3ba559b5ecd4
\ No newline at end of file
+a62872aacd544a1465b06e007153168663f3c83a
\ No newline at end of file
index d26ad6a55d4cb3b2dbdb2f5365b6946f08f7b6de..a1cd608b5c8f6f20c09a2fa30931d0764064f8b0 100644 (file)
@@ -23,7 +23,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.186 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: build.c,v 1.187 2004/05/18 09:58:07 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -790,7 +790,7 @@ char sqlite3AffinityType(const char *zType, int nType){
 
   for(n=0; n<(nType-2); n++){
     for(i=0; i<sizeof(substrings)/sizeof(substrings[0]); i++){
-      if( 0==sqlite3StrNICmp(zType, substrings[i].zSub, substrings[i].nSub) ){
+      if( 0==sqlite3StrNICmp(&zType[n], substrings[i].zSub, substrings[i].nSub) ){
         return substrings[i].affinity;
       }
     }
@@ -992,7 +992,7 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){
       n = Addr(pEnd->z) - Addr(pParse->sFirstToken.z) + 1;
       sqlite3VdbeChangeP3(v, -1, pParse->sFirstToken.z, n);
     }
-    sqlite3VdbeAddOp(v, OP_MakeRecord, 5, 0);
+    sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
     sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
     if( !p->iDb ){
       sqlite3ChangeCookie(db, v);
@@ -1002,7 +1002,7 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){
       sqlite3VdbeAddOp(v, OP_Integer, p->iDb, 0);
       sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0);
       pParse->nTab = 2;
-      sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0);
+      sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0);
     }
     sqlite3EndWriteOperation(pParse);
   }
@@ -1720,7 +1720,7 @@ void sqlite3CreateIndex(
       n = Addr(pEnd->z) - Addr(pStart->z) + 1;
       sqlite3VdbeChangeP3(v, addr, pStart->z, n);
     }
-    sqlite3VdbeAddOp(v, OP_MakeRecord, 5, 0);
+    sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
     sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
     if( pTable ){
       sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
index 66497002f14106d27537e6bee346fef7f3a05bdb..df1a0485d57eeb55179e26e4f218a602e4d97458 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle DELETE FROM statements.
 **
-** $Id: delete.c,v 1.66 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: delete.c,v 1.67 2004/05/18 09:58:07 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -149,7 +149,7 @@ void sqlite3DeleteFrom(
   */
   if( isView ){
     Select *pView = sqlite3SelectDup(pTab->pSelect);
-    sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
+    sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
     sqlite3SelectDelete(pView);
   }
 
@@ -213,6 +213,7 @@ void sqlite3DeleteFrom(
     */
     if( row_triggers_exist ){
       sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
+      sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
     }
 
     /* Delete every item whose key was written to the list during the
index f572bb8939bd607f4f4ad1b1c7c96c77690c9fac..12ed4a4d5347ff3c485f879700d11d6da929e216 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.101 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: insert.c,v 1.102 2004/05/18 09:58:07 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -260,7 +260,7 @@ void sqlite3Insert(
     iInitCode = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
     iSelectLoop = sqlite3VdbeCurrentAddr(v);
     iInsertBlock = sqlite3VdbeMakeLabel(v);
-    rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0);
+    rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0,0);
     if( rc || pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
     iCleanup = sqlite3VdbeMakeLabel(v);
     sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup);
@@ -278,7 +278,7 @@ void sqlite3Insert(
     if( row_triggers_exist ){
       useTempTable = 1;
     }else{
-      int addr = sqlite3VdbeFindOp(v, OP_OpenRead, pTab->tnum);
+      int addr = sqlite3VdbeFindOp(v, 0, OP_OpenRead, pTab->tnum);
       useTempTable = 0;
       if( addr>0 ){
         VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-2);
@@ -398,6 +398,7 @@ void sqlite3Insert(
   */
   if( row_triggers_exist ){
     sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
+    sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
   }
     
   /* Initialize the count of rows to be inserted
index b0be50a254149c16079ca0064ecd8eae4cdaf52a..aafa1451daf7d23d4f97e6b701c105800d658f38 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to implement the PRAGMA command.
 **
-** $Id: pragma.c,v 1.24 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: pragma.c,v 1.25 2004/05/18 09:58:08 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -622,11 +622,11 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
       */
       addr = sqlite3VdbeAddOpList(v, ArraySize(checkDb), checkDb);
       sqlite3VdbeChangeP1(v, addr+1, i);
-      sqlite3VdbeChangeP2(v, addr+3, addr+7);
-      sqlite3VdbeChangeP2(v, addr+6, addr+4);
-      sqlite3VdbeChangeP2(v, addr+7, i);
-      sqlite3VdbeChangeP2(v, addr+10, addr+ArraySize(checkDb));
-      sqlite3VdbeChangeP3(v, addr+13, db->aDb[i].zName, P3_STATIC);
+      sqlite3VdbeChangeP2(v, addr+4, addr+8);
+      sqlite3VdbeChangeP2(v, addr+7, addr+5);
+      sqlite3VdbeChangeP2(v, addr+8, i);
+      sqlite3VdbeChangeP2(v, addr+11, addr+ArraySize(checkDb));
+      sqlite3VdbeChangeP3(v, addr+14, db->aDb[i].zName, P3_STATIC);
 
       /* Make sure all the indices are constructed correctly.
       */
index ac715fa0b61af12eae3d83c742ce1e4f3523eda1..a27e7aa240ae6ac6d8e64759ea3e94beb5714436 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.166 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: select.c,v 1.167 2004/05/18 09:58:08 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -382,7 +382,8 @@ static int selectInnerLoop(
   int eDest,              /* How to dispose of the results */
   int iParm,              /* An argument to the disposal method */
   int iContinue,          /* Jump here to continue with next row */
-  int iBreak              /* Jump here to break out of the inner loop */
+  int iBreak,             /* Jump here to break out of the inner loop */
+  char *aff               /* affinity string if eDest is SRT_Union */
 ){
   Vdbe *v = pParse->pVdbe;
   int i;
@@ -440,6 +441,7 @@ static int selectInnerLoop(
     */
     case SRT_Union: {
       sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT);
+      sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
       sqlite3VdbeAddOp(v, OP_String, 0, 0);
       sqlite3VdbeAddOp(v, OP_PutStrKey, iParm, 0);
       break;
@@ -467,6 +469,7 @@ static int selectInnerLoop(
     case SRT_Except: {
       int addr;
       addr = sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT);
+      sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
       sqlite3VdbeAddOp(v, OP_NotFound, iParm, addr+3);
       sqlite3VdbeAddOp(v, OP_Delete, iParm, 0);
       break;
@@ -491,7 +494,7 @@ static int selectInnerLoop(
         char aff = (iParm>>16)&0xFF;
         aff = sqlite3CompareAffinity(pEList->a[0].pExpr, aff);
         affStr = sqlite3AffinityString(aff);
-        sqlite3VdbeOp3(v, OP_MakeKey, 1, 1, affStr, P3_STATIC);
+        sqlite3VdbeOp3(v, OP_MakeKey, 1, 0, affStr, P3_STATIC);
         sqlite3VdbeAddOp(v, OP_String, 0, 0);
         sqlite3VdbeAddOp(v, OP_PutStrKey, (iParm&0x0000FFFF), 0);
       }
@@ -612,11 +615,13 @@ static void generateSortTail(
     }
     case SRT_Subroutine: {
       int i;
+      sqlite3VdbeAddOp(v, OP_Integer, p->pEList->nExpr, 0);
+      sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
       for(i=0; i<nColumn; i++){
         sqlite3VdbeAddOp(v, OP_Column, -1-i, i);
       }
       sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
-      sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
+      sqlite3VdbeAddOp(v, OP_Pop, 2, 0);
       break;
     }
     default: {
@@ -1208,6 +1213,19 @@ static void multiSelectSortOrder(Select *p, ExprList *pOrderBy){
   }
 }
 
+static void multiSelectAffinity(Select *p, char *zAff){
+  int i;
+
+  if( !p ) return;
+  multiSelectAffinity(p->pPrior, zAff);
+
+  for(i=0; i<p->pEList->nExpr; i++){
+    if( zAff[i]=='\0' ){
+      zAff[i] = sqlite3ExprAffinity(p->pEList->a[i].pExpr);
+    }
+  }
+}
+
 /*
 ** Compute the iLimit and iOffset fields of the SELECT based on the
 ** nLimit and nOffset fields.  nLimit and nOffset hold the integers
@@ -1284,31 +1302,62 @@ static void computeLimitRegisters(Parse *pParse, Select *p){
 ** Notice that because of the way SQLite parses compound SELECTs, the
 ** individual selects always group from left to right.
 */
-static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
-  int rc;             /* Success code from a subroutine */
+static int multiSelect(
+  Parse *pParse, 
+  Select *p, 
+  int eDest, 
+  int iParm, 
+  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 */
+  char *affStr = 0;
+
+  if( !aff ){
+    int len;
+    rc = fillInColumnList(pParse, p);
+    if( rc!=SQLITE_OK ){
+      goto multi_select_end;
+    }
+    len = p->pEList->nExpr+1;
+    affStr = (char *)sqliteMalloc(p->pEList->nExpr+1);
+    if( !affStr ){
+      rc = SQLITE_NOMEM;
+      goto multi_select_end;
+    }
+    memset(affStr, (int)SQLITE_AFF_NUMERIC, len-1);
+    aff = affStr;
+  }
 
   /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs.  Only
   ** the last SELECT in the series may have an ORDER BY or LIMIT.
   */
-  if( p==0 || p->pPrior==0 ) return 1;
+  if( p==0 || p->pPrior==0 ){
+    rc = 1;
+    goto multi_select_end;
+  }
   pPrior = p->pPrior;
   if( pPrior->pOrderBy ){
     sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
       selectOpName(p->op));
-    return 1;
+    rc = 1;
+    goto multi_select_end;
   }
   if( pPrior->nLimit>=0 || pPrior->nOffset>0 ){
     sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before",
       selectOpName(p->op));
-    return 1;
+    rc = 1;
+    goto multi_select_end;
   }
 
   /* Make sure we have a valid query engine.  If not, create a new one.
   */
   v = sqlite3GetVdbe(pParse);
-  if( v==0 ) return 1;
+  if( v==0 ){
+    rc = 1;
+    goto multi_select_end;
+  }
 
   /* Create the destination temporary table if necessary
   */
@@ -1326,16 +1375,20 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
       if( p->pOrderBy==0 ){
         pPrior->nLimit = p->nLimit;
         pPrior->nOffset = p->nOffset;
-        rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0);
-        if( rc ) return rc;
+        rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff);
+        if( rc ){
+          goto multi_select_end;
+        }
         p->pPrior = 0;
         p->iLimit = pPrior->iLimit;
         p->iOffset = pPrior->iOffset;
         p->nLimit = -1;
         p->nOffset = 0;
-        rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0);
+        rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff);
         p->pPrior = pPrior;
-        if( rc ) return rc;
+        if( rc ){
+          goto multi_select_end;
+        }
         break;
       }
       /* For UNION ALL ... ORDER BY fall through to the next case */
@@ -1361,7 +1414,8 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
         unionTab = pParse->nTab++;
         if( p->pOrderBy 
         && matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){
-          return 1;
+          rc = 1;
+          goto multi_select_end;
         }
         if( p->op!=TK_ALL ){
           sqlite3VdbeAddOp(v, OP_OpenTemp, unionTab, 1);
@@ -1369,12 +1423,18 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
         }else{
           sqlite3VdbeAddOp(v, OP_OpenTemp, unionTab, 0);
         }
+        assert( p->pEList );
       }
 
       /* Code the SELECT statements to our left
       */
-      rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0);
-      if( rc ) return rc;
+      rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff);
+      if( rc ){
+        goto multi_select_end;
+      }
+      if( p->op==TK_ALL ){
+        sqlite3VdbeAddOp(v, OP_SetNumColumns, unionTab, pPrior->pEList->nExpr);
+      }
 
       /* Code the current SELECT statement
       */
@@ -1390,12 +1450,15 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
       p->nLimit = -1;
       nOffset = p->nOffset;
       p->nOffset = 0;
-      rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0);
+      rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff);
       p->pPrior = pPrior;
       p->pOrderBy = pOrderBy;
       p->nLimit = nLimit;
       p->nOffset = nOffset;
-      if( rc ) return rc;
+      if( rc ){
+        goto multi_select_end;
+      }
+
 
       /* Convert the data in the temporary table into whatever form
       ** it is that we currently need.
@@ -1415,8 +1478,11 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
         multiSelectSortOrder(p, p->pOrderBy);
         rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
                              p->pOrderBy, -1, eDest, iParm, 
-                             iCont, iBreak);
-        if( rc ) return 1;
+                             iCont, iBreak, 0);
+        if( rc ){
+          rc = 1;
+          goto multi_select_end;
+        }
         sqlite3VdbeResolveLabel(v, iCont);
         sqlite3VdbeAddOp(v, OP_Next, unionTab, iStart);
         sqlite3VdbeResolveLabel(v, iBreak);
@@ -1439,15 +1505,19 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
       tab1 = pParse->nTab++;
       tab2 = pParse->nTab++;
       if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){
-        return 1;
+        rc = 1;
+        goto multi_select_end;
       }
       sqlite3VdbeAddOp(v, OP_OpenTemp, tab1, 1);
       sqlite3VdbeAddOp(v, OP_KeyAsData, tab1, 1);
+      assert( p->pEList );
 
       /* Code the SELECTs to our left into temporary table "tab1".
       */
-      rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0);
-      if( rc ) return rc;
+      rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff);
+      if( rc ){
+        goto multi_select_end;
+      }
 
       /* Code the current SELECT into temporary table "tab2"
       */
@@ -1458,11 +1528,13 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
       p->nLimit = -1;
       nOffset = p->nOffset;
       p->nOffset = 0;
-      rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0);
+      rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff);
       p->pPrior = pPrior;
       p->nLimit = nLimit;
       p->nOffset = nOffset;
-      if( rc ) return rc;
+      if( rc ){
+        goto multi_select_end;
+      }
 
       /* Generate code to take the intersection of the two temporary
       ** tables.
@@ -1481,8 +1553,11 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
       multiSelectSortOrder(p, p->pOrderBy);
       rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
                              p->pOrderBy, -1, eDest, iParm, 
-                             iCont, iBreak);
-      if( rc ) return 1;
+                             iCont, iBreak, 0);
+      if( rc ){
+        rc = 1;
+        goto multi_select_end;
+      }
       sqlite3VdbeResolveLabel(v, iCont);
       sqlite3VdbeAddOp(v, OP_Next, tab1, iStart);
       sqlite3VdbeResolveLabel(v, iBreak);
@@ -1498,9 +1573,20 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
   if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
     sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
       " do not have the same number of result columns", selectOpName(p->op));
-    return 1;
+    rc = 1;
+    goto multi_select_end;
   }
-  return 0;
+
+multi_select_end:
+  if( affStr ){
+    if( rc!=SQLITE_OK ){
+      sqliteFree(affStr);
+    }else{
+      multiSelectAffinity(p, affStr);
+      sqlite3VdbeOp3(v, OP_Noop, 0, 0, affStr, P3_DYNAMIC);
+    }
+  }
+  return rc;
 }
 
 /*
@@ -1937,7 +2023,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
   memset(&eListItem, 0, sizeof(eListItem));
   eList.a = &eListItem;
   eList.a[0].pExpr = pExpr;
-  selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont);
+  selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont, 0);
   sqlite3VdbeResolveLabel(v, cont);
   sqlite3VdbeAddOp(v, OP_Close, base, 0);
   
@@ -2003,7 +2089,8 @@ int sqlite3Select(
   int iParm,             /* A parameter used by the eDest disposal method */
   Select *pParent,       /* Another SELECT for which this is a sub-query */
   int parentTab,         /* Index in pParent->pSrc of this query */
-  int *pParentAgg        /* True if pParent uses aggregate functions */
+  int *pParentAgg,       /* True if pParent uses aggregate functions */
+  char *aff              /* If eDest is SRT_Union, the affinity string */
 ){
   int i;
   WhereInfo *pWInfo;
@@ -2025,7 +2112,7 @@ int sqlite3Select(
   /* If there is are a sequence of queries, do the earlier ones first.
   */
   if( p->pPrior ){
-    return multiSelect(pParse, p, eDest, iParm);
+    return multiSelect(pParse, p, eDest, iParm, aff);
   }
 
   /* Make local copies of the parameters for this query.
@@ -2181,6 +2268,21 @@ int sqlite3Select(
     generateColumnNames(pParse, pTabList, pEList);
   }
 
+  /* If the destination is SRT_Union, then set the number of columns in
+  ** the records that will be inserted into the temporary table. The caller
+  ** couldn't do this, in case the select statement is of the form 
+  ** "SELECT * FROM ....". 
+  **
+  ** We need to do this before we start inserting records into the 
+  ** temporary table (which has had OP_KeyAsData executed on it), because
+  ** it is required by the key comparison function. So do it now, even
+  ** though this means that OP_SetNumColumns may be executed on the same
+  ** cursor more than once.
+  */
+  if( eDest==SRT_Union ){
+    sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, pEList->nExpr);
+  }
+
   /* Generate code for all sub-queries in the FROM clause
   */
   for(i=0; i<pTabList->nSrc; i++){
@@ -2196,7 +2298,7 @@ int sqlite3Select(
       needRestoreContext = 0;
     }
     sqlite3Select(pParse, pTabList->a[i].pSelect, SRT_TempTable, 
-                 pTabList->a[i].iCursor, p, i, &isAgg);
+                 pTabList->a[i].iCursor, p, i, &isAgg, 0);
     if( needRestoreContext ){
       pParse->zAuthContext = zSavedAuthContext;
     }
@@ -2324,7 +2426,7 @@ int sqlite3Select(
   */
   if( !isAgg ){
     if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
-                    iParm, pWInfo->iContinue, pWInfo->iBreak) ){
+                    iParm, pWInfo->iContinue, pWInfo->iBreak, aff) ){
        goto select_end;
     }
   }
@@ -2383,7 +2485,7 @@ int sqlite3Select(
       sqlite3ExprIfFalse(pParse, pHaving, startagg, 1);
     }
     if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
-                    iParm, startagg, endagg) ){
+                    iParm, startagg, endagg, aff) ){
       goto select_end;
     }
     sqlite3VdbeAddOp(v, OP_Goto, 0, startagg);
index d234f5e350ccc04fbcede3ebedc11d2539c1bd9b..71c6c6f840bd8183b1b05cb5ad6b6ebc5aa825c1 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.75 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: update.c,v 1.76 2004/05/18 09:58:08 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -216,7 +216,7 @@ void sqlite3Update(
   if( isView ){
     Select *pView;
     pView = sqlite3SelectDup(pTab->pSelect);
-    sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
+    sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
     sqlite3SelectDelete(pView);
   }
 
@@ -243,7 +243,9 @@ void sqlite3Update(
     /* Create pseudo-tables for NEW and OLD
     */
     sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
+    sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
     sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
+    sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
 
     /* The top of the update loop for when there are triggers.
     */
index 52b8c8ac543bb50c146187181b0321ab492095c6..f09d3b9b2ab0950bb57927534bdfadd7e6231fc8 100644 (file)
@@ -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.297 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: vdbe.c,v 1.298 2004/05/18 09:58:08 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -485,6 +485,57 @@ static void applyAffinity(Mem *pRec, char affinity){
   }
 }
 
+static int getBtreeMem(
+  BtCursor *pCur,   /* Cursor pointing at record to retrieve. */
+  int offset,       /* Offset from the start of data to return bytes from. */
+  int amt,          /* Number of bytes to return. */
+  int key,          /* If true, retrieve from the btree key, not data. */
+  Mem *pMem         /* OUT: Return data in this Mem structure. */
+){
+  char *zData;
+
+  if( key ){
+    zData = (char *)sqlite3BtreeKeyFetch(pCur, offset+amt);
+  }else{
+    zData = (char *)sqlite3BtreeDataFetch(pCur, offset+amt);
+  }
+
+  if( zData ){
+    pMem->z = &zData[offset];
+    pMem->n = amt;
+    pMem->flags = MEM_Blob|MEM_Ephem;
+  }else{
+    int rc;
+    if( amt>NBFS ){
+      zData = (char *)sqliteMallocRaw(amt);
+      if( !zData ){
+        return SQLITE_NOMEM;
+      }
+      pMem->flags = MEM_Blob|MEM_Dyn;
+    }else{
+      zData = &(pMem->zShort[0]);
+      pMem->flags = MEM_Blob|MEM_Short;
+    }
+    pMem->z = zData;
+
+    if( key ){
+      rc = sqlite3BtreeKey(pCur, offset, amt, zData);
+    }else{
+      rc = sqlite3BtreeData(pCur, offset, amt, zData);
+    }
+
+    if( rc!=SQLITE_OK ){
+      if( amt>NBFS ){
+        sqliteFree(zData);
+      }
+      return rc;
+    }
+  }
+
+  return SQLITE_OK;
+}
+
+
 #ifdef VDBE_PROFILE
 /*
 ** The following routine only works on pentium-class processors.
@@ -2019,7 +2070,8 @@ case OP_SetNumColumns: {
 ** a table.  For P1==-1, the top of the stack is used.  For P1==-2, the
 ** next on the stack is used.  And so forth.  The value pushed is always
 ** just a pointer into the record which is stored further down on the
-** stack.  The column value is not copied.
+** stack.  The column value is not copied. The number of columns in the
+** record is stored on the stack just above the record itself.
 */
 case OP_Column: {
   int payloadSize;   /* Number of bytes in the record */
@@ -2029,30 +2081,61 @@ case OP_Column: {
   char *zRec;        /* Pointer to record-data from stack or pseudo-table. */
   BtCursor *pCrsr;
 
-  char *zData;       
-  int freeZdata = 0; /* zData requires sqliteFree() */
-
   u64 nField;        /* number of fields in the record */
-
   int len;           /* The length of the serialized data for the column */
   int offset = 0;
   int nn;
 
+  char *zData;       
+  Mem zMem;
+  zMem.flags = 0;
+
   assert( i<p->nCursor );
   pTos++;
 
-  /* This block sets the variable payloadSize, and if the data is coming
-  ** from the stack or from a pseudo-table zRec. If the data is coming
-  ** from a real cursor, then zRec is left as NULL.
+  /* If the record is coming from the stack, not from a cursor, then there
+  ** is nowhere to cache the record header infomation. This simplifies
+  ** things greatly, so deal with this case seperately.
   */
   if( i<0 ){
-    assert( &pTos[i]>=p->aStack );
+    char *zRec;     /* Pointer to record data from the stack. */
+    int off = 0;    /* Offset in zRec to start of the columns data. */
+    int off2 = 0;   /* Offset in zRec to the next serial type to read */
+    u64 colType;    /* The serial type of the value being read. */
+
+    assert( &pTos[i-1]>=p->aStack );
     assert( pTos[i].flags & MEM_Str );
+    assert( pTos[i-1].flags & MEM_Int );
+
+    if( pTos[i].n==0 ){
+      pTos->flags = MEM_Null;
+      break;
+    }
+
     zRec = pTos[i].z;
-    payloadSize = pTos[i].n;
-    pC->cacheValid = 0;
-    assert(!"broken for now");
-  }else if( (pC = p->apCsr[i])->pCursor!=0 ){
+    nField = pTos[i-1].i;
+     
+    for( nn=0; nn<nField; nn++ ){
+      u64 v;
+      off2 += sqlite3GetVarint(&zRec[off2], &v);
+      if( nn==p2 ){
+        colType = v;
+      }else if( nn<p2 ){
+        off += sqlite3VdbeSerialTypeLen(v);
+      }
+    }
+    off += off2;
+    
+    sqlite3VdbeSerialGet(&zRec[off], colType, pTos);
+    break;
+  }
+
+
+  /* This block sets the variable payloadSize, and if the data is coming
+  ** from the stack or from a pseudo-table zRec. If the data is coming
+  ** from a real cursor, then zRec is left as NULL.
+  */
+  if( (pC = p->apCsr[i])->pCursor!=0 ){
     sqlite3VdbeCursorMoveto(pC);
     zRec = 0;
     pCrsr = pC->pCursor;
@@ -2093,31 +2176,8 @@ case OP_Column: {
   /* Read and parse the table header.  Store the results of the parse
   ** into the record header cache fields of the cursor.
   */
-  if( !pC->cacheValid ){
+  if( !pC || !pC->cacheValid ){
     pC->payloadSize = payloadSize;
-#if 0
-    if( zRec ){
-      zData = zRec;
-    }else{
-      /* We can assume that 10 bytes (maximum length of a varint) fits
-      ** on the main page in all cases.
-      */
-      int n = 10;
-      if( payloadSize<10 ) n = payloadSize;
-      if( pC->keyAsData ){
-        zData = (char *)sqlite3BtreeKeyFetch(pCrsr, n);
-      }else{
-        zData = (char *)sqlite3BtreeDataFetch(pCrsr, n);
-      }
-      assert( zData );
-    }
-    {
-      u64 x;
-      offset = sqlite3GetVarint(zData, &x);
-      assert( x==nField );
-    }
-#endif
-
     if( !pC->aType ){
       pC->aType = sqliteMallocRaw( nField*sizeof(pC->aType[0]) );
       if( pC->aType==0 ){
@@ -2125,52 +2185,28 @@ case OP_Column: {
       }
     }
 
-    if( !zRec ){
-      /* If the record is stored in a table, see if enough of it is on
-      ** the main page to use sqlite3BtreeDataFetch() to get the data
-      ** containing the nField serial types (varints). This will almost
-      ** always work, but if it doesn't sqliteMalloc() space and use
-      ** sqlite3BtreeData().
-      **
-      ** Estimate the maximum space required by the nField varints by
+    if( zRec ){
+      zData = zRec;
+    }else{
+      /* Estimate the maximum space required by the nField varints by
       ** assuming the maximum space for each is the length required to store:
       **
       **     (<record length> * 2) + 13
       **
       ** This is the serial-type for a text object as long as the record
-      ** itself. In all cases the length required to store this is three
-      ** bytes or less. 
+      ** itself. In almost all cases the length required to store this is
+      ** three bytes or less. 
       */
       int max_space = sqlite3VarintLen((((u64)payloadSize)<<1)+13)*nField;
-      max_space += offset;
       if( max_space>payloadSize ){
         max_space = payloadSize;
       }
 
-      if( pC->keyAsData ){
-        zData = (char *)sqlite3BtreeKeyFetch(pCrsr, max_space);
-      }else{
-        zData = (char *)sqlite3BtreeDataFetch(pCrsr, max_space);
-      }
-      if( !zData ){
-        /* This code will run very infrequently (e.g. tables with several
-        ** hundred columns).
-        */
-        zData = (char *)sqliteMallocRaw(max_space);
-        if( !zData ){
-          goto no_mem;
-        }
-        if( pC->keyAsData ){
-          rc = sqlite3BtreeKey(pCrsr, 0, max_space, zData);
-        }else{
-          rc = sqlite3BtreeData(pCrsr, 0, max_space, zData);
-        }
-        if( rc!=SQLITE_OK ){
-          sqliteFree(zData);
-          goto abort_due_to_error;
-        }
-        freeZdata = 1;
+      rc = getBtreeMem(pCrsr, 0, max_space, pC->keyAsData, &zMem);
+      if( rc!=SQLITE_OK ){
+        goto abort_due_to_error;
       }
+      zData = zMem.z;
     }
 
     /* Read all the serial types for the record.  At the end of this block
@@ -2179,12 +2215,11 @@ case OP_Column: {
     for(nn=0; nn<nField; nn++){
       offset += sqlite3GetVarint(&zData[offset], &pC->aType[nn]);
     }
-    if( freeZdata ){
-      freeZdata = 0;
-      sqliteFree(zData);
-    }
     pC->nHeader = offset;
     pC->cacheValid = 1;
+
+    Release(&zMem);
+    zMem.flags = 0;
   }
 
   /* Compute the offset from the beginning of the record to the beginning
@@ -2194,44 +2229,17 @@ case OP_Column: {
   for(nn=0; nn<p2; nn++){
     offset += sqlite3VdbeSerialTypeLen(pC->aType[nn]);
   }
-  len = sqlite3VdbeSerialTypeLen(pC->aType[p2]);
 
-  if( !zRec ){
-    /* If the record is stored in a table, see if enough of it
-    ** is on the main page to read our column using
-    ** sqlite3BtreeDataFetch(). If not sqliteMalloc() space and read data
-    ** with sqlite3BtreeData().
-    */
-    if( pC->keyAsData ){
-      zData = (char *)sqlite3BtreeKeyFetch(pCrsr, offset+len);
-    }else{
-      zData = (char *)sqlite3BtreeDataFetch(pCrsr, offset+len);
-    }
-    if( !zData ){
-      zData = (char *)sqliteMallocRaw(len);
-      if( !zData ){
-        goto no_mem;
-      }
-      if( pC->keyAsData ){
-        rc = sqlite3BtreeKey(pCrsr, offset, len, zData);
-      }else{
-        rc = sqlite3BtreeData(pCrsr, offset, len, zData);
-      }
-      if( rc!=SQLITE_OK ){
-        sqliteFree( zData );
-        goto abort_due_to_error;
-      }
-      freeZdata = 1;
-      offset = 0;
-    }
+  if( zRec ){
+    zData = &zRec[offset];
+  }else{
+    len = sqlite3VdbeSerialTypeLen(pC->aType[p2]);
+    getBtreeMem(pCrsr, offset, len, pC->keyAsData, &zMem);
+    zData = zMem.z;
   }
+  sqlite3VdbeSerialGet(zData, pC->aType[p2], pTos);
 
-  /* Deserialize the value directly into the top of the stack */
-  sqlite3VdbeSerialGet(&zData[offset], pC->aType[p2], pTos);
-
-  if( freeZdata ){
-    sqliteFree(zData);
-  }
+  Release(&zMem);
   break;
 }
 
@@ -2293,7 +2301,6 @@ case OP_MakeRecord: {
   /* Loop through the elements that will make up the record to figure
   ** out how much space is required for the new record.
   */
-  // nBytes = sqlite3VarintLen(nField);
   for(pRec=pData0; pRec<=pTos; pRec++){
     u64 serial_type;
     if( zAffinity ){
@@ -2317,7 +2324,6 @@ case OP_MakeRecord: {
 
   /* Write the record */
   zCsr = zNewRecord;
-  // zCsr += sqlite3PutVarint(zCsr, nField);             /* number of fields */
   for(pRec=pData0; pRec<=pTos; pRec++){
     u64 serial_type = sqlite3VdbeSerialType(pRec);
     zCsr += sqlite3PutVarint(zCsr, serial_type);      /* serial type */
@@ -2348,9 +2354,9 @@ case OP_MakeRecord: {
 /* Opcode: MakeKey P1 P2 P3
 **
 ** Convert the top P1 entries of the stack into a single entry suitable
-** for use as the key in an index. If P2 is not zero, then the original 
-** entries are popped off the stack. If P2 is zero, the original entries
-** remain on the stack.
+** for use as the key in an index. If P2 is zero, then the original 
+** entries are popped off the stack. If P2 is not zero, the original 
+** entries remain on the stack.
 **
 ** P3 is interpreted in the same way as for MakeIdxKey.
 */
@@ -3449,11 +3455,16 @@ case OP_SetCounts: {
 ** off (if P2==0).  In key-as-data mode, the OP_Column opcode pulls
 ** data off of the key rather than the data.  This is used for
 ** processing compound selects.
+**
+** This opcode also instructs the cursor that the keys used will be
+** serialized in the record format usually used for table data, not
+** the usual index key format.
 */
 case OP_KeyAsData: {
   int i = pOp->p1;
   assert( i>=0 && i<p->nCursor );
   p->apCsr[i]->keyAsData = pOp->p2;
+  sqlite3BtreeSetCompare(p->apCsr[i]->pCursor, sqlite3VdbeRowCompare, p->apCsr[i]);
   break;
 }
 
index 4814647fb64f1460f2df874e8a3d5a4c8e82a344..c5a464b2bbda1344c28ccea82f5ceca8d18068df 100644 (file)
@@ -366,13 +366,14 @@ void sqlite3VdbeCompressSpace(Vdbe *p, int addr){
 }
 
 /*
-** Search for the current program for the given opcode and P2
-** value.  Return the address plus 1 if found and 0 if not found.
+** Search the current program starting at instruction addr for the given
+** opcode and P2 value.  Return the address plus 1 if found and 0 if not
+** found.
 */
-int sqlite3VdbeFindOp(Vdbe *p, int op, int p2){
+int sqlite3VdbeFindOp(Vdbe *p, int addr, int op, int p2){
   int i;
   assert( p->magic==VDBE_MAGIC_INIT );
-  for(i=0; i<p->nOp; i++){
+  for(i=addr; i<p->nOp; i++){
     if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return i+1;
   }
   return 0;
@@ -1478,7 +1479,7 @@ int sqlite3VdbeKeyCompare(
 ** or positive integer if {nKey1, pKey1} is less than, equal to or 
 ** greater than {nKey2, pKey2}.
 **
-** This function is pretty inefficient and will probably be replace
+** This function is pretty inefficient and will probably be replaced
 ** by something else in the near future. It is currently required
 ** by compound SELECT operators. 
 */
@@ -1487,12 +1488,58 @@ int sqlite3VdbeRowCompare(
   int nKey1, const void *pKey1, 
   int nKey2, const void *pKey2
 ){
+  Cursor *pC = (Cursor *)userData;
   int offset1 = 0;
   int offset2 = 0;
+  int toffset1 = 0;
+  int toffset2 = 0;
+  int i;
   const unsigned char *aKey1 = (const unsigned char *)pKey1;
   const unsigned char *aKey2 = (const unsigned char *)pKey2;
 
-  assert( userData==0 );
+  assert( pC );
+  assert( pC->nField>0 );
+
+  for( i=0; i<pC->nField; i++ ){
+    u64 dummy;
+    offset1 += sqlite3GetVarint(&aKey1[offset1], &dummy);
+    offset2 += sqlite3GetVarint(&aKey1[offset1], &dummy);
+  }
+
+  for( i=0; i<pC->nField; i++ ){
+    Mem mem1;
+    Mem mem2;
+    u64 serial_type1;
+    u64 serial_type2;
+    int rc;
+
+    /* Read the serial types for the next element in each key. */
+    toffset1 += sqlite3GetVarint(&aKey1[toffset1], &serial_type1);
+    toffset2 += sqlite3GetVarint(&aKey2[toffset2], &serial_type2);
+
+    assert( serial_type1 && serial_type2 );
+
+    /* Assert that there is enough space left in each key for the blob of
+    ** data to go with the serial type just read. This assert may fail if
+    ** the file is corrupted.  Then read the value from each key into mem1
+    ** and mem2 respectively.
+    */
+    offset1 += sqlite3VdbeSerialGet(&aKey1[offset1], serial_type1, &mem1);
+    offset2 += sqlite3VdbeSerialGet(&aKey2[offset2], serial_type2, &mem2);
+
+    rc = sqlite3MemCompare(&mem1, &mem2);
+    if( mem1.flags&MEM_Dyn ){
+      sqliteFree(mem1.z);
+    }
+    if( mem2.flags&MEM_Dyn ){
+      sqliteFree(mem2.z);
+    }
+    if( rc!=0 ){
+      return rc;
+    }
+  }
+
+  return 0;
 }