diff --git a/manifest b/manifest index 7f9b9adba6..aa73e89149 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 9dff5c9c91..78c332e81c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -177012249ae93dbea4a11fb50faaae7912848bd0 \ No newline at end of file +e6ca23fa4569bc33065bf57ce7ce6132cd6a9de0 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index aea978b04f..cc6ddf8cfd 100644 --- a/src/btree.c +++ b/src/btree.c @@ -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 pCur0 This means pCur>pKey ** -** If pCur contains N bytes where N0 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->idxpPage->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 = nKeyMX_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 = nKeyOVERFLOW_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 pCurpKey. -** -** 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; diff --git a/src/btree.h b/src/btree.h index 0769e405ba..b468a55367 100644 --- a/src/btree.h +++ b/src/btree.h @@ -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*); diff --git a/src/build.c b/src/build.c index bec84b6f44..c9fea4ecdf 100644 --- a/src/build.c +++ b/src/build.c @@ -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 @@ -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); diff --git a/src/delete.c b/src/delete.c index 62dc19f570..5654b6ccef 100644 --- a/src/delete.c +++ b/src/delete.c @@ -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); diff --git a/src/insert.c b/src/insert.c index 8f93d5cebd..50e095797e 100644 --- a/src/insert.c +++ b/src/insert.c @@ -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); } diff --git a/src/select.c b/src/select.c index 271fbb1586..9ff90043e9 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.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 diff --git a/src/update.c b/src/update.c index b4dea0ddea..9cc967a113 100644 --- a/src/update.c +++ b/src/update.c @@ -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. diff --git a/src/vdbe.c b/src/vdbe.c index 5aea72e670..ba6fc566a5 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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 @@ -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 && inCursor && ) (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 && inCursor && ) (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 && inCursor && ) (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; } diff --git a/src/vdbe.h b/src/vdbe.h index d835b2a113..7d3aac1578 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -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_NextN 27 -#define OP_Destroy 27 -#define OP_Clear 28 -#define OP_CreateIndex 29 -#define OP_CreateTable 30 -#define OP_Reorganize 31 +#define OP_Destroy 28 +#define OP_Clear 29 +#define OP_CreateIndex 30 +#define OP_CreateTable 31 +#define OP_Reorganize 32 -#define OP_BeginIdx 32 -#define OP_NextIdx 33 -#define OP_PutIdx 34 -#define OP_DeleteIdx 35 +#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 36 -#define OP_MemStore 37 +#define OP_MemLoad 40 +#define OP_MemStore 41 -#define OP_ListWrite 38 -#define OP_ListRewind 39 -#define OP_ListRead 40 -#define OP_ListReset 41 +#define OP_ListWrite 42 +#define OP_ListRewind 43 +#define OP_ListRead 44 +#define OP_ListReset 45 -#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_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 49 -#define OP_FileRead 50 -#define OP_FileColumn 51 +#define OP_FileOpen 53 +#define OP_FileRead 54 +#define OP_FileColumn 55 -#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_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 58 -#define OP_SetFound 59 -#define OP_SetNotFound 60 +#define OP_SetInsert 62 +#define OP_SetFound 63 +#define OP_SetNotFound 64 -#define OP_MakeRecord 61 -#define OP_MakeKey 62 -#define OP_MakeIdxKey 63 +#define OP_MakeRecord 65 +#define OP_MakeKey 66 +#define OP_MakeIdxKey 67 +#define OP_IncrKey 68 -#define OP_Goto 64 -#define OP_If 65 -#define OP_Halt 66 +#define OP_Goto 69 +#define OP_If 70 +#define OP_Halt 71 -#define OP_ColumnCount 67 -#define OP_ColumnName 68 -#define OP_Callback 69 -#define OP_NullCallback 70 +#define OP_ColumnCount 72 +#define OP_ColumnName 73 +#define OP_Callback 74 +#define OP_NullCallback 75 -#define OP_Integer 71 -#define OP_String 72 -#define OP_Pop 73 -#define OP_Dup 74 -#define OP_Pull 75 +#define OP_Integer 76 +#define OP_String 77 +#define OP_Pop 78 +#define OP_Dup 79 +#define OP_Pull 80 -#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_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 107 -#define OP_Substr 108 +#define OP_Strlen 112 +#define OP_Substr 113 -#define OP_Limit 109 +#define OP_Limit 114 -#define OP_MAX 111 +#define OP_MAX 114 /* ** Prototypes for the VDBE interface. See comments on the implementation