]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Incremental update. We are in the middle of modifying the index system
authordrh <drh@noemail.net>
Wed, 7 Nov 2001 14:22:00 +0000 (14:22 +0000)
committerdrh <drh@noemail.net>
Wed, 7 Nov 2001 14:22:00 +0000 (14:22 +0000)
to support range queries without doing a complete table scan. (CVS 303)

FossilOrigin-Name: e6ca23fa4569bc33065bf57ce7ce6132cd6a9de0

manifest
manifest.uuid
src/btree.c
src/btree.h
src/build.c
src/delete.c
src/insert.c
src/select.c
src/update.c
src/vdbe.c
src/vdbe.h

index 7f9b9adba697101700fd491523f83b199e7d9025..aa73e89149c04d3915412ae137b87208fe980a7d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Added\ssupport\sfor\sLIMIT.\s(CVS\s302)
-D 2001-11-06T14:10:42
+C Incremental\supdate.\s\sWe\sare\sin\sthe\smiddle\sof\smodifying\sthe\sindex\ssystem\nto\ssupport\srange\squeries\swithout\sdoing\sa\scomplete\stable\sscan.\s(CVS\s303)
+D 2001-11-07T14:22:00
 F Makefile.in 6801df952cb1df64aa32e4de85fed24511d28efd
 F Makefile.template 1fdb891f14083ee0b63cf7282f91529634438e7a
 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@@ -19,14 +19,14 @@ F libtool c56e618713c9510a103bda6b95f3ea3900dcacd6
 F ltmain.sh e9ed72eb1d690f447c13945eaf69e28af531eda1
 F publish.sh 33cbe6798969f637698044023c139080e5d772a6
 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
-F src/btree.c 2789f704777d29b1b38e62e4798381ce602dc0fb
-F src/btree.h 57d653ef5137b91f2a068aaf71a2905468dd2cb7
-F src/build.c 65438f92919d92c7974e995f2d654b6cb3280a50
-F src/delete.c a4c13c444544f315703d5fbed6419c8786f66581
+F src/btree.c add522fad1b18c0face24e6f9f7468a6c696c5cc
+F src/btree.h 0250a0a577a98cc64ddf1582d50c08b8d2451650
+F src/build.c b459cbe33ee617f46b1975f96ae605d3519583d9
+F src/delete.c 9cb0b1470e50881d3404f78af353df3ebb6399e5
 F src/expr.c 2dd0252ced345c1e64db015b94dc6b5d7a57eef3
 F src/hash.c d0110e6da70a5962e21575fccf8206f7d9d75e00
 F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
-F src/insert.c b65c1d4b848e45d41e9dcccd2b226ca335de67b6
+F src/insert.c 962f277340adc265fbde4dd952055df7ede4e67b
 F src/main.c e2ae5e14a3f936d5fa7e3d9d9477610b5f16e7eb
 F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
 F src/os.c 66b677479eae37e30bdfbe32deb0fe6a2efca983
@@ -36,7 +36,7 @@ F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca
 F src/parse.y 5295f393f41ea89958287e5738e6c12c7cd67482
 F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
 F src/random.c 2a9cc2c9716d14815fd4c2accf89d87a1143e46b
-F src/select.c da60dfdd449ef6a71225878aca130b86f298c76e
+F src/select.c a97d3d27c544dc9a4849bfbad1cfa3e7c673bda9
 F src/shell.c 71597951753b56a97fea1c7a30908f31e635c00c
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in 934de9112747ad8d8e7d5fec44876246b24ca5a3
@@ -47,10 +47,10 @@ F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49
 F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321
 F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96
 F src/tokenize.c 830e9ef684334070a26583d94770bb869e2727bf
-F src/update.c 4eeb154a2da8a934d180e2d9e4211ac0a7a4ce8b
+F src/update.c b1e315e20b98a013d30fd9ff3b7d9dc4f29b39b3
 F src/util.c ac83973ecc647d3d3c58708f148442365abf9b94
-F src/vdbe.c 9f6ff3444a38d9bba27497be56e4ad386b316cbb
-F src/vdbe.h ea71a2c29d43c03283dee30237a01f4726900b29
+F src/vdbe.c 24306643bed5e19406735152ad68e98d598dcab0
+F src/vdbe.h a1170446638ce5b7f078279e640dcf91ec50de01
 F src/where.c 601f096f2a37ca688a775ca36d33534b13b876cb
 F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
 F test/bigrow.test 9458134d67f81559845f934fdd6802fe19a68ad1
@@ -115,7 +115,7 @@ F www/speed.tcl 212a91d555384e01873160d6a189f1490c791bc2
 F www/sqlite.tcl 6a21242a272e9c0939a04419a51c3d50cae33e3e
 F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
 F www/vdbe.tcl bb7d620995f0a987293e9d4fb6185a3b077e9b44
-P eb07768ae93f14bf6c150c1c4329948857a9d01c
-R 69771165b17aa31e07d926b8467701a7
+P 177012249ae93dbea4a11fb50faaae7912848bd0
+R 28881ea0807c6135a3c8ce43fbf768db
 U drh
-Z 0d18c20a2f39388100a44f2bc527ed6b
+Z bdd4c0f13b513e97b71388c7bea5ec3a
index 9dff5c9c91a2301d83e1f31a131700f5090a81b0..78c332e81c3ae89e0488a336bb5282189aea004a 100644 (file)
@@ -1 +1 @@
-177012249ae93dbea4a11fb50faaae7912848bd0
\ No newline at end of file
+e6ca23fa4569bc33065bf57ce7ce6132cd6a9de0
\ No newline at end of file
index aea978b04fd6ded347b87a580d666ecae53fc354..cc6ddf8cfddf62e2bc4a4a5ce2f6d2d6124f302d 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.37 2001/11/04 18:32:47 drh Exp $
+** $Id: btree.c,v 1.38 2001/11/07 14:22:00 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -1085,9 +1085,14 @@ int sqliteBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){
 }
 
 /*
-** Compare the first nKey bytes of the key of the entry that pCur
-** points to against the first nKey bytes of pKey.  Set *pRes to
-** show the comparison results:
+** Compare an external key against the key on the entry that pCur points to.
+**
+** The external key is pKey and is nKey bytes long.  The last nIgnore bytes
+** of the key associated with pCur are ignored, as if they do not exist.
+** (The normal case is for nIgnore to be zero in which case the entire
+** internal key is used in the comparison.)
+**
+** The comparison result is written to *pRes as follows:
 **
 **    *pRes<0    This means pCur<pKey
 **
@@ -1095,33 +1100,29 @@ int sqliteBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){
 **
 **    *pRes>0    This means pCur>pKey
 **
-** If pCur contains N bytes where N<nKey and the N bytes of pCur
-** match the first N bytes of pKey, then *pRes<0 is returned.
-** If pCur differs from pKey in the first N bytes, then *pRes<0
-** or *pRes>0 depending on the difference.
-**
-** If pCur contains M bytes where M>nKey then only the first nKey
-** bytes of pCur are used in the comparison.  The result is the same
-** as it would be if pCur were truncated to nKey bytes.
+** When one key is an exact prefix of the other, the shorter key is
+** considered less than the longer one.  In order to be equal the
+** keys must be exactly the same length. (The length of the pCur key
+** is the actual key length minus nIgnore bytes.)
 */
 int sqliteBtreeKeyCompare(
-  BtCursor *pCur,
-  const void *pKey,
-  int nKey,
-  int *pResult
+  BtCursor *pCur,       /* Pointer to entry to compare against */
+  const void *pKey,     /* Key to compare against entry that pCur points to */
+  int nKey,             /* Number of bytes in pKey */
+  int nIgnore,          /* Ignore this many bytes at the end of pCur */
+  int *pResult          /* Write the result here */
 ){
   Pgno nextPage;
-  int n, c, rc;
+  int n, c, rc, nLocal;
   Cell *pCell;
   const char *zKey  = (const char*)pKey;
 
   assert( pCur->pPage );
   assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
   pCell = pCur->pPage->apCell[pCur->idx];
-  if( nKey > NKEY(pCell->h) ){
-    nKey = NKEY(pCell->h);
-  }
-  n = nKey;
+  nLocal = NKEY(pCell->h) - nIgnore;
+  if( nLocal<0 ) nLocal = 0;
+  n = nKey<nLocal ? nKey : nLocal;
   if( n>MX_LOCAL_PAYLOAD ){
     n = MX_LOCAL_PAYLOAD;
   }
@@ -1132,8 +1133,9 @@ int sqliteBtreeKeyCompare(
   }
   zKey += n;
   nKey -= n;
+  nLocal -= n;
   nextPage = pCell->ovfl;
-  while( nKey>0 ){
+  while( nKey>0 && nLocal>0 ){
     OverflowPage *pOvfl;
     if( nextPage==0 ){
       return SQLITE_CORRUPT;
@@ -1143,7 +1145,7 @@ int sqliteBtreeKeyCompare(
       return rc;
     }
     nextPage = pOvfl->iNext;
-    n = nKey;
+    n = nKey<nLocal ? nKey : nLocal;
     if( n>OVERFLOW_SIZE ){
       n = OVERFLOW_SIZE;
     }
@@ -1154,44 +1156,11 @@ int sqliteBtreeKeyCompare(
       return SQLITE_OK;
     }
     nKey -= n;
+    nLocal -= n;
     zKey += n;
   }
-  *pResult = c;
-  return SQLITE_OK;
-}
-
-/*
-** Compare the key for the entry that pCur points to against the 
-** given key (pKey,nKeyOrig).  Put the comparison result in *pResult.
-** The result is negative if pCur<pKey, zero if they are equal and
-** positive if pCur>pKey.
-**
-** Shorter strings are considered less than longer strings if they
-** are otherwise equal.  All bytes of both pCur and pKey are considered
-** in this comparison.  This is different from sqliteBtreeKeyCompare()
-** which only considers the first nKeyOrig bytes of pCur.
-**
-** SQLITE_OK is returned on success.  If part of the cursor key
-** is on overflow pages and we are unable to access those overflow
-** pages, then some other value might be returned to indicate the
-** reason for the error.
-*/
-static int compareKey(
-  BtCursor *pCur,      /* Points to the entry against which we are comparing */
-  const char *pKey,    /* The comparison key */
-  int nKeyOrig,        /* Number of bytes in the comparison key */
-  int *pResult         /* Write the comparison results here */
-){
-  int rc, c;
-  
-  rc = sqliteBtreeKeyCompare(pCur, pKey, nKeyOrig, &c);
-  if( rc!=SQLITE_OK ) return rc;
   if( c==0 ){
-    Cell *pCell;
-    assert( pCur->pPage );
-    assert( pCur->pPage->nCell>pCur->idx && pCur->idx>=0 );
-    pCell = pCur->pPage->apCell[pCur->idx];
-    c = NKEY(pCell->h) - nKeyOrig;
+    c = nLocal - nKey;
   }
   *pResult = c;
   return SQLITE_OK;
@@ -1329,7 +1298,7 @@ int sqliteBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){
     upr = pPage->nCell-1;
     while( lwr<=upr ){
       pCur->idx = (lwr+upr)/2;
-      rc = compareKey(pCur, pKey, nKey, &c);
+      rc = sqliteBtreeKeyCompare(pCur, pKey, nKey, 0, &c);
       if( rc ) return rc;
       if( c==0 ){
         pCur->iMatch = c;
index 0769e405ba952c5341626adf9acaf9762f3d09fc..b468a55367d710cfccc04391f3897a8509015104 100644 (file)
@@ -12,7 +12,7 @@
 ** This header file defines the interface that the sqlite B-Tree file
 ** subsystem.
 **
-** @(#) $Id: btree.h,v 1.16 2001/09/27 03:22:33 drh Exp $
+** @(#) $Id: btree.h,v 1.17 2001/11/07 14:22:00 drh Exp $
 */
 #ifndef _BTREE_H_
 #define _BTREE_H_
@@ -41,7 +41,8 @@ int sqliteBtreeFirst(BtCursor*, int *pRes);
 int sqliteBtreeNext(BtCursor*, int *pRes);
 int sqliteBtreeKeySize(BtCursor*, int *pSize);
 int sqliteBtreeKey(BtCursor*, int offset, int amt, char *zBuf);
-int sqliteBtreeKeyCompare(BtCursor*, const void *pKey, int nKey, int *pRes);
+int sqliteBtreeKeyCompare(BtCursor*, const void *pKey, int nKey,
+                          int nIgnore, int *pRes);
 int sqliteBtreeDataSize(BtCursor*, int *pSize);
 int sqliteBtreeData(BtCursor*, int offset, int amt, char *zBuf);
 int sqliteBtreeCloseCursor(BtCursor*);
index bec84b6f4467e65f8de2bae24f2bfd052b235671..c9fea4ecdfdc63418070fea92e8ec68bcb757b7c 100644 (file)
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.53 2001/11/06 14:10:42 drh Exp $
+** $Id: build.c,v 1.54 2001/11/07 14:22:00 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -991,7 +991,7 @@ void sqliteCreateIndex(
         sqliteVdbeAddOp(v, OP_Column, 2, pIndex->aiColumn[i]);
       }
       sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0);
-      sqliteVdbeAddOp(v, OP_PutIdx, 1, pIndex->isUnique);
+      sqliteVdbeAddOp(v, OP_IdxPut, 1, pIndex->isUnique);
       sqliteVdbeAddOp(v, OP_Goto, 0, lbl1);
       sqliteVdbeResolveLabel(v, lbl2);
       sqliteVdbeAddOp(v, OP_Noop, 0, 0);
@@ -1282,7 +1282,7 @@ void sqliteCopy(
         sqliteVdbeAddOp(v, OP_FileColumn, pIdx->aiColumn[j], 0);
       }
       sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
-      sqliteVdbeAddOp(v, OP_PutIdx, i, pIdx->isUnique);
+      sqliteVdbeAddOp(v, OP_IdxPut, i, pIdx->isUnique);
     }
     sqliteVdbeAddOp(v, OP_Goto, 0, addr);
     sqliteVdbeResolveLabel(v, end);
index 62dc19f570777d523d43f86c2854742b52aa4848..5654b6ccef12e487e351a8c3cbea52505b980778 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.19 2001/11/01 14:41:34 drh Exp $
+** $Id: delete.c,v 1.20 2001/11/07 14:22:00 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -161,7 +161,7 @@ void sqliteDeleteFrom(
           sqliteVdbeAddOp(v, OP_Column, base, pIdx->aiColumn[j]);
         }
         sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
-        sqliteVdbeAddOp(v, OP_DeleteIdx, base+i, 0);
+        sqliteVdbeAddOp(v, OP_IdxDelete, base+i, 0);
       }
     }
     sqliteVdbeAddOp(v, OP_Delete, base, 0);
index 8f93d5cebde8d5718696a0c9c689220f1b06e0b7..50e095797e117f86f3c486e3992d99013676de7a 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.24 2001/10/15 00:44:36 drh Exp $
+** $Id: insert.c,v 1.25 2001/11/07 14:22:00 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -231,7 +231,7 @@ void sqliteInsert(
       }
     }
     sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
-    sqliteVdbeAddOp(v, OP_PutIdx, idx+base, pIdx->isUnique);
+    sqliteVdbeAddOp(v, OP_IdxPut, idx+base, pIdx->isUnique);
   }
 
 
index 271fbb158670ea563f9ce2dae2ed389b17db81ad..9ff90043e99d62336dc476b640cc25006795ad2f 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.47 2001/11/06 14:10:42 drh Exp $
+** $Id: select.c,v 1.48 2001/11/07 14:22:00 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -200,7 +200,7 @@ static int selectInnerLoop(
   */
   if( eDest==SRT_Mem ){
     assert( nColumn==1 );
-    sqliteVdbeAddOp(v, OP_MemStore, iParm, 0);
+    sqliteVdbeAddOp(v, OP_MemStore, iParm, 1);
     sqliteVdbeAddOp(v, OP_Goto, 0, iBreak);
   }else
 
@@ -907,7 +907,7 @@ int sqliteSelect(
   */
   if( eDest==SRT_Mem ){
     sqliteVdbeAddOp(v, OP_String, 0, 0);
-    sqliteVdbeAddOp(v, OP_MemStore, iParm, 0);
+    sqliteVdbeAddOp(v, OP_MemStore, iParm, 1);
   }
 
   /* Begin the database scan
index b4dea0ddea4fa18fd2477eaf37ee5010b555e1dd..9cc967a1136ab012e776e32557e3d8159c8367d1 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.20 2001/11/01 14:41:34 drh Exp $
+** $Id: update.c,v 1.21 2001/11/07 14:22:00 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -190,7 +190,7 @@ void sqliteUpdate(
       sqliteVdbeAddOp(v, OP_Column, base, pIdx->aiColumn[j]);
     }
     sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
-    sqliteVdbeAddOp(v, OP_DeleteIdx, base+i+1, 0);
+    sqliteVdbeAddOp(v, OP_IdxDelete, base+i+1, 0);
   }
 
   /* Compute a completely new data for this record.  
@@ -213,7 +213,7 @@ void sqliteUpdate(
       sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiColumn[j], 0);
     }
     sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
-    sqliteVdbeAddOp(v, OP_PutIdx, base+i+1, pIdx->isUnique);
+    sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, pIdx->isUnique);
   }
 
   /* Write the new data back into the database.
index 5aea72e670f7ca34f37b92076bd11c65ef68c84a..ba6fc566a584773c661717b89ad2395bd18da597 100644 (file)
@@ -30,7 +30,7 @@
 ** But other routines are also provided to help in building up
 ** a program instruction by instruction.
 **
-** $Id: vdbe.c,v 1.93 2001/11/06 04:00:19 drh Exp $
+** $Id: vdbe.c,v 1.94 2001/11/07 14:22:00 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -843,28 +843,29 @@ static char *zOpName[] = { 0,
   "MoveTo",            "Fcnt",              "NewRecno",          "Put",
   "Distinct",          "Found",             "NotFound",          "Delete",
   "Column",            "KeyAsData",         "Recno",             "FullKey",
-  "Rewind",            "Next",              "Destroy",           "Clear",
-  "CreateIndex",       "CreateTable",       "Reorganize",        "BeginIdx",
-  "NextIdx",           "PutIdx",            "DeleteIdx",         "MemLoad",
+  "Rewind",            "Next",              "NextN",             "Destroy",
+  "Clear",             "CreateIndex",       "CreateTable",       "Reorganize",
+  "BeginIdx",          "NextIdx",           "IdxPut",            "IdxDelete",
+  "IdxRecno",          "IdxGT",             "IdxGE",             "MemLoad",
   "MemStore",          "ListWrite",         "ListRewind",        "ListRead",
   "ListReset",         "SortPut",           "SortMakeRec",       "SortMakeKey",
   "Sort",              "SortNext",          "SortCallback",      "SortReset",
   "FileOpen",          "FileRead",          "FileColumn",        "AggReset",
   "AggFocus",          "AggIncr",           "AggNext",           "AggSet",
   "AggGet",            "SetInsert",         "SetFound",          "SetNotFound",
-  "MakeRecord",        "MakeKey",           "MakeIdxKey",        "Goto",
-  "If",                "Halt",              "ColumnCount",       "ColumnName",
-  "Callback",          "NullCallback",      "Integer",           "String",
-  "Pop",               "Dup",               "Pull",              "Add",
-  "AddImm",            "Subtract",          "Multiply",          "Divide",
-  "Remainder",         "BitAnd",            "BitOr",             "BitNot",
-  "ShiftLeft",         "ShiftRight",        "AbsValue",          "Precision",
-  "Min",               "Max",               "Like",              "Glob",
-  "Eq",                "Ne",                "Lt",                "Le",
-  "Gt",                "Ge",                "IsNull",            "NotNull",
-  "Negative",          "And",               "Or",                "Not",
-  "Concat",            "Noop",              "Strlen",            "Substr",
-  "Limit",
+  "MakeRecord",        "MakeKey",           "MakeIdxKey",        "IncrKey",
+  "Goto",              "If",                "Halt",              "ColumnCount",
+  "ColumnName",        "Callback",          "NullCallback",      "Integer",
+  "String",            "Pop",               "Dup",               "Pull",
+  "Add",               "AddImm",            "Subtract",          "Multiply",
+  "Divide",            "Remainder",         "BitAnd",            "BitOr",
+  "BitNot",            "ShiftLeft",         "ShiftRight",        "AbsValue",
+  "Precision",         "Min",               "Max",               "Like",
+  "Glob",              "Eq",                "Ne",                "Lt",
+  "Le",                "Gt",                "Ge",                "IsNull",
+  "NotNull",           "Negative",          "And",               "Or",
+  "Not",               "Concat",            "Noop",              "Strlen",
+  "Substr",            "Limit",           
 };
 
 /*
@@ -2156,6 +2157,29 @@ case OP_MakeKey: {
   break;
 }
 
+/* Opcode: IncrKey * * *
+**
+** The top of the stack should contain an index key generated by
+** The MakeKey opcode.  This routine increases the least significant
+** byte of that key by one.  This is used so that the MoveTo opcode
+** will move to the first entry greater than the key rather than to
+** the key itself.
+*/
+case OP_IncrKey: {
+  int tos = p->tos;
+
+  VERIFY( if( tos<0 ) goto bad_instruction );
+  if( Stringify(p, tos) ) goto no_mem;
+  if( aStack[tos].flags & STK_Static ){
+    char *zNew = sqliteMalloc( aStack[tos].n );
+    memcpy(zNew, zStack[tos], aStack[tos].n);
+    zStack[tos] = zNew;
+    aStack[tos].flags = STK_Str | STK_Dyn;
+  }
+  zStack[tos][aStack[tos].n-1]++;
+  break;
+}
+
 /* Opcode: Transaction * * *
 **
 ** Begin a transaction.  The transaction ends when a Commit or Rollback
@@ -2473,12 +2497,14 @@ case OP_Close: {
   break;
 }
 
-/* Opcode: MoveTo P1 * *
+/* Opcode: MoveTo P1 P2 *
 **
 ** Pop the top of the stack and use its value as a key.  Reposition
 ** cursor P1 so that it points to an entry with a matching key.  If
 ** the table contains no record with a matching key, then the cursor
-** is left pointing at a nearby record.
+** is left pointing at the first record that is greater than the key.
+** If there are no records greater than the key and P2 is not zero,
+** then an immediate jump to P2 is made.
 **
 ** See also: Found, NotFound, Distinct
 */
@@ -2501,6 +2527,13 @@ case OP_MoveTo: {
       pC->recnoIsValid = 0;
     }
     p->nFetch++;
+    if( res<0 ){
+      sqliteBtreeNext(pC->pCursor, &res);
+      pC->recnoIsValid = 0;
+      if( res && pOp->p2>0 ){
+        pc = pOp->p2 - 1;
+      }
+    }
   }
   POPSTACK;
   break;
@@ -2870,10 +2903,13 @@ case OP_FullKey: {
   break;
 }
 
-/* Opcode: Rewind P1 * *
+/* Opcode: Rewind P1 P2 *
 **
 ** The next use of the Recno or Column or Next instruction for P1 
-** will refer to the first entry in the database file.
+** will refer to the first entry in the database table or index.
+** If the table or index is empty and P2>0, then jump immediately to P2.
+** If P2 is 0 or if the table or index is not empty, fall through
+** to the following instruction.
 */
 case OP_Rewind: {
   int i = pOp->p1;
@@ -2883,6 +2919,9 @@ case OP_Rewind: {
     int res;
     sqliteBtreeFirst(pCrsr, &res);
     p->aCsr[i].atFirst = res==0;
+    if( res && pOp->p2>0 ){
+      pc = pOp->p2 - 1;
+    }
   }
   break;
 }
@@ -2912,6 +2951,29 @@ case OP_Next: {
   break;
 }
 
+/* Opcode: NextN P1 P2 *
+**
+** Advance cursor P1 so that it points to the next key/data pair in its
+** table or index.  If there are no more key/value pairs then fall through
+** to the following instruction.  But if the cursor advance was successful,
+** jump immediately to P2.
+*/
+case OP_NextN: {
+  int i = pOp->p1;
+  BtCursor *pCrsr;
+
+  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
+    int res;
+    rc = sqliteBtreeNext(pCrsr, &res);
+    if( res==0 ){
+      pc = pOp->p2 - 1;
+      p->nFetch++;
+    }
+    p->aCsr[i].recnoIsValid = 0;
+  }
+  break;
+}
+
 /* Opcode: BeginIdx P1 * *
 **
 ** Begin searching an index for records with the key found on the
@@ -2981,8 +3043,8 @@ case OP_NextIdx: {
     }
     sqliteBtreeKeySize(pCur, &size);
     if( res>0 || size!=pCrsr->nKey+sizeof(u32) ||
-      sqliteBtreeKeyCompare(pCur, pCrsr->zKey, pCrsr->nKey, &res)!=SQLITE_OK ||
-      res!=0
+      sqliteBtreeKeyCompare(pCur, pCrsr->zKey, pCrsr->nKey, 4, &res)!=SQLITE_OK
+      || res!=0
     ){
       pc = pOp->p2 - 1;
       POPSTACK;
@@ -2998,7 +3060,7 @@ case OP_NextIdx: {
   break;
 }
 
-/* Opcode: PutIdx P1 P2 P3
+/* Opcode: IdxPut P1 P2 P3
 **
 ** The top of the stack hold an SQL index key made using the
 ** MakeIdxKey instruction.  This opcode writes that key into the
@@ -3009,7 +3071,7 @@ case OP_NextIdx: {
 ** is rolled back.  If P3 is not null, then it because part of the
 ** error message returned with the SQLITE_CONSTRAINT.
 */
-case OP_PutIdx: {
+case OP_IdxPut: {
   int i = pOp->p1;
   int tos = p->tos;
   BtCursor *pCrsr;
@@ -3026,7 +3088,7 @@ case OP_PutIdx: {
         int c;
         sqliteBtreeKeySize(pCrsr, &n);
         if( n==nKey
-           && sqliteBtreeKeyCompare(pCrsr, zKey, nKey-4, &c)==SQLITE_OK
+           && sqliteBtreeKeyCompare(pCrsr, zKey, nKey-4, 4, &c)==SQLITE_OK
            && c==0
         ){
           rc = SQLITE_CONSTRAINT;
@@ -3049,12 +3111,12 @@ case OP_PutIdx: {
   break;
 }
 
-/* Opcode: DeleteIdx P1 * *
+/* Opcode: IdxDelete P1 * *
 **
 ** The top of the stack is an index key built using the MakeIdxKey opcode.
 ** This opcode removes that entry from the index.
 */
-case OP_DeleteIdx: {
+case OP_IdxDelete: {
   int i = pOp->p1;
   int tos = p->tos;
   BtCursor *pCrsr;
@@ -3070,6 +3132,74 @@ case OP_DeleteIdx: {
   break;
 }
 
+/* Opcode: IdxRecno P1 * *
+**
+** Push onto the stack an integer which is the last 4 bytes of the
+** the key to the current entry in index P1.  These 4 bytes should
+** be the record number of the table entry to which this index entry
+** points.
+**
+** See also: Recno, MakeIdxKey.
+*/
+case OP_IdxRecno: {
+  int i = pOp->p1;
+  int tos = ++p->tos;
+  BtCursor *pCrsr;
+
+  VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
+  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
+    int v;
+    int sz;
+    sqliteBtreeKeySize(pCrsr, &sz);
+    sqliteBtreeKey(pCrsr, sz - sizeof(u32), sizeof(u32), (char*)&v);
+    v = bigEndian(v);
+    aStack[tos].i = v;
+    aStack[tos].flags = STK_Int;
+  }
+  break;
+}
+
+/* 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 last 4 bytes of the
+** index entry.  If the 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 *
+**
+** Compare the top of the stack against the key on the index entry that
+** cursor P1 is currently pointing to.  Ignore the last 4 bytes of the
+** index entry.  If the 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.
+*/
+case OP_IdxGT:
+case OP_IdxGE: {
+  int i= pOp->p1;
+  int tos = p->tos;
+  BtCursor *pCrsr;
+
+  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
+    int res, rc;
+    if( Stringify(p, tos) ) goto no_mem;
+    rc = sqliteBtreeKeyCompare(pCrsr, zStack[tos], aStack[tos].n, 4, &res);
+    if( rc!=SQLITE_OK ){
+      break;
+    }
+    if( pOp->opcode==OP_IdxGE ){
+      res++;
+    }
+    if( res>0 ){
+      pc = pOp->p2 - 1 ;
+    }
+  }
+  break;
+}
+
 /* Opcode: Destroy P1 P2 *
 **
 ** Delete an entire database table or index whose root page in the database
@@ -3613,11 +3743,15 @@ case OP_FileColumn: {
   break;
 }
 
-/* Opcode: MemStore P1 * *
+/* Opcode: MemStore P1 P2 *
 **
-** Pop a single value of the stack and store that value into memory
-** location P1.  P1 should be a small integer since space is allocated
+** Write the top of the stack into memory location P1.
+** P1 should be a small integer since space is allocated
 ** for all memory locations between 0 and P1 inclusive.
+**
+** After the data is stored in the memory location, the
+** stack is popped once if P2 is 1.  If P2 is zero, then
+** the original data remains on the stack.
 */
 case OP_MemStore: {
   int i = pOp->p1;
@@ -3644,41 +3778,43 @@ case OP_MemStore: {
   }
   pMem->s = aStack[tos];
   if( pMem->s.flags & (STK_Static|STK_Dyn) ){
-    pMem->z = zStack[tos];
+    if( pOp->p2==0 && (pMem->s.flags & STK_Dyn)!=0 ){
+      pMem->z = sqliteMalloc( pMem->s.n );
+      if( pMem->z ) goto no_mem;
+      memcpy(pMem->z, zStack[tos], pMem->s.n);
+    }else{
+      pMem->z = zStack[tos];
+    }
   }else{
     pMem->z = pMem->s.z;
   }
   if( zOld ) sqliteFree(zOld);
-  zStack[tos] = 0;
-  aStack[tos].flags = 0;
-  POPSTACK;
+  if( pOp->p2 ){
+    zStack[tos] = 0;
+    aStack[tos].flags = 0;
+    POPSTACK;
+  }
   break;
 }
 
 /* Opcode: MemLoad P1 * *
 **
 ** Push a copy of the value in memory location P1 onto the stack.
+**
+** If the value is a string, then the value pushed is a pointer to
+** the string that is stored in the memory location.  If the memory
+** location is subsequently changed (using OP_MemStore) then the
+** value pushed onto the stack will change too.
 */
 case OP_MemLoad: {
   int tos = ++p->tos;
   int i = pOp->p1;
   VERIFY( if( NeedStack(p, tos) ) goto no_mem; )
-  if( i<0 || i>=p->nMem ){
-    aStack[tos].flags = STK_Null;
-    zStack[tos] = 0;
-  }else{
-    aStack[tos] = p->aMem[i].s;
-    if( aStack[tos].flags & STK_Dyn ){
-      char *z = sqliteMalloc(aStack[tos].n);
-      if( z==0 ) goto no_mem;
-      memcpy(z, p->aMem[i].z, aStack[tos].n);
-      zStack[tos] = z;
-      aStack[tos].flags |= STK_Dyn;
-    }else if( aStack[tos].flags & STK_Static ){
-      zStack[tos] = p->aMem[i].z;
-    }else if( aStack[tos].flags & STK_Str ){
-      zStack[tos] = aStack[tos].z;
-    }
+  VERIFY( if( i<0 || i>=p->nMem ) goto bad_instruction; )
+  memcpy(&aStack[tos], &p->aMem[i].s, sizeof(aStack[tos])-NBFS);;
+  if( aStack[tos].flags & STK_Str ){
+    zStack[tos] = p->aMem[i].z;
+    aStack[tos].flags = STK_Str | STK_Static;
   }
   break;
 }
index d835b2a113f92883a01615db228b6ecd7c6be7aa..7d3aac15789b6ada4a7e328d748519078eb47fa1 100644 (file)
@@ -15,7 +15,7 @@
 ** or VDBE.  The VDBE implements an abstract machine that runs a
 ** simple program to access and modify the underlying database.
 **
-** $Id: vdbe.h,v 1.33 2001/11/06 04:00:19 drh Exp $
+** $Id: vdbe.h,v 1.34 2001/11/07 14:22:00 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -96,106 +96,111 @@ typedef struct VdbeOp VdbeOp;
 #define OP_FullKey            24
 #define OP_Rewind             25
 #define OP_Next               26
-
-#define OP_Destroy            27
-#define OP_Clear              28
-#define OP_CreateIndex        29
-#define OP_CreateTable        30
-#define OP_Reorganize         31
-
-#define OP_BeginIdx           32
-#define OP_NextIdx            33
-#define OP_PutIdx             34
-#define OP_DeleteIdx          35
-
-#define OP_MemLoad            36
-#define OP_MemStore           37
-
-#define OP_ListWrite          38
-#define OP_ListRewind         39
-#define OP_ListRead           40
-#define OP_ListReset          41
-
-#define OP_SortPut            42
-#define OP_SortMakeRec        43
-#define OP_SortMakeKey        44
-#define OP_Sort               45
-#define OP_SortNext           46
-#define OP_SortCallback       47
-#define OP_SortReset          48
-
-#define OP_FileOpen           49
-#define OP_FileRead           50
-#define OP_FileColumn         51
-
-#define OP_AggReset           52
-#define OP_AggFocus           53
-#define OP_AggIncr            54
-#define OP_AggNext            55
-#define OP_AggSet             56
-#define OP_AggGet             57
-
-#define OP_SetInsert          58
-#define OP_SetFound           59
-#define OP_SetNotFound        60
-
-#define OP_MakeRecord         61
-#define OP_MakeKey            62
-#define OP_MakeIdxKey         63
-
-#define OP_Goto               64
-#define OP_If                 65
-#define OP_Halt               66
-
-#define OP_ColumnCount        67
-#define OP_ColumnName         68
-#define OP_Callback           69
-#define OP_NullCallback       70
-
-#define OP_Integer            71
-#define OP_String             72
-#define OP_Pop                73
-#define OP_Dup                74
-#define OP_Pull               75
-
-#define OP_Add                76
-#define OP_AddImm             77
-#define OP_Subtract           78
-#define OP_Multiply           79
-#define OP_Divide             80
-#define OP_Remainder          81
-#define OP_BitAnd             82
-#define OP_BitOr              83
-#define OP_BitNot             84
-#define OP_ShiftLeft          85
-#define OP_ShiftRight         86
-#define OP_AbsValue           87
-#define OP_Precision          88
-#define OP_Min                89
-#define OP_Max                90
-#define OP_Like               91
-#define OP_Glob               92
-#define OP_Eq                 93
-#define OP_Ne                 94
-#define OP_Lt                 95
-#define OP_Le                 96
-#define OP_Gt                 97
-#define OP_Ge                 98
-#define OP_IsNull             99
-#define OP_NotNull           100
-#define OP_Negative          101
-#define OP_And               102
-#define OP_Or                103
-#define OP_Not               104
-#define OP_Concat            105
-#define OP_Noop              106
-
-#define OP_Strlen            107
-#define OP_Substr            108
-
-#define OP_Limit             109
-
-#define OP_MAX               111
+#define OP_NextN              27
+
+#define OP_Destroy            28
+#define OP_Clear              29
+#define OP_CreateIndex        30
+#define OP_CreateTable        31
+#define OP_Reorganize         32
+
+#define OP_BeginIdx           33
+#define OP_NextIdx            34
+#define OP_IdxPut             35
+#define OP_IdxDelete          36
+#define OP_IdxRecno           37
+#define OP_IdxGT              38
+#define OP_IdxGE              39
+
+#define OP_MemLoad            40
+#define OP_MemStore           41
+
+#define OP_ListWrite          42
+#define OP_ListRewind         43
+#define OP_ListRead           44
+#define OP_ListReset          45
+
+#define OP_SortPut            46
+#define OP_SortMakeRec        47
+#define OP_SortMakeKey        48
+#define OP_Sort               49
+#define OP_SortNext           50
+#define OP_SortCallback       51
+#define OP_SortReset          52
+
+#define OP_FileOpen           53
+#define OP_FileRead           54
+#define OP_FileColumn         55
+
+#define OP_AggReset           56
+#define OP_AggFocus           57
+#define OP_AggIncr            58
+#define OP_AggNext            59
+#define OP_AggSet             60
+#define OP_AggGet             61
+
+#define OP_SetInsert          62
+#define OP_SetFound           63
+#define OP_SetNotFound        64
+
+#define OP_MakeRecord         65
+#define OP_MakeKey            66
+#define OP_MakeIdxKey         67
+#define OP_IncrKey            68
+
+#define OP_Goto               69
+#define OP_If                 70
+#define OP_Halt               71
+
+#define OP_ColumnCount        72
+#define OP_ColumnName         73
+#define OP_Callback           74
+#define OP_NullCallback       75
+
+#define OP_Integer            76
+#define OP_String             77
+#define OP_Pop                78
+#define OP_Dup                79
+#define OP_Pull               80
+
+#define OP_Add                81
+#define OP_AddImm             82
+#define OP_Subtract           83
+#define OP_Multiply           84
+#define OP_Divide             85
+#define OP_Remainder          86
+#define OP_BitAnd             87
+#define OP_BitOr              88
+#define OP_BitNot             89
+#define OP_ShiftLeft          90
+#define OP_ShiftRight         91
+#define OP_AbsValue           92
+#define OP_Precision          93
+#define OP_Min                94
+#define OP_Max                95
+#define OP_Like               96
+#define OP_Glob               97
+#define OP_Eq                 98
+#define OP_Ne                 99
+#define OP_Lt                100
+#define OP_Le                101
+#define OP_Gt                102
+#define OP_Ge                103
+#define OP_IsNull            104
+#define OP_NotNull           105
+#define OP_Negative          106
+#define OP_And               107
+#define OP_Or                108
+#define OP_Not               109
+#define OP_Concat            110
+#define OP_Noop              111
+
+#define OP_Strlen            112
+#define OP_Substr            113
+
+#define OP_Limit             114
+
+#define OP_MAX               114
 
 /*
 ** Prototypes for the VDBE interface.  See comments on the implementation