]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Tables and indices use the same record format. (CVS 1481)
authordrh <drh@noemail.net>
Fri, 28 May 2004 08:21:02 +0000 (08:21 +0000)
committerdrh <drh@noemail.net>
Fri, 28 May 2004 08:21:02 +0000 (08:21 +0000)
FossilOrigin-Name: ebd564d10b0ecd7ff15cbd6cd2b979c9f767476c

VERSION
manifest
manifest.uuid
src/expr.c
src/vdbe.c

diff --git a/VERSION b/VERSION
index 01b0f095f39f7610b127b0d734571fd62f39d88a..5e03dc0a917ac7bee19b957c65946e8b3c10d77d 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.8.13
+3.0.0alpha
index 4b3bcf03bed993c916bbdd6c34a4e11254454856..88f873d24b0c7b44ca158abb262734536701b579 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,9 +1,9 @@
-C Remove\sthe\sencoding\sargument\sfrom\ssqlite3VdbeSerialGet.\s\sUse\sthe\s32-bit\nversion\sof\ssqlite3GetVarint\sfor\sschema-level\sparameters.\s(CVS\s1480)
-D 2004-05-28T01:39:01
+C Tables\sand\sindices\suse\sthe\ssame\srecord\sformat.\s(CVS\s1481)
+D 2004-05-28T08:21:02
 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
-F VERSION 4328de2a5fb5000699b907ca405cb9d84ba4e097
+F VERSION 4490ff094970c0e36eff0cbe2adcdb3a701f6ad6
 F aclocal.m4 7daea4c35e88de30d5a3f6f7a2ab99720e803bbd
 F art/SQLite.eps 9b43cc99cfd2be687d386faea6862ea68d6a72b2
 F art/SQLite.gif 1bbb94484963f1382e27e1c5e86dd0c1061eba2b
@@ -30,7 +30,7 @@ F src/build.c 35cbeb439b49cca5eb5e8a1de010a5194f4523e8
 F src/date.c 0eb922af5c5f5e2455f8dc2f98023ed3e04a857e
 F src/delete.c 66c5ab98cbad7e6b315fc997bfe6c8080784a701
 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
-F src/expr.c 3f43cae2c8cf51ea8ee2abbf4dcc900b1326c5d6
+F src/expr.c 1f7b853b097806ff6b0a3edd884c9b6675698745
 F src/func.c 1fe0763675eb38b6e3992d3edfbec2271798b658
 F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
 F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
@@ -69,7 +69,7 @@ F src/update.c 96461bcf4e946697e83c09c77c7e61b545a2f66e
 F src/utf.c 59b5c8f06a4384a9f64933d6c57a2de02ce3673b
 F src/util.c d299404febd509556e720fbecadd880756b0f899
 F src/vacuum.c 8734f89742f246abd91dbd3e087fc153bddbfbad
-F src/vdbe.c ea44f5bef30c7fd8eeb28fb4aa5f05875566b369
+F src/vdbe.c c661752ea19a8b5a041d8c4f234e1524f6b3250e
 F src/vdbe.h e73f890e0f2a6c42b183d7d6937947930fe4fdeb
 F src/vdbeInt.h 57b649105aeab1e39e77bdb3de3c1560deddc69e
 F src/vdbeapi.c b0bb1f98c899ba00c8a5cbca612c2a28a1bb79de
@@ -203,7 +203,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P 203af2b2e3a25f4fe0e128e350c21834cad0bd7f
-R 2b74d4b0c22d8325d92f20886c62da43
+P 321f8c463520e99681de878b743027c570b73e35
+R b41c78025f27adccaab04283941e1081
 U drh
-Z e19993d4f4e147db54eb88d1ba253c94
+Z 03b836ac44307f3719b7ddd6c55ebe4b
index c4b14adb2c930d1909427a26bade3833cc6ddbdc..8acdec43de38a4b9ed8788861b802769073b6312 100644 (file)
@@ -1 +1 @@
-321f8c463520e99681de878b743027c570b73e35
\ No newline at end of file
+ebd564d10b0ecd7ff15cbd6cd2b979c9f767476c
\ No newline at end of file
index 20cd58f49d96d2ab9e26e8dc753e1435f01c7690..02f254bd8565450173f1560e5889a7121f4106a1 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.130 2004/05/27 09:28:42 danielk1977 Exp $
+** $Id: expr.c,v 1.131 2004/05/28 08:21:06 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -824,6 +824,7 @@ int sqlite3ExprResolveIds(
       keyInfo.aColl[0] = pParse->db->pDfltColl;
       sqlite3VdbeOp3(v, OP_OpenTemp, pExpr->iTable, 0, \
            (char*)&keyInfo, P3_KEYINFO);
+      sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1);
 
       if( pExpr->pSelect ){
         /* Case 1:     expr IN (SELECT ...)
index c40740589912e99f2594ad295c96557fbeb0dc6d..4d7ea7cfe41580051405b804657c6a8857184640 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.342 2004/05/28 01:39:01 drh Exp $
+** $Id: vdbe.c,v 1.343 2004/05/28 08:21:09 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -404,66 +404,6 @@ void prettyPrintMem(Mem *pMem, char *zBuf, int nBuf){
 char zGdbBuf[100];
 #endif
 
-/*
-** Move data out of a btree key or data field and into a Mem structure.
-** The data or key is taken from the entry that pCur is currently pointing
-** to.  offset and amt determine what portion of the data or key to retrieve.
-** key is true to get the key or false to get data.  The result is written
-** into the pMem element.
-*/
-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-2 ){
-      zData = (char *)sqliteMallocRaw(amt+2);
-      if( !zData ){
-        return SQLITE_NOMEM;
-      }
-      pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term;
-    }else{
-      zData = &(pMem->zShort[0]);
-      pMem->flags = MEM_Blob|MEM_Short|MEM_Term;
-    }
-    pMem->z = zData;
-    pMem->enc = 0;
-    pMem->type = SQLITE3_BLOB;
-
-    if( key ){
-      rc = sqlite3BtreeKey(pCur, offset, amt, zData);
-    }else{
-      rc = sqlite3BtreeData(pCur, offset, amt, zData);
-    }
-    zData[amt] = 0;
-    zData[amt+1] = 0;
-    if( rc!=SQLITE_OK ){
-      if( amt>NBFS ){
-        sqliteFree(zData);
-      }
-      return rc;
-    }
-  }
-
-  return SQLITE_OK;
-}
-
 
 #ifdef VDBE_PROFILE
 /*
@@ -1801,6 +1741,11 @@ case OP_SetNumColumns: {
   break;
 }
 
+/* Opcode: IdxColumn P1 * *
+**
+** P1 is a cursor opened on an index. Push the first field from the
+** current index key onto the stack.
+*/
 /* Opcode: Column P1 P2 *
 **
 ** Interpret the data that cursor P1 points to as a structure built using
@@ -1818,6 +1763,7 @@ case OP_SetNumColumns: {
 ** 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_IdxColumn:
 case OP_Column: {
   int payloadSize;   /* Number of bytes in the record */
   int p1 = pOp->p1;  /* P1 value of the opcode */
@@ -1921,7 +1867,7 @@ case OP_Column: {
 
     /* Get the complete header text */
     if( !zRec ){
-      rc = getBtreeMem(pCrsr, 0, szHdr, pC->keyAsData, &sMem);
+      rc = sqlite3VdbeMemFromBtree(pCrsr, 0, szHdr, pC->keyAsData, &sMem);
       if( rc!=SQLITE_OK ){
         goto abort_due_to_error;
       }
@@ -1971,7 +1917,7 @@ case OP_Column: {
     zData = &zRec[aOffset[p2]];
   }else{
     len = sqlite3VdbeSerialTypeLen(aType[p2]);
-    getBtreeMem(pCrsr, aOffset[p2], len, pC->keyAsData, &sMem);
+    sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->keyAsData, &sMem);
     zData = sMem.z;
   }
   sqlite3VdbeSerialGet(zData, aType[p2], pTos);
@@ -1988,6 +1934,44 @@ case OP_Column: {
   break;
 }
 
+/* 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 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.
+*/
+/* Opcode: MakeIdxKey P1 P2 P3
+**
+** Convert the top P1 entries of the stack into a single entry suitable
+** for use as the key in an index.  In addition, take one additional integer
+** off of the stack, treat that integer as an eight-byte record number, and
+** append the integer to the key as a varint.  Thus a total of P1+1 entries
+** are popped from the stack for this instruction and a single entry is
+** pushed back.  
+**
+** If P2 is not zero and one or more of the P1 entries that go into the
+** generated key is NULL, then jump to P2 after the new key has been
+** pushed on the stack.  In other words, jump to P2 if the key is
+** guaranteed to be unique.  This jump can be used to skip a subsequent
+** uniqueness test.
+**
+** P3 may be a string that is P1 characters long.  The nth character of the
+** string indicates the column affinity that should be used for the nth
+** field of the index key (i.e. the first character of P3 corresponds to the
+** lowest element on the stack).
+**
+**  Character      Column affinity
+**  ------------------------------
+**  'n'            NUMERIC
+**  'i'            INTEGER
+**  't'            TEXT
+**  'o'            NONE
+**
+** If P3 is NULL then datatype coercion occurs.
+*/
 /* Opcode MakeRecord P1 * P3
 **
 ** Convert the top P1 entries of the stack into a single entry
@@ -2010,6 +1994,8 @@ case OP_Column: {
 **
 ** If P3 is NULL then all index fields have the affinity NONE.
 */
+case OP_MakeKey:
+case OP_MakeIdxKey:
 case OP_MakeRecord: {
   /* Assuming the record contains N fields, the record format looks
   ** like this:
@@ -2033,26 +2019,49 @@ case OP_MakeRecord: {
   unsigned char *zCsr;
   char *zAffinity;
   Mem *pRec;
+  Mem *pRowid;
   int nData = 0;     /* Number of bytes of data space */
   int nHdr = 0;      /* Number of bytes of header space */
   int nByte = 0;     /* Space required for this record */
+  int addRowid;      /* True to append a rowid column at the end */
+  u32 serial_type;   /* Type field */
+  int containsNull;  /* True if any of the data fields are NULL */
 
   Mem *pData0 = &pTos[1-nField];
   assert( pData0>=p->aStack );
   zAffinity = pOp->p3;
+  addRowid = pOp->opcode==OP_MakeIdxKey;
+  containsNull = 0;
 
   /* Loop through the elements that will make up the record to figure
   ** out how much space is required for the new record.
   */
   for(pRec=pData0; pRec<=pTos; pRec++){
-    u32 serial_type;
     if( zAffinity ){
       applyAffinity(pRec, zAffinity[pRec-pData0], db->enc);
     }
+    if( pRec->flags&MEM_Null ){
+      containsNull = 1;
+    }
     serial_type = sqlite3VdbeSerialType(pRec);
     nData += sqlite3VdbeSerialTypeLen(serial_type);
     nHdr += sqlite3VarintLen(serial_type);
   }
+
+  /* If we have to append a varint rowid to this record, set 'rowid'
+  ** to the value of the rowid and increase nByte by the amount of space
+  ** required to store it and the 0x00 seperator byte.
+  */
+  if( addRowid ){
+    pRowid = &pTos[0-nField];
+    assert( pRowid>=p->aStack );
+    Integerify(pRowid, db->enc);
+    serial_type = sqlite3VdbeSerialType(pRowid);
+    nData += sqlite3VdbeSerialTypeLen(serial_type);
+    nHdr += sqlite3VarintLen(serial_type);
+  }
+
+  /* Add the initial header varint and total the size */
   nHdr += sqlite3VarintLen(nHdr);
   nByte = nHdr+nData;
 
@@ -2071,12 +2080,18 @@ case OP_MakeRecord: {
   zCsr = zNewRecord;
   zCsr += sqlite3PutVarint(zCsr, nHdr);
   for(pRec=pData0; pRec<=pTos; pRec++){
-    u32 serial_type = sqlite3VdbeSerialType(pRec);
+    serial_type = sqlite3VdbeSerialType(pRec);
     zCsr += sqlite3PutVarint(zCsr, serial_type);      /* serial type */
   }
+  if( addRowid ){
+    zCsr += sqlite3PutVarint(zCsr, sqlite3VdbeSerialType(pRowid));
+  }
   for(pRec=pData0; pRec<=pTos; pRec++){
     zCsr += sqlite3VdbeSerialPut(zCsr, pRec);  /* serial data */
   }
+  if( addRowid ){
+    zCsr += sqlite3VdbeSerialPut(zCsr, pRowid);
+  }
 
   /* If zCsr has not been advanced exactly nByte bytes, then one
   ** of the sqlite3PutVarint() or sqlite3VdbeSerialPut() calls above
@@ -2088,142 +2103,13 @@ case OP_MakeRecord: {
   }
 
   /* Pop nField entries from the stack and push the new entry on */
-  popStack(&pTos, nField);
-  pTos++;
-  pTos->n = nByte;
-  pTos->z = zNewRecord;
-  pTos->flags = MEM_Blob | MEM_Dyn;
-
-  break;
-}
-
-/* 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 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.
-*/
-/* Opcode: MakeIdxKey P1 P2 P3
-**
-** Convert the top P1 entries of the stack into a single entry suitable
-** for use as the key in an index.  In addition, take one additional integer
-** off of the stack, treat that integer as an eight-byte record number, and
-** append the integer to the key as a varint.  Thus a total of P1+1 entries
-** are popped from the stack for this instruction and a single entry is
-** pushed back.  
-**
-** If P2 is not zero and one or more of the P1 entries that go into the
-** generated key is NULL, then jump to P2 after the new key has been
-** pushed on the stack.  In other words, jump to P2 if the key is
-** guaranteed to be unique.  This jump can be used to skip a subsequent
-** uniqueness test.
-**
-** P3 may be a string that is P1 characters long.  The nth character of the
-** string indicates the column affinity that should be used for the nth
-** field of the index key (i.e. the first character of P3 corresponds to the
-** lowest element on the stack).
-**
-**  Character      Column affinity
-**  ------------------------------
-**  'n'            NUMERIC
-**  'i'            INTEGER
-**  't'            TEXT
-**  'o'            NONE
-**
-** If P3 is NULL then datatype coercion occurs.
-*/
-case OP_MakeKey:
-case OP_MakeIdxKey: {
-  Mem *pRec;
-  Mem *pData0;
-  int nField;
-  u64 rowid;
-  int nByte = 0;
-  int addRowid;
-  int containsNull = 0;
-  char *zKey;      /* The new key */
-  int offset = 0;
-  char *zAffinity = pOp->p3;
-  nField = pOp->p1;
-  assert( zAffinity==0 || strlen(zAffinity)>=nField );
-  pData0 = &pTos[1-nField];
-  assert( pData0>=p->aStack );
-
-  addRowid = ((pOp->opcode==OP_MakeIdxKey)?1:0);
-
-  /* Loop through the P1 elements that will make up the new index
-  ** key. Call applyAffinity() to perform any conversion required
-  ** the column affinity string P3 to modify stack elements in place.
-  ** Set containsNull to 1 if a NULL value is encountered.
-  **
-  ** Once the value has been coerced, figure out how much space is required
-  ** to store the coerced values serial-type and blob, and add this
-  ** quantity to nByte.
-  **
-  ** TODO: Figure out if the in-place coercion causes a problem for
-  ** OP_MakeKey when P2 is 0 (used by DISTINCT).
-  */
-  for(pRec=pData0; pRec<=pTos; pRec++){
-    u32 serial_type;
-    if( zAffinity ){
-      applyAffinity(pRec, zAffinity[pRec-pData0], db->enc);
-    }
-    if( pRec->flags&MEM_Null ){
-      containsNull = 1;
-    }
-    serial_type = sqlite3VdbeSerialType(pRec);
-    nByte += sqlite3VarintLen(serial_type);
-    nByte += sqlite3VdbeSerialTypeLen(serial_type);
-  }
-
-  /* If we have to append a varint rowid to this record, set 'rowid'
-  ** to the value of the rowid and increase nByte by the amount of space
-  ** required to store it and the 0x00 seperator byte.
-  */
-  if( addRowid ){
-    pRec = &pTos[0-nField];
-    assert( pRec>=p->aStack );
-    Integerify(pRec, db->enc);
-    rowid = pRec->i;
-    nByte += sqlite3VarintLen(rowid);
-    nByte++;
-  }
-  
-  if( nByte>MAX_BYTES_PER_ROW ){
-    rc = SQLITE_TOOBIG;
-    goto abort_due_to_error;
-  }
-
-  /* Allocate space for the new key */
-  zKey = (char *)sqliteMallocRaw(nByte);
-  if( !zKey ){
-    goto no_mem;
-  }
-  
-  /* Build the key in the buffer pointed to by zKey. */
-  for(pRec=pData0; pRec<=pTos; pRec++){
-    u32 serial_type = sqlite3VdbeSerialType(pRec);
-    offset += sqlite3PutVarint(&zKey[offset], serial_type);
-    offset += sqlite3VdbeSerialPut(&zKey[offset], pRec);
-  }
-  if( addRowid ){
-    zKey[offset++] = '\0';
-    offset += sqlite3PutVarint(&zKey[offset], rowid);
-  }
-  assert( offset==nByte );
-
-  /* Pop the consumed values off the stack and push on the new key. */
-  if( addRowid||(pOp->p2==0) ){
+  if( addRowid || pOp->p2==0 ){
     popStack(&pTos, nField+addRowid);
   }
   pTos++;
-  pTos->flags = MEM_Blob|MEM_Dyn;
-  pTos->z = zKey;
   pTos->n = nByte;
+  pTos->z = zNewRecord;
+  pTos->flags = MEM_Blob | MEM_Dyn;
 
   /* If P2 is non-zero, and if the key contains a NULL value, and if this
   ** was an OP_MakeIdxKey instruction, not OP_MakeKey, jump to P2.
@@ -2842,8 +2728,8 @@ case OP_Found: {
 **
 ** P1 is an index.  So it has no data and its key consists of a
 ** record generated by OP_MakeIdxKey.  This key contains one or more
-** fields followed by a varint ROWID.
-**
+** fields followed by a ROWID field.
+** 
 ** This instruction asks if there is an entry in P1 where the
 ** fields matches K but the rowid is different from R.
 ** If there is no such entry, then there is an immediate
@@ -2876,6 +2762,7 @@ case OP_IsUnique: {
     char *zKey;    /* The value of K */
     int nKey;      /* Number of bytes in K */
     int len;       /* Number of bytes in K without the rowid at the end */
+    int szRowid;   /* Size of the rowid column at the end of zKey */
 
     /* Make sure K is a string and make zKey point to K
     */
@@ -2883,9 +2770,8 @@ case OP_IsUnique: {
     zKey = pNos->z;
     nKey = pNos->n;
 
-    assert( nKey >= 2 );
-    len = nKey-2;
-    while( zKey[len] && --len );
+    szRowid = sqlite3VdbeIdxRowidLen(nKey, zKey);
+    len = nKey-szRowid;
 
     /* Search for an entry in P1 where all but the last four bytes match K.
     ** If there is no such entry, jump immediately to P2.
@@ -2909,8 +2795,8 @@ case OP_IsUnique: {
     }
 
     /* At this point, pCrsr is pointing to an entry in P1 where all but
-    ** the final varint (the rowid) matches K.  Check to see if the
-    ** final varint is different from R.  If it equals R then jump
+    ** the final entry (the rowid) matches K.  Check to see if the
+    ** final rowid column is different from R.  If it equals R then jump
     ** immediately to P2.
     */
     rc = sqlite3VdbeIdxRowid(pCrsr, &v);
@@ -3347,57 +3233,6 @@ case OP_Recno: {
   break;
 }
 
-/* Opcode: IdxColumn P1 * *
-**
-** P1 is a cursor opened on an index. Push the first field from the
-** current index key onto the stack.
-*/
-case OP_IdxColumn: {
-  char *zData;
-  i64 n;
-  u32 serial_type;
-  int len;
-  int freeZData = 0;
-  BtCursor *pCsr;
-
-  assert( 0==p->apCsr[pOp->p1]->intKey );
-  pCsr = p->apCsr[pOp->p1]->pCursor;
-  rc = sqlite3BtreeKeySize(pCsr, &n);
-  if( rc!=SQLITE_OK ){
-    goto abort_due_to_error;
-  }
-  if( n>10 ) n = 10;
-
-  zData = (char *)sqlite3BtreeKeyFetch(pCsr, n);
-  assert( zData );
-
-  len = sqlite3GetVarint32(zData, &serial_type);
-  n = sqlite3VdbeSerialTypeLen(serial_type);
-
-  zData = (char *)sqlite3BtreeKeyFetch(pCsr, len+n);
-  if( !zData ){
-    zData = (char *)sqliteMalloc(n);
-    if( !zData ){
-      goto no_mem;
-    }
-    rc = sqlite3BtreeKey(pCsr, len, n, zData);
-    if( rc!=SQLITE_OK ){
-      sqliteFree(zData);
-      goto abort_due_to_error;
-    }
-    freeZData = 1;
-    len = 0;
-  }
-
-  pTos++;
-  sqlite3VdbeSerialGet(&zData[len], serial_type, pTos);
-  pTos->enc = db->enc;
-  if( freeZData ){
-    sqliteFree(zData);
-  }
-  break;
-}
-
 /* Opcode: FullKey P1 * *
 **
 ** Extract the complete key from the record that cursor P1 is currently
@@ -3592,21 +3427,15 @@ case OP_IdxPut: {
     if( pOp->p2 ){
       int res;
       int len;
-      u64 n;
    
       /* 'len' is the length of the key minus the rowid at the end */
-      len = nKey-2;
-      while( zKey[len] && --len );
+      len = nKey - sqlite3VdbeIdxRowidLen(nKey, zKey);
 
       rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res);
       if( rc!=SQLITE_OK ) goto abort_due_to_error;
-      while( res!=0 ){
+      while( res!=0 && !sqlite3BtreeEof(pCrsr) ){
         int c;
-        sqlite3BtreeKeySize(pCrsr, &n);
-        if( n==nKey && 
-            sqlite3VdbeIdxKeyCompare(pC, len, zKey, &c)==SQLITE_OK
-            && c==0
-        ){
+        if( sqlite3VdbeIdxKeyCompare(pC, len, zKey, &c)==SQLITE_OK && c==0 ){
           rc = SQLITE_CONSTRAINT;
           if( pOp->p3 && pOp->p3[0] ){
             sqlite3SetString(&p->zErrMsg, pOp->p3, (char*)0);
@@ -3723,18 +3552,23 @@ case OP_IdxRecno: {
 
 /* Opcode: IdxGT P1 P2 *
 **
-** Compare the top of the stack against the key on the index entry that
-** cursor P1 is currently pointing to.  Ignore the ROWID of the
-** index entry.  If the index entry is greater than the top of the stack
+** The top of the stack is an index entry that omits the ROWID.  Compare
+** the top of stack against the index that P1 is currently pointing to.
+** Ignore the ROWID on the P1 index.
+**
+** The top of the stack might have fewer columns that P1.
+**
+** If the P1 index entry is greater than the top of the stack
 ** then jump to P2.  Otherwise fall through to the next instruction.
 ** In either case, the stack is popped once.
 */
 /* Opcode: IdxGE P1 P2 P3
 **
-** Compare the top of the stack against the key on the index entry that
-** cursor P1 is currently pointing to.  Ignore the ROWID of the
-** index entry.  If the index in the cursor is greater than or equal to 
-** the top of the stack
+** The top of the stack is an index entry that omits the ROWID.  Compare
+** the top of stack against the index that P1 is currently pointing to.
+** Ignore the ROWID on the P1 index.
+**
+** If the P1 index entry is greater than or equal to the top of the stack
 ** then jump to P2.  Otherwise fall through to the next instruction.
 ** In either case, the stack is popped once.
 **
@@ -3747,9 +3581,11 @@ case OP_IdxRecno: {
 */
 /* Opcode: IdxLT P1 P2 P3
 **
-** Compare the top of the stack against the key on the index entry that
-** cursor P1 is currently pointing to.  Ignore the ROWID of the
-** index entry.  If the index entry is less than the top of the stack
+** The top of the stack is an index entry that omits the ROWID.  Compare
+** the top of stack against the index that P1 is currently pointing to.
+** Ignore the ROWID on the P1 index.
+**
+** If the P1 index entry is less than  the top of the stack
 ** then jump to P2.  Otherwise fall through to the next instruction.
 ** In either case, the stack is popped once.
 **
@@ -3770,6 +3606,7 @@ case OP_IdxGE: {
   if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
     int res, rc;
  
+    assert( pTos->flags & MEM_Blob );  /* Created using OP_Make*Key */
     Stringify(pTos, db->enc);
     assert( pC->deferredMoveto==0 );
     *pC->pIncrKey = pOp->p3!=0;
@@ -3806,19 +3643,19 @@ case OP_IdxIsNull: {
   int i = pOp->p1;
   int k, n;
   const char *z;
+  u32 serial_type;
 
   assert( pTos>=p->aStack );
   assert( pTos->flags & MEM_Blob );
   z = pTos->z;
   n = pTos->n;
-  for(k=0; k<n && i>0; i--){
-    u32 serial_type;
+  k = sqlite3GetVarint32(z, &serial_type);
+  for(; k<n && i>0; i--){
     k += sqlite3GetVarint32(&z[k], &serial_type);
     if( serial_type==6 ){   /* Serial type 6 is a NULL */
       pc = pOp->p2-1;
       break;
     }
-    k += sqlite3VdbeSerialTypeLen(serial_type);
   }
   Release(pTos);
   pTos--;