From c87fa69a2901b5c057e8119e73f420a1bf283613 Mon Sep 17 00:00:00 2001 From: drh Date: Sun, 19 Aug 2001 18:19:46 +0000 Subject: [PATCH] Add index access methods to the DBBE in preparation for adding a new DBBE for the btree.c module. (CVS 236) FossilOrigin-Name: c15f6ffc4d41f30a06d750c8015226713ae0126b --- manifest | 30 ++++----- manifest.uuid | 2 +- src/dbbe.h | 17 ++++- src/dbbegdbm.c | 128 +++++++++++++++++++++++++++++++++++-- src/dbbemem.c | 121 ++++++++++++++++++++++++++++++++++- src/vdbe.c | 160 ++++++++++------------------------------------ src/vdbe.h | 4 +- src/where.c | 4 +- test/index.test | 4 +- test/rowid.test | 6 +- test/select2.test | 6 +- test/where.test | 44 ++++++------- 12 files changed, 340 insertions(+), 186 deletions(-) diff --git a/manifest b/manifest index ddad4ce04e..0fe001ba43 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Version\s1.0.32\s(CVS\s471) -D 2001-07-23T14:35:00 +C Add\sindex\saccess\smethods\sto\sthe\sDBBE\sin\spreparation\sfor\sadding\sa\snew\nDBBE\sfor\sthe\sbtree.c\smodule.\s(CVS\s236) +D 2001-08-19T18:19:46 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 F Makefile.in a4595a83d56549b527dace5415729d20995f717b F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 @@ -17,9 +17,9 @@ F src/btree.c d6bbe3152ce3eb47ffd0c797897bf75c5ca784fc F src/btree.h 5fb5799bcb39900386ce6cae61fa33e357851ffe F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651 F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af -F src/dbbe.h 7235b15c6c5d8be0c4da469cef9620cee70b1cc8 -F src/dbbegdbm.c d75c45d39f15970c6e2881e955b799643649ebb1 -F src/dbbemem.c f76343d1ad1f92f1367536973e2c1d17c2f7686f +F src/dbbe.h bbb53eafcd1e3186597f6ee4a17ef2501f1b0628 +F src/dbbegdbm.c cbb6ebc79a7100324f07b67d4e867faca9f9efa9 +F src/dbbemem.c f4534a524e956b1db9af070b896040fc1b9cb80e F src/delete.c 40ddb169ee98013d976b2dadd140d98f7876f54f F src/ex/README b745b00acce2d892f60c40111dacdfc48e0c1c7a F src/ex/db.c f1419ae6c93e40b5ac6e39fe7efd95d868e6f9d7 @@ -49,9 +49,9 @@ F src/test1.c abb3cb427e735ae87e6533f5b3b7164b7da91bc4 F src/tokenize.c 0118b57702cb6550769316e8443b06760b067acf F src/update.c 0cf789656a936d4356668393267692fa4b03ffc6 F src/util.c 1b396ac34e30dd6222d82e996c17b161bbc906bc -F src/vdbe.c f93be4414ba892df9c5589815d2a57c1fb12c820 -F src/vdbe.h dc1205da434c6a9da03b5d6b089270bbc8e6d437 -F src/where.c 0c542fc44bd85152dfb8507862cfe2e60c629e9f +F src/vdbe.c b019394ebe0de12917a93ec06d787d8d909726cc +F src/vdbe.h 5331b9a3963d13af01a9cf749f57ac46727bdbe6 +F src/where.c a49083e59358bac83c80cf0d19626d09bab629bd F test/all.test 21d55a97e39e7ec5776751dc9dd8b1b51ef4a048 F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb F test/dbbe.test a022fe2d983848f786e17ef1fc6809cfd37fb02c @@ -59,7 +59,7 @@ F test/delete.test 50b9b1f06c843d591741dba7869433a105360dbf F test/expr.test 80bf8f0e9aa6b9c35bf97ce5d603a28381168d8a F test/func.test ac3def2a673d1042750ae1a4ad1768bb7c7ae90b F test/in.test ea48016c4fcc479d315932ae2b8568146686ffaf -F test/index.test b189ac11bf8d4fbcf87402f4028c25c8a6d91bb5 +F test/index.test 266474cd101d7ed3703a0fc0428145cedacc92e0 F test/insert.test dbd3bd189edb61fddbe66c236694ef23352429f1 F test/insert2.test 732405e30331635af8d159fccabe835eea5cd0c6 F test/lock.test bca7d53de73138b1f670a2fbdb1f481ff7eaa45a @@ -67,9 +67,9 @@ F test/main.test da635f9e078cd21ddf074e727381a715064489ff F test/malloc.test 3daa97f6a9577d8f4c6e468b274333af19ce5861 F test/printf.test 4c71871e1a75a2dacb673945fc13ddb30168798f F test/quote.test 40a3164af8456933a81312803fa8cdb21b205c12 -F test/rowid.test 128453599def7435e988216f7fe89c7450b8a9a3 +F test/rowid.test b01e6dec09780c93f55db6cfe7ad097323954f23 F test/select1.test 223507655cdb4f9901d83fa7f5c5328e022c211f -F test/select2.test 04ac3bd69298f58c7d0883159bab42ab9ad6021c +F test/select2.test 4cee2d9d4d7d4657b086569064a0c454e1795afe F test/select3.test a9234b8424b6c6d71de534f43b91ade9be68e9cc F test/select4.test cb5374d7c87680e294ac749307459a5cc547609d F test/select5.test e2b9d51d88cbd6c307c2c05b0ef55fe7ba811ac2 @@ -82,7 +82,7 @@ F test/tester.tcl 39a707dac2b6048d9c9e07a98d3256d50069fe47 F test/trans.test 51e50e8273da6845b31a2095e9d3b221fb60d8d0 F test/update.test 72c0c93310483b86dc904a992220c5b84c7ce100 F test/vacuum.test b95d8119a0a83dc6c4ac63888f8872f06199e065 -F test/where.test bbab5a308055fb6087dc23d600b4ad2b72797397 +F test/where.test 755957829c493b1b7ad1ecb27d6c782131a6b3d5 F tool/gdbmdump.c 529e67c78d920606ba196326ea55b57b75fcc82b F tool/gdbmstat.c 56a9033531e5f5a48413f6ec436d5fb0341632c1 F tool/lemon.c e007bfdbc79a51a4cd7c8a5f81f517cebd121150 @@ -107,7 +107,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2 F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad -P 770e983628d873039857c889ba302cf6926d19d9 -R eec7e6db07d9a5655c1c80f7d8ed8318 +P cfc86dc48afb6b7e052e418db1c596b665d5cc66 +R 79a41eb08d305d22b658e8f00e7f0110 U drh -Z 72bd26de798d42ee72d6abb10f413593 +Z 385160b9b18c8b4f775dcbb82eee9159 diff --git a/manifest.uuid b/manifest.uuid index 7b86480d73..181a107136 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cfc86dc48afb6b7e052e418db1c596b665d5cc66 \ No newline at end of file +c15f6ffc4d41f30a06d750c8015226713ae0126b \ No newline at end of file diff --git a/src/dbbe.h b/src/dbbe.h index 41442e4a44..1ab99a86bb 100644 --- a/src/dbbe.h +++ b/src/dbbe.h @@ -28,7 +28,7 @@ ** This library was originally designed to support the following ** backends: GDBM, NDBM, SDBM, Berkeley DB. ** -** $Id: dbbe.h,v 1.13 2001/04/04 11:48:57 drh Exp $ +** $Id: dbbe.h,v 1.14 2001/08/19 18:19:46 drh Exp $ */ #ifndef _SQLITE_DBBE_H_ #define _SQLITE_DBBE_H_ @@ -160,6 +160,21 @@ struct DbbeMethods { /* Rollback a transaction. */ int (*Rollback)(Dbbe*); + + /* Begin searching an index where the key is given. */ + int (*BeginIndex)(DbbeCursor*, int nKey, char *pKey); + + /* Return the integer key for the next index entry, or return 0 if + ** there are no more index entries. */ + int (*NextIndex)(DbbeCursor*); + + /* Add a new index entry to the file. The key and record number are + ** given. */ + int (*PutIndex)(DbbeCursor*, int nKey, char *pKey, int recno); + + /* Delete an index entry from the file. The key and record number are + ** given. */ + int (*DeleteIndex)(DbbeCursor*, int nKey, char *pKey, int recno); }; /* diff --git a/src/dbbegdbm.c b/src/dbbegdbm.c index 269cf00006..b1ee44cc99 100644 --- a/src/dbbegdbm.c +++ b/src/dbbegdbm.c @@ -30,7 +30,7 @@ ** relatively simple to convert to a different database such ** as NDBM, SDBM, or BerkeleyDB. ** -** $Id: dbbegdbm.c,v 1.8 2001/04/28 16:52:41 drh Exp $ +** $Id: dbbegdbm.c,v 1.9 2001/08/19 18:19:46 drh Exp $ */ #ifndef DISABLE_GDBM #include "sqliteInt.h" @@ -87,6 +87,7 @@ struct DbbeCursor { BeFile *pFile; /* The database file for this table */ datum key; /* Most recently used key */ datum data; /* Most recent data */ + int nextIndex; /* Next index entry to search */ int needRewind; /* Next key should be the first */ int readPending; /* The fetch hasn't actually been done yet */ }; @@ -334,18 +335,18 @@ static void sqliteGdbmCloseCursor(DbbeCursor *pCursr){ ** Reorganize a table to reduce search times and disk usage. */ static int sqliteGdbmReorganizeTable(Dbbe *pBe, const char *zTable){ - DbbeCursor *pCrsr; + DbbeCursor *pCursr; int rc; - rc = sqliteGdbmOpenCursor(pBe, zTable, 1, 0, &pCrsr); + rc = sqliteGdbmOpenCursor(pBe, zTable, 1, 0, &pCursr); if( rc!=SQLITE_OK ){ return rc; } - if( pCrsr && pCrsr->pFile && pCrsr->pFile->dbf ){ - gdbm_reorganize(pCrsr->pFile->dbf); + if( pCursr && pCursr->pFile && pCursr->pFile->dbf ){ + gdbm_reorganize(pCursr->pFile->dbf); } - if( pCrsr ){ - sqliteGdbmCloseCursor(pCrsr); + if( pCursr ){ + sqliteGdbmCloseCursor(pCursr); } return SQLITE_OK; } @@ -586,7 +587,116 @@ static int sqliteGdbmEndTrans(Dbbe *pDbbe){ return SQLITE_OK; } +/* +** Begin scanning an index for the given key. Return 1 on success and +** 0 on failure. +*/ +static int sqliteGdbmBeginIndex(DbbeCursor *pCursr, int nKey, char *pKey){ + if( !sqliteGdbmFetch(pCursr, nKey, pKey) ) return 0; + pCursr->nextIndex = 0; + return 1; +} +/* +** Return an integer key which is the next record number in the index search +** that was started by a prior call to BeginIndex. Return 0 if all records +** have already been searched. +*/ +static int sqliteGdbmNextIndex(DbbeCursor *pCursr){ + int *aIdx; + int nIdx; + int k; + nIdx = pCursr->data.dsize/sizeof(int); + aIdx = (int*)pCursr->data.dptr; + if( nIdx>1 ){ + k = *(aIdx++); + if( k>nIdx-1 ) k = nIdx-1; + }else{ + k = nIdx; + } + while( pCursr->nextIndex < k ){ + int recno = aIdx[pCursr->nextIndex++]; + if( recno!=0 ) return recno; + } + pCursr->nextIndex = 0; + return 0; +} + +/* +** Write a new record number and key into an index table. Return a status +** code. +*/ +static int sqliteGdbmPutIndex(DbbeCursor *pCursr, int nKey, char *pKey, int N){ + int r = sqliteGdbmFetch(pCursr, nKey, pKey); + if( r==0 ){ + /* Create a new record for this index */ + sqliteGdbmPut(pCursr, nKey, pKey, sizeof(int), (char*)&N); + }else{ + /* Extend the existing record */ + int nIdx; + int *aIdx; + int k; + + nIdx = pCursr->data.dsize/sizeof(int); + if( nIdx==1 ){ + aIdx = sqliteMalloc( sizeof(int)*4 ); + if( aIdx==0 ) return SQLITE_NOMEM; + aIdx[0] = 2; + sqliteGdbmCopyData(pCursr, 0, sizeof(int), (char*)&aIdx[1]); + aIdx[2] = N; + sqliteGdbmPut(pCursr, nKey, pKey, sizeof(int)*4, (char*)aIdx); + sqliteFree(aIdx); + }else{ + aIdx = (int*)sqliteGdbmReadData(pCursr, 0); + k = aIdx[0]; + if( kdata.dsize/sizeof(int); + aIdx = (int*)sqliteGdbmReadData(pCursr, 0); + if( (nIdx==1 && aIdx[0]==N) || (aIdx[0]==1 && aIdx[1]==N) ){ + sqliteGdbmDelete(pCursr, nKey, pKey); + }else{ + k = aIdx[0]; + for(j=1; j<=k && aIdx[j]!=N; j++){} + if( j>k ) return SQLITE_OK; + aIdx[j] = aIdx[k]; + aIdx[k] = 0; + aIdx[0]--; + if( aIdx[0]*3 + 1 < nIdx ){ + nIdx /= 2; + } + sqliteGdbmPut(pCursr, nKey, pKey, sizeof(int)*nIdx, (char*)aIdx); + } + return SQLITE_OK; +} /* ** This variable contains pointers to all of the access methods @@ -614,6 +724,10 @@ static struct DbbeMethods gdbmMethods = { /* BeginTrans */ sqliteGdbmBeginTrans, /* Commit */ sqliteGdbmEndTrans, /* Rollback */ sqliteGdbmEndTrans, + /* BeginIndex */ sqliteGdbmBeginIndex, + /* NextIndex */ sqliteGdbmNextIndex, + /* PutIndex */ sqliteGdbmPutIndex, + /* DeleteIndex */ sqliteGdbmDeleteIndex, }; diff --git a/src/dbbemem.c b/src/dbbemem.c index d5c8220d31..54f18b2283 100644 --- a/src/dbbemem.c +++ b/src/dbbemem.c @@ -30,7 +30,7 @@ ** Nothing is ever written to disk using this backend. All information ** is forgotten when the program exits. ** -** $Id: dbbemem.c,v 1.15 2001/04/28 16:52:42 drh Exp $ +** $Id: dbbemem.c,v 1.16 2001/08/19 18:19:46 drh Exp $ */ #include "sqliteInt.h" #include @@ -371,6 +371,7 @@ struct DbbeCursor { MTable *pTble; /* The database file for this table */ ArrayElem *elem; /* Most recently accessed record */ int needRewind; /* Next key should be the first */ + int nextIndex; /* Next recno in an index entry */ }; /* @@ -722,6 +723,117 @@ static int sqliteMemDelete(DbbeCursor *pCursr, int nKey, char *pKey){ return SQLITE_OK; } +/* +** Begin scanning an index for the given key. Return 1 on success and +** 0 on failure. +*/ +static int sqliteMemBeginIndex(DbbeCursor *pCursr, int nKey, char *pKey){ + if( !sqliteMemFetch(pCursr, nKey, pKey) ) return 0; + pCursr->nextIndex = 0; + return 1; +} + +/* +** Return an integer key which is the next record number in the index search +** that was started by a prior call to BeginIndex. Return 0 if all records +** have already been searched. +*/ +static int sqliteMemNextIndex(DbbeCursor *pCursr){ + int *aIdx; + int nIdx; + int k; + nIdx = sqliteMemDataLength(pCursr)/sizeof(int); + aIdx = (int*)sqliteMemReadData(pCursr, 0); + if( nIdx>1 ){ + k = *(aIdx++); + if( k>nIdx-1 ) k = nIdx-1; + }else{ + k = nIdx; + } + while( pCursr->nextIndex < k ){ + int recno = aIdx[pCursr->nextIndex++]; + if( recno!=0 ) return recno; + } + pCursr->nextIndex = 0; + return 0; +} + +/* +** Write a new record number and key into an index table. Return a status +** code. +*/ +static int sqliteMemPutIndex(DbbeCursor *pCursr, int nKey, char *pKey, int N){ + int r = sqliteMemFetch(pCursr, nKey, pKey); + if( r==0 ){ + /* Create a new record for this index */ + sqliteMemPut(pCursr, nKey, pKey, sizeof(int), (char*)&N); + }else{ + /* Extend the existing record */ + int nIdx; + int *aIdx; + int k; + + nIdx = sqliteMemDataLength(pCursr)/sizeof(int); + if( nIdx==1 ){ + aIdx = sqliteMalloc( sizeof(int)*4 ); + if( aIdx==0 ) return SQLITE_NOMEM; + aIdx[0] = 2; + sqliteMemCopyData(pCursr, 0, sizeof(int), (char*)&aIdx[1]); + aIdx[2] = N; + sqliteMemPut(pCursr, nKey, pKey, sizeof(int)*4, (char*)aIdx); + sqliteFree(aIdx); + }else{ + aIdx = (int*)sqliteMemReadData(pCursr, 0); + k = aIdx[0]; + if( kk ) return SQLITE_OK; + aIdx[j] = aIdx[k]; + aIdx[k] = 0; + aIdx[0]--; + if( aIdx[0]*3 + 1 < nIdx ){ + nIdx /= 2; + } + sqliteMemPut(pCursr, nKey, pKey, sizeof(int)*nIdx, (char*)aIdx); + } + return SQLITE_OK; +} + /* ** This variable contains pointers to all of the access methods ** used to implement the MEMORY backend. @@ -745,6 +857,13 @@ static struct DbbeMethods memoryMethods = { /* New */ sqliteMemNew, /* Put */ sqliteMemPut, /* Delete */ sqliteMemDelete, + /* BeginTrans */ 0, + /* Commit */ 0, + /* Rollback */ 0, + /* BeginIndex */ sqliteMemBeginIndex, + /* NextIndex */ sqliteMemNextIndex, + /* PutIndex */ sqliteMemPutIndex, + /* DeleteIndex */ sqliteMemDeleteIndex, }; /* diff --git a/src/vdbe.c b/src/vdbe.c index 0458bcfcfb..e13e32bdb8 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -41,7 +41,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.58 2001/04/28 16:52:42 drh Exp $ +** $Id: vdbe.c,v 1.59 2001/08/19 18:19:46 drh Exp $ */ #include "sqliteInt.h" #include @@ -822,7 +822,7 @@ static char *zOpName[] = { 0, "Fcnt", "New", "Put", "Distinct", "Found", "NotFound", "Delete", "Field", "KeyAsData", "Key", "FullKey", "Rewind", - "Next", "Destroy", "Reorganize", "ResetIdx", + "Next", "Destroy", "Reorganize", "BeginIdx", "NextIdx", "PutIdx", "DeleteIdx", "MemLoad", "MemStore", "ListOpen", "ListWrite", "ListRewind", "ListRead", "ListClose", "SortOpen", "SortPut", @@ -2245,35 +2245,33 @@ int sqliteVdbeExec( break; } - /* Opcode: ResetIdx P1 * * + /* Opcode: BeginIdx P1 * * ** - ** Begin treating the current data in cursor P1 as a bunch of integer - ** keys to records of a (separate) SQL table file. This instruction - ** causes the new NextIdx instruction push the first integer table - ** key in the data. + ** Begin searching an index for records with the key found on the + ** top of the stack. The stack is popped once. Subsequent calls + ** to NextIdx will push record numbers onto the stack until all + ** records with the same key have been returned. */ - case OP_ResetIdx: { + case OP_BeginIdx: { int i = pOp->p1; - if( i>=0 && inCursor ){ - p->aCsr[i].index = 0; + int tos = p->tos; + VERIFY( if( tos<0 ) goto not_enough_stack; ) + if( i>=0 && inCursor && p->aCsr[i].pCursor ){ + if( Stringify(p, tos) ) goto no_mem; + pBex->BeginIndex(p->aCsr[i].pCursor, aStack[tos].n, zStack[tos]); + p->aCsr[i].keyIsValid = 0; } + POPSTACK; break; } /* Opcode: NextIdx P1 P2 * ** - ** The P1 cursor points to an SQL index. The data from the most - ** recent fetch on that cursor consists of a bunch of integers where - ** each integer is the key to a record in an SQL table file. - ** This instruction grabs the next integer table key from the data - ** of P1 and pushes that integer onto the stack. The first time - ** this instruction is executed after a fetch, the first integer - ** table key is pushed. Subsequent integer table keys are pushed - ** in each subsequent execution of this instruction. - ** - ** If there are no more integer table keys in the data of P1 - ** when this instruction is executed, then nothing gets pushed and - ** there is an immediate jump to instruction P2. + ** The P1 cursor points to an SQL index for which a BeginIdx operation + ** has been issued. This operation retrieves the next record number and + ** pushes that record number onto the stack. Or, if there are no more + ** record numbers for the given key, this opcode pushes nothing onto the + ** stack but instead jumps to instruction P2. */ case OP_NextIdx: { int i = pOp->p1; @@ -2283,32 +2281,15 @@ int sqliteVdbeExec( VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) zStack[tos] = 0; if( VERIFY( i>=0 && inCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ - int *aIdx; - int nIdx; - int j, k; - nIdx = pBex->DataLength(pCrsr)/sizeof(int); - aIdx = (int*)pBex->ReadData(pCrsr, 0); - if( nIdx>1 ){ - k = *(aIdx++); - if( k>nIdx-1 ) k = nIdx-1; + int recno = pBex->NextIndex(pCrsr); + if( recno!=0 ){ + p->aCsr[i].lastKey = aStack[tos].i = recno; + p->aCsr[i].keyIsValid = 1; + aStack[tos].flags = STK_Int; }else{ - k = nIdx; - } - p->aCsr[i].keyIsValid = 0; - for(j=p->aCsr[i].index; jaCsr[i].lastKey = aIdx[j]; - p->aCsr[i].keyIsValid = 1; - aStack[tos].flags = STK_Int; - break; - } - } - if( j>=k ){ - j = -1; pc = pOp->p2 - 1; POPSTACK; } - p->aCsr[i].index = j+1; } break; } @@ -2317,10 +2298,9 @@ int sqliteVdbeExec( ** ** The top of the stack hold an SQL index key (probably made using the ** MakeKey instruction) and next on stack holds an integer which - ** the key to an SQL table entry. Locate the record in cursor P1 - ** that has the same key as on the TOS. Create a new record if - ** necessary. Then append the integer table key to the data for that - ** record and write it back to the P1 file. + ** the record number for an SQL table entry. This opcode makes an entry + ** in the index table P1 that associates the key with the record number. + ** But the record number and the key are popped from the stack. */ case OP_PutIdx: { int i = pOp->p1; @@ -2329,53 +2309,9 @@ int sqliteVdbeExec( DbbeCursor *pCrsr; VERIFY( if( nos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && inCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ - int r; - int newVal; Integerify(p, nos); - newVal = aStack[nos].i; if( Stringify(p, tos) ) goto no_mem; - r = pBex->Fetch(pCrsr, aStack[tos].n, zStack[tos]); - if( r==0 ){ - /* Create a new record for this index */ - pBex->Put(pCrsr, aStack[tos].n, zStack[tos], - sizeof(int), (char*)&newVal); - }else{ - /* Extend the existing record */ - int nIdx; - int *aIdx; - int k; - - nIdx = pBex->DataLength(pCrsr)/sizeof(int); - if( nIdx==1 ){ - aIdx = sqliteMalloc( sizeof(int)*4 ); - if( aIdx==0 ) goto no_mem; - aIdx[0] = 2; - pBex->CopyData(pCrsr, 0, sizeof(int), (char*)&aIdx[1]); - aIdx[2] = newVal; - pBex->Put(pCrsr, aStack[tos].n, zStack[tos], - sizeof(int)*4, (char*)aIdx); - sqliteFree(aIdx); - }else{ - aIdx = (int*)pBex->ReadData(pCrsr, 0); - k = aIdx[0]; - if( kPut(pCrsr, aStack[tos].n, zStack[tos], - sizeof(int)*nIdx, (char*)aIdx); - }else{ - nIdx *= 2; - aIdx = sqliteMalloc( sizeof(int)*nIdx ); - if( aIdx==0 ) goto no_mem; - pBex->CopyData(pCrsr, 0, sizeof(int)*(k+1), (char*)aIdx); - aIdx[k+1] = newVal; - aIdx[0]++; - pBex->Put(pCrsr, aStack[tos].n, zStack[tos], - sizeof(int)*nIdx, (char*)aIdx); - sqliteFree(aIdx); - } - } - } + pBex->PutIndex(pCrsr, aStack[tos].n, zStack[tos], aStack[nos].i); } POPSTACK; POPSTACK; @@ -2385,15 +2321,9 @@ int sqliteVdbeExec( /* Opcode: DeleteIdx P1 * * ** ** The top of the stack is a key and next on stack is integer - ** which is the key to a record in an SQL table. - ** Locate the record in the cursor P1 (P1 represents an SQL index) - ** that has the same key as the top of stack. Then look through - ** the integer table-keys contained in the data of the P1 record. - ** Remove the integer table-key that matches the NOS and write the - ** revised data back to P1 with the same key. - ** - ** If this routine removes the very last integer table-key from - ** the P1 data, then the corresponding P1 record is deleted. + ** which is a record number for an SQL table. The operation removes + ** any entry to the index table P1 that associates the key with the + ** record number. */ case OP_DeleteIdx: { int i = pOp->p1; @@ -2402,33 +2332,9 @@ int sqliteVdbeExec( DbbeCursor *pCrsr; VERIFY( if( nos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && inCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ - int *aIdx; - int nIdx; - int j, k; - int r; - int oldVal; Integerify(p, nos); - oldVal = aStack[nos].i; if( Stringify(p, tos) ) goto no_mem; - r = pBex->Fetch(pCrsr, aStack[tos].n, zStack[tos]); - if( r==0 ) break; - nIdx = pBex->DataLength(pCrsr)/sizeof(int); - aIdx = (int*)pBex->ReadData(pCrsr, 0); - if( (nIdx==1 && aIdx[0]==oldVal) || (aIdx[0]==1 && aIdx[1]==oldVal) ){ - pBex->Delete(pCrsr, aStack[tos].n, zStack[tos]); - }else{ - k = aIdx[0]; - for(j=1; j<=k && aIdx[j]!=oldVal; j++){} - if( j>k ) break; - aIdx[j] = aIdx[k]; - aIdx[k] = 0; - aIdx[0]--; - if( aIdx[0]*3 + 1 < nIdx ){ - nIdx /= 2; - } - pBex->Put(pCrsr, aStack[tos].n, zStack[tos], - sizeof(int)*nIdx, (char*)aIdx); - } + pBex->DeleteIndex(pCrsr, aStack[tos].n, zStack[tos], aStack[nos].i); } POPSTACK; POPSTACK; diff --git a/src/vdbe.h b/src/vdbe.h index 6f5c343a46..d8459bef71 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -27,7 +27,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.17 2001/04/04 11:48:58 drh Exp $ +** $Id: vdbe.h,v 1.18 2001/08/19 18:19:46 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -92,7 +92,7 @@ typedef struct VdbeOp VdbeOp; #define OP_Destroy 18 #define OP_Reorganize 19 -#define OP_ResetIdx 20 +#define OP_BeginIdx 20 #define OP_NextIdx 21 #define OP_PutIdx 22 #define OP_DeleteIdx 23 diff --git a/src/where.c b/src/where.c index 13914fc23a..9f8a92433a 100644 --- a/src/where.c +++ b/src/where.c @@ -25,7 +25,7 @@ ** the WHERE clause of SQL statements. Also found here are subroutines ** to generate VDBE code to evaluate expressions. ** -** $Id: where.c,v 1.14 2001/04/11 14:28:43 drh Exp $ +** $Id: where.c,v 1.15 2001/08/19 18:19:46 drh Exp $ */ #include "sqliteInt.h" @@ -385,7 +385,7 @@ WhereInfo *sqliteWhereBegin( } } sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0); - sqliteVdbeAddOp(v, OP_Fetch, base+pTabList->nId+i, 0, 0, 0); + sqliteVdbeAddOp(v, OP_BeginIdx, base+pTabList->nId+i, 0, 0, 0); sqliteVdbeAddOp(v, OP_NextIdx, base+pTabList->nId+i, brk, 0, cont); if( i==pTabList->nId-1 && pushKey ){ haveKey = 1; diff --git a/test/index.test b/test/index.test index eec1b5746b..79d54a8c43 100644 --- a/test/index.test +++ b/test/index.test @@ -23,7 +23,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE INDEX statement. # -# $Id: index.test,v 1.9 2001/04/04 11:48:58 drh Exp $ +# $Id: index.test,v 1.10 2001/08/19 18:19:46 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -349,6 +349,6 @@ do_test index-11.1 { execsql "INSERT INTO t3 VALUES('x${i}x',$i,0.$i)" } execsql {SELECT c, fcnt() FROM t3 WHERE b==10} -} {0.10 2} +} {0.10 1} finish_test diff --git a/test/rowid.test b/test/rowid.test index a12b31a11e..14ba42bf75 100644 --- a/test/rowid.test +++ b/test/rowid.test @@ -24,7 +24,7 @@ # focus of this file is testing the magic ROWID column that is # found on all tables. # -# $Id: rowid.test,v 1.1 2001/04/04 11:48:58 drh Exp $ +# $Id: rowid.test,v 1.2 2001/08/19 18:19:46 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -247,13 +247,13 @@ do_test rowid-4.5 { SELECT t1.x, fcnt() FROM t2, t1 WHERE t2.y==256 AND t1.rowid==t2.rowid } -} {4 3} +} {4 2} do_test rowid-4.5.1 { execsql { SELECT t1.x, fcnt() FROM t2, t1 WHERE t1.OID==t2.rowid AND t2.y==81 } -} {3 3} +} {3 2} do_test rowid-4.6 { execsql { SELECT t1.x FROM t1, t2 diff --git a/test/select2.test b/test/select2.test index fd108ef082..ef1ffb204a 100644 --- a/test/select2.test +++ b/test/select2.test @@ -23,7 +23,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the SELECT statement. # -# $Id: select2.test,v 1.10 2001/03/15 18:21:22 drh Exp $ +# $Id: select2.test,v 1.11 2001/08/19 18:19:46 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -105,10 +105,10 @@ do_test select2-3.2c { } {500} do_test select2-3.2d { execsql {SELECT fcnt() FROM tbl2 WHERE 1000=f2} -} {2} +} {1} do_test select2-3.2e { execsql {SELECT fcnt() FROM tbl2 WHERE f2=1000} -} {2} +} {1} # omit the time-dependent tests # diff --git a/test/where.test b/test/where.test index 8ee4d0d18e..33e7a664ec 100644 --- a/test/where.test +++ b/test/where.test @@ -23,7 +23,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the use of indices in WHERE clases. # -# $Id: where.test,v 1.1 2000/06/12 12:20:49 drh Exp $ +# $Id: where.test,v 1.2 2001/08/19 18:19:46 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -59,37 +59,37 @@ do_test where-1.0 { # do_test where-1.1 { execsql {SELECT x, y, fcnt(*) FROM t1 WHERE w=10} -} {3 121 2} +} {3 121 1} do_test where-1.2 { execsql {SELECT x, y, fcnt(*) FROM t1 WHERE w=11} -} {3 144 2} +} {3 144 1} do_test where-1.3 { execsql {SELECT x, y, fcnt(*) FROM t1 WHERE 11=w} -} {3 144 2} +} {3 144 1} do_test where-1.4 { execsql {SELECT x, y, fcnt(*) FROM t1 WHERE 11=w AND x>2} -} {3 144 2} +} {3 144 1} do_test where-1.5 { execsql {SELECT x, y, fcnt(*) FROM t1 WHERE y<200 AND w=11 AND x>2} -} {3 144 2} +} {3 144 1} do_test where-1.6 { execsql {SELECT x, y, fcnt(*) FROM t1 WHERE y<200 AND x>2 AND w=11} -} {3 144 2} +} {3 144 1} do_test where-1.7 { execsql {SELECT x, y, fcnt(*) FROM t1 WHERE w=11 AND y<200 AND x>2} -} {3 144 2} +} {3 144 1} do_test where-1.8 { execsql {SELECT x, y, fcnt(*) FROM t1 WHERE w>10 AND y=144 AND x=3} -} {3 144 2} +} {3 144 1} do_test where-1.9 { execsql {SELECT x, y, fcnt(*) FROM t1 WHERE y=144 AND w>10 AND x=3} -} {3 144 2} +} {3 144 1} do_test where-1.10 { execsql {SELECT x, y, fcnt(*) FROM t1 WHERE x=3 AND w>=10 AND y=121} -} {3 121 2} +} {3 121 1} do_test where-1.11 { execsql {SELECT x, y, fcnt(*) FROM t1 WHERE x=3 AND y=100 AND w<10} -} {3 100 2} +} {3 100 1} # Do the same kind of thing except use a join as the data source. # @@ -98,43 +98,43 @@ do_test where-2.1 { SELECT w, p, fcnt(*) FROM t2, t1 WHERE x=q AND y=s AND r=8977 } -} {34 67 4} +} {34 67 2} do_test where-2.2 { execsql { SELECT w, p, fcnt(*) FROM t2, t1 WHERE x=q AND s=y AND r=8977 } -} {34 67 4} +} {34 67 2} do_test where-2.3 { execsql { SELECT w, p, fcnt(*) FROM t2, t1 WHERE x=q AND s=y AND r=8977 AND w>10 } -} {34 67 4} +} {34 67 2} do_test where-2.4 { execsql { SELECT w, p, fcnt(*) FROM t2, t1 WHERE p<80 AND x=q AND s=y AND r=8977 AND w>10 } -} {34 67 4} +} {34 67 2} do_test where-2.5 { execsql { SELECT w, p, fcnt(*) FROM t2, t1 WHERE p<80 AND x=q AND 8977=r AND s=y AND w>10 } -} {34 67 4} +} {34 67 2} do_test where-2.6 { execsql { SELECT w, p, fcnt(*) FROM t2, t1 WHERE x=q AND p=77 AND s=y AND w>5 } -} {24 77 4} +} {24 77 2} do_test where-2.7 { execsql { SELECT w, p, fcnt(*) FROM t1, t2 WHERE x=q AND p>77 AND s=y AND w=5 } -} {5 96 4} +} {5 96 2} # Lets do a 3-way join. # @@ -143,18 +143,18 @@ do_test where-3.1 { SELECT A.w, B.p, C.w, fcnt(*) FROM t1 as A, t2 as B, t1 as C WHERE C.w=101-B.p AND B.r=10202-A.y AND A.w=11 } -} {11 90 11 6} +} {11 90 11 3} do_test where-3.2 { execsql { SELECT A.w, B.p, C.w, fcnt(*) FROM t1 as A, t2 as B, t1 as C WHERE C.w=101-B.p AND B.r=10202-A.y AND A.w=12 } -} {12 89 12 6} +} {12 89 12 3} do_test where-3.3 { execsql { SELECT A.w, B.p, C.w, fcnt(*) FROM t1 as A, t2 as B, t1 as C WHERE A.w=15 AND B.p=C.w AND B.r=10202-A.y } -} {15 86 86 6} +} {15 86 86 3} finish_test