diff --git a/manifest b/manifest index 4a0b7cfdf2..7592083adc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C A\spartial\sfix\sfor\sticket\s#3292.\s\sThis\sfixes\sthe\soriginal\sproblem\sbut\sthere\nare\sother\ssimilar\sproblems\slurking\sin\sthe\scode\sstill.\s(CVS\s5561) -D 2008-08-13T14:07:40 +C Additional\schanges\stoward\sfixing\sticket\s#3292.\s(CVS\s5562) +D 2008-08-13T19:11:48 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in 2713ea64947be3b35f35d9a3158bb8299c90b019 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -96,8 +96,8 @@ F src/attach.c a85c14612e7e3410e0c3d2e0241832fa9688bd14 F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/bitvec.c 95c86bd18d8fedf0533f5af196192546e10a7e7d F src/btmutex.c 709cad2cdca0afd013f0f612363810e53f59ec53 -F src/btree.c 2ae1092eee58d2d89e5d2f59f711f805dec59bbc -F src/btree.h 03256ed7ee42b5ecacbe887070b0f8249e7d069d +F src/btree.c c38431aed9dcdf62916c9009d6f9971e588189fe +F src/btree.h 6371c5e599fab391a150c96afbc10062b276d107 F src/btreeInt.h ab18c7b4980314e9e4b402e5dcde09f3c2545576 F src/build.c 931ed94fd3bbd67b6ac9d5ac6a45dc01e9f01726 F src/callback.c c9f75a4c403f166af3761df47d78a806587d63af @@ -146,14 +146,14 @@ F src/select.c 390d1bdde0c24f0225e369896da8e60ef2aeffbe F src/shell.c d83b578a8ccdd3e0e7fef4388a0887ce9f810967 F src/sqlite.h.in 54e51c22e2294c5989156b0aec87aa44168ac1f0 F src/sqlite3ext.h 1e3887c9bd3ae66cb599e922824b04cd0d0f2c3e -F src/sqliteInt.h df48efd8c4cb7b833bd7299a41c59c6651be0072 +F src/sqliteInt.h 7c68cacc760e8038ba6221c4d9ee3a7f0580e181 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/status.c 8caa772cd9310bc297280f7cf0ede4d69ed5b801 F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8 F src/tclsqlite.c ec46084184f033ba396a9ee7b5514b695083d0f3 F src/test1.c 0ae2203b03dec8ecf8ad731038df47ba27bfe68c F src/test2.c 7a634c1e044be3ea5845e65155fdd1cab13936cb -F src/test3.c e00795839be38f0345a4845170426fb17d828bf9 +F src/test3.c e85b7ce5c28c3ce7fbdbf7f98e1467b19786c62b F src/test4.c 41056378671e7b00e6305fa9ac6fa27e6f96f406 F src/test5.c 162a1cea2105a2c460a3f39fa6919617b562a288 F src/test6.c 0a0304a69cfa4962a429d084c6d451ff9e4fb572 @@ -183,11 +183,11 @@ F src/update.c 79b77a3cc8ed5f8903a7f37055fcedd69388dcae F src/utf.c c63e6f69082f85c19ab88d62dedaf91d71ac1a50 F src/util.c afe659ccc05d1f8af9e8631dabfec3ee3a7144af F src/vacuum.c ef342828002debc97514617af3424aea8ef8522c -F src/vdbe.c cda10a8e6ac05c783d6cd8a1d4852754fa73cf3b -F src/vdbe.h ccca49ce3db3486ae27f9baec68a77ccc29c43a9 -F src/vdbeInt.h 6f04c2bf65a0d5c2bb8318b226278a35d1f7a8f5 +F src/vdbe.c e2dd0c78c5579e23db49ed8265f0b44d7b22c51d +F src/vdbe.h 17bcc2b41082f9b99718b3757cbf97145a72023a +F src/vdbeInt.h b48c74d86a9fb62b707a3186ccca76bb32f1c6be F src/vdbeapi.c f21971516880fd3a10821b2cdd0e64a5a63952c9 -F src/vdbeaux.c 7b25fbbbdbd548b71c0a44d2f90fd3d0b06e70b8 +F src/vdbeaux.c 3e2e1f36c25eae32bdd605456c8be99f73e71eaf F src/vdbeblob.c f93110888ddc246215e9ba1f831d3d375bfd8355 F src/vdbefifo.c 20fda2a7c4c0bcee1b90eb7e545fefcdbf2e1de7 F src/vdbemem.c c37b2a266a49eaf0c0f5080157f9f1a908fdaac3 @@ -618,7 +618,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P d6aacc5dc7c06f97fb5faa3d85a8f2d8ab0dd554 -R 9b480ed8f28854c07567551a082c6f07 +P 055f173ab1b6fb657bf817faa3a37335d8fa60d5 +R 3660b918f4cbadc772ff6c9bb7d03fb8 U drh -Z d0f90d7840e7d910b5f941e8ef52ae1d +Z ef96eabf3e6f46a636feb3cbdfe8a28b diff --git a/manifest.uuid b/manifest.uuid index c7a7043d69..db4a82ec54 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -055f173ab1b6fb657bf817faa3a37335d8fa60d5 \ No newline at end of file +0b92cbf5255020d4fde382f81590ff0488936667 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index a75da9c615..f00422da43 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.496 2008/08/13 14:07:40 drh Exp $ +** $Id: btree.c,v 1.497 2008/08/13 19:11:48 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -375,7 +375,7 @@ int sqlite3BtreeRestoreCursorPosition(BtCursor *pCur){ return pCur->skip; } pCur->eState = CURSOR_INVALID; - rc = sqlite3BtreeMoveto(pCur, pCur->pKey, 0, pCur->nKey, 0, &pCur->skip); + rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skip); if( rc==SQLITE_OK ){ sqlite3_free(pCur->pKey); pCur->pKey = 0; @@ -3648,12 +3648,11 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ } /* Move the cursor so that it points to an entry near the key -** specified by pKey/nKey/pUnKey. Return a success code. +** specified by pIdxKey or intKey. Return a success code. ** -** For INTKEY tables, only the nKey parameter is used. pKey -** and pUnKey must be NULL. For index tables, either pUnKey -** must point to a key that has already been unpacked, or else -** pKey/nKey describes a blob containing the key. +** For INTKEY tables, the intKey parameter is used. pIdxKey +** must be NULL. For index tables, pIdxKey is used and intKey +** is ignored. ** ** If an exact match is not found, then the cursor is always ** left pointing at a leaf page which would hold the entry if it @@ -3675,16 +3674,14 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ ** is larger than pKey. ** */ -int sqlite3BtreeMoveto( - BtCursor *pCur, /* The cursor to be moved */ - const void *pKey, /* The key content for indices. Not used by tables */ - UnpackedRecord *pUnKey,/* Unpacked version of pKey */ - i64 nKey, /* Size of pKey. Or the key for tables */ - int biasRight, /* If true, bias the search to the high end */ - int *pRes /* Search result flag */ +int sqlite3BtreeMovetoUnpacked( + BtCursor *pCur, /* The cursor to be moved */ + UnpackedRecord *pIdxKey, /* Unpacked index key */ + i64 intKey, /* The table key */ + int biasRight, /* If true, bias the search to the high end */ + int *pRes /* Write search results here */ ){ int rc; - char aSpace[200]; assert( cursorHoldsMutex(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); @@ -3692,11 +3689,11 @@ int sqlite3BtreeMoveto( /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ if( pCur->eState==CURSOR_VALID && pCur->validNKey && pCur->pPage->intKey ){ - if( pCur->info.nKey==nKey ){ + if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK; } - if( pCur->atLast && pCur->info.nKeyatLast && pCur->info.nKeypPage->nCell==0 ); return SQLITE_OK; } - if( pCur->pPage->intKey ){ - /* We are given an SQL table to search. The key is the integer - ** rowid contained in nKey. pKey and pUnKey should both be NULL */ - assert( pUnKey==0 ); - assert( pKey==0 ); - }else if( pUnKey==0 ){ - /* We are to search an SQL index using a key encoded as a blob. - ** The blob is found at pKey and is nKey bytes in length. Unpack - ** this key so that we can use it. */ - assert( pKey!=0 ); - pUnKey = sqlite3VdbeRecordUnpack(pCur->pKeyInfo, nKey, pKey, - aSpace, sizeof(aSpace)); - if( pUnKey==0 ) return SQLITE_NOMEM; - }else{ - /* We are to search an SQL index using a key that is already unpacked - ** and handed to us in pUnKey. */ - assert( pKey==0 ); - } + assert( pCur->pPage->intKey || pIdxKey ); for(;;){ int lwr, upr; Pgno chldPg; @@ -3739,7 +3719,7 @@ int sqlite3BtreeMoveto( int c = -1; /* pRes return if table is empty must be -1 */ lwr = 0; upr = pPage->nCell-1; - if( !pPage->intKey && pUnKey==0 ){ + if( !pPage->intKey && pIdxKey==0 ){ rc = SQLITE_CORRUPT_BKPT; goto moveto_finish; } @@ -3761,12 +3741,12 @@ int sqlite3BtreeMoveto( pCell += getVarint32(pCell, dummy); } getVarint(pCell, (u64*)&nCellKey); - if( nCellKey==nKey ){ + if( nCellKey==intKey ){ c = 0; - }else if( nCellKeynKey ); + assert( nCellKey>intKey ); c = +1; } }else{ @@ -3774,7 +3754,7 @@ int sqlite3BtreeMoveto( pCellKey = (void *)fetchPayload(pCur, &available, 0); nCellKey = pCur->info.nKey; if( available>=nCellKey ){ - c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, 0, pUnKey); + c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, pIdxKey); }else{ pCellKey = sqlite3Malloc( nCellKey ); if( pCellKey==0 ){ @@ -3782,7 +3762,7 @@ int sqlite3BtreeMoveto( goto moveto_finish; } rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey); - c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, 0, pUnKey); + c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, pIdxKey); sqlite3_free(pCellKey); if( rc ) goto moveto_finish; } @@ -3832,10 +3812,35 @@ int sqlite3BtreeMoveto( if( rc ) goto moveto_finish; } moveto_finish: + return rc; +} + +/* +** In this version of BtreeMoveto, pKey is a packed index record +** such as is generated by the OP_MakeRecord opcode. Unpack the +** record and then call BtreeMovetoUnpacked() to do the work. +*/ +int sqlite3BtreeMoveto( + BtCursor *pCur, /* Cursor open on the btree to be searched */ + const void *pKey, /* Packed key if the btree is an index */ + i64 nKey, /* Integer key for tables. Size of pKey for indices */ + int bias, /* Bias search to the high end */ + int *pRes /* Write search results here */ +){ + int rc; /* Status code */ + UnpackedRecord *pIdxKey; /* Unpacked index key */ + char aSpace[200]; /* Temp space for pIdxKey - to avoid a malloc */ + if( pKey ){ - /* If we created our own unpacked key at the top of this - ** procedure, then destroy that key before returning. */ - sqlite3VdbeDeleteUnpackedRecord(pUnKey); + pIdxKey = sqlite3VdbeRecordUnpack(pCur->pKeyInfo, nKey, pKey, + aSpace, sizeof(aSpace)); + if( pIdxKey==0 ) return SQLITE_NOMEM; + }else{ + pIdxKey = 0; + } + rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes); + if( pKey ){ + sqlite3VdbeDeleteUnpackedRecord(pIdxKey); } return rc; } @@ -5836,7 +5841,7 @@ int sqlite3BtreeInsert( clearCursorPosition(pCur); if( SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) || - SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, 0, nKey, appendBias, &loc)) + SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, appendBias, &loc)) ){ return rc; } diff --git a/src/btree.h b/src/btree.h index 3fe01cbd23..5db917b5dc 100644 --- a/src/btree.h +++ b/src/btree.h @@ -13,7 +13,7 @@ ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** -** @(#) $Id: btree.h,v 1.102 2008/07/11 21:02:54 drh Exp $ +** @(#) $Id: btree.h,v 1.103 2008/08/13 19:11:48 drh Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ @@ -122,8 +122,6 @@ int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); void sqlite3BtreeTripAllCursors(Btree*, int); -struct UnpackedRecord; /* Forward declaration. Definition in vdbeaux.c. */ - int sqlite3BtreeCursor( Btree*, /* BTree containing table to open */ int iTable, /* Index of root page */ @@ -137,11 +135,17 @@ int sqlite3BtreeCloseCursor(BtCursor*); int sqlite3BtreeMoveto( BtCursor*, const void *pKey, - struct UnpackedRecord *pUnKey, i64 nKey, int bias, int *pRes ); +int sqlite3BtreeMovetoUnpacked( + BtCursor*, + UnpackedRecord *pUnKey, + i64 intKey, + int bias, + int *pRes +); int sqlite3BtreeCursorHasMoved(BtCursor*, int*); int sqlite3BtreeDelete(BtCursor*); int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 45c787e1f0..1851b41522 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.754 2008/08/13 14:07:40 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.755 2008/08/13 19:11:48 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -470,6 +470,7 @@ typedef struct Token Token; typedef struct TriggerStack TriggerStack; typedef struct TriggerStep TriggerStep; typedef struct Trigger Trigger; +typedef struct UnpackedRecord UnpackedRecord; typedef struct WhereInfo WhereInfo; typedef struct WhereLevel WhereLevel; @@ -1037,21 +1038,45 @@ struct FKey { ** An instance of the following structure is passed as the first ** argument to sqlite3VdbeKeyCompare and is used to control the ** comparison of the two index keys. -** -** If the KeyInfo.incrKey value is true and the comparison would -** otherwise be equal, then return a result as if the second key -** were larger. */ struct KeyInfo { sqlite3 *db; /* The database connection */ u8 enc; /* Text encoding - one of the TEXT_Utf* values */ - u8 incrKey; /* Increase 2nd key by epsilon before comparison */ - u8 ckPrefixOnly; /* Records are equal if shorter is a prefix of longer */ - int nField; /* Number of entries in aColl[] */ + u16 nField; /* Number of entries in aColl[] */ u8 *aSortOrder; /* If defined an aSortOrder[i] is true, sort DESC */ CollSeq *aColl[1]; /* Collating sequence for each term of the key */ }; +/* +** An instance of the following structure holds information about a +** single index record that has already been parsed out into individual +** values. +** +** A record is an object that contains one or more fields of data. +** Records are used to store the content of a table row and to store +** the key of an index. A blob encoding of a record is created by +** the OP_MakeRecord opcode of the VDBE and is disassemblied by the +** OP_Column opcode. +** +** This structure holds a record that has already been disassembled +** into its constitutent fields. +*/ +struct UnpackedRecord { + KeyInfo *pKeyInfo; /* Collation and sort-order information */ + u16 nField; /* Number of entries in apMem[] */ + u16 flags; /* Boolean settings. UNPACKED_... below */ + Mem *aMem; /* Values */ +}; + +/* +** Allowed values of UnpackedRecord.flags +*/ +#define UNPACKED_NEED_FREE 0x0001 /* Memory is from sqlite3Malloc() */ +#define UNPACKED_NEED_DESTROY 0x0002 /* apMem[]s should all be destroyed */ +#define UNPACKED_IGNORE_ROWID 0x0004 /* Ignore trailing rowid on key1 */ +#define UNPACKED_INCRKEY 0x0008 /* Make this key an epsilon larger */ +#define UNPACKED_PREFIX_MATCH 0x0010 /* A prefix match is considered OK */ + /* ** Each SQL index is represented in memory by an ** instance of the following structure. diff --git a/src/test3.c b/src/test3.c index 6b06dfcfc0..4b75690fff 100644 --- a/src/test3.c +++ b/src/test3.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test3.c,v 1.100 2008/07/12 14:52:20 drh Exp $ +** $Id: test3.c,v 1.101 2008/08/13 19:11:48 drh Exp $ */ #include "sqliteInt.h" #include "btreeInt.h" @@ -697,9 +697,9 @@ static int btree_move_to( sqlite3BtreeLeave(pCur->pBtree); return TCL_ERROR; } - rc = sqlite3BtreeMoveto(pCur, 0, 0, iKey, 0, &res); + rc = sqlite3BtreeMovetoUnpacked(pCur, 0, iKey, 0, &res); }else{ - rc = sqlite3BtreeMoveto(pCur, argv[2], 0, strlen(argv[2]), 0, &res); + rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res); } sqlite3BtreeLeave(pCur->pBtree); if( rc ){ diff --git a/src/vdbe.c b/src/vdbe.c index d02bc8da73..f2e39dd2d6 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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.774 2008/08/13 14:07:40 drh Exp $ +** $Id: vdbe.c,v 1.775 2008/08/13 19:11:48 drh Exp $ */ #include "sqliteInt.h" #include @@ -555,6 +555,8 @@ int sqlite3VdbeExec( #ifndef SQLITE_OMIT_PROGRESS_CALLBACK int nProgressOps = 0; /* Opcodes executed since progress callback. */ #endif + char zTempSpace[200]; /* Space to hold a transient UnpackedRecord */ + assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */ assert( db->magic==SQLITE_MAGIC_BUSY ); @@ -2705,11 +2707,9 @@ case OP_OpenWrite: { rc = sqlite3BtreeCursor(pX, p2, wrFlag, pOp->p4.p, pCur->pCursor); if( pOp->p4type==P4_KEYINFO ){ pCur->pKeyInfo = pOp->p4.pKeyInfo; - pCur->pIncrKey = &pCur->pKeyInfo->incrKey; pCur->pKeyInfo->enc = ENC(p->db); }else{ pCur->pKeyInfo = 0; - pCur->pIncrKey = &pCur->bogusIncrKey; } switch( rc ){ case SQLITE_BUSY: { @@ -2809,13 +2809,11 @@ case OP_OpenEphemeral: { (KeyInfo*)pOp->p4.z, pCx->pCursor); pCx->pKeyInfo = pOp->p4.pKeyInfo; pCx->pKeyInfo->enc = ENC(p->db); - pCx->pIncrKey = &pCx->pKeyInfo->incrKey; } pCx->isTable = 0; }else{ rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, pCx->pCursor); pCx->isTable = 1; - pCx->pIncrKey = &pCx->bogusIncrKey; } } pCx->isIndex = !pCx->isTable; @@ -2851,7 +2849,6 @@ case OP_OpenPseudo: { pCx->nullRow = 1; pCx->pseudoTable = 1; pCx->ephemPseudoTable = pOp->p2; - pCx->pIncrKey = &pCx->bogusIncrKey; pCx->isTable = 1; pCx->isIndex = 0; break; @@ -2943,7 +2940,6 @@ case OP_MoveGt: { /* jump, in3 */ int res, oc; oc = pOp->opcode; pC->nullRow = 0; - *pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe; if( pC->isTable ){ i64 iKey = sqlite3VdbeIntValue(pIn3); if( pOp->p2==0 ){ @@ -2953,7 +2949,7 @@ case OP_MoveGt: { /* jump, in3 */ pC->deferredMoveto = 1; break; } - rc = sqlite3BtreeMoveto(pC->pCursor, 0, 0, (u64)iKey, 0, &res); + rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } @@ -2966,10 +2962,13 @@ case OP_MoveGt: { /* jump, in3 */ assert( nField>0 ); r.pKeyInfo = pC->pKeyInfo; r.nField = nField; - r.needFree = 0; - r.needDestroy = 0; + if( oc==OP_MoveGt || oc==OP_MoveLe ){ + r.flags = UNPACKED_INCRKEY; + }else{ + r.flags = 0; + } r.aMem = &p->aMem[pOp->p3]; - rc = sqlite3BtreeMoveto(pC->pCursor, 0, &r, 0, 0, &res); + rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } @@ -2977,7 +2976,6 @@ case OP_MoveGt: { /* jump, in3 */ } pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; - *pC->pIncrKey = 0; #ifdef SQLITE_TEST sqlite3_search_count++; #endif @@ -3055,13 +3053,20 @@ case OP_Found: { /* jump, in3 */ assert( p->apCsr[i]!=0 ); if( (pC = p->apCsr[i])->pCursor!=0 ){ int res; + UnpackedRecord *pIdxKey; + assert( pC->isTable==0 ); assert( pIn3->flags & MEM_Blob ); - if( pOp->opcode==OP_Found ){ - pC->pKeyInfo->ckPrefixOnly = 1; + pIdxKey = sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, + zTempSpace, sizeof(zTempSpace)); + if( pIdxKey==0 ){ + goto no_mem; } - rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, 0, pIn3->n, 0, &res); - pC->pKeyInfo->ckPrefixOnly = 0; + if( pOp->opcode==OP_Found ){ + pIdxKey->flags |= UNPACKED_PREFIX_MATCH; + } + rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res); + sqlite3VdbeDeleteUnpackedRecord(pIdxKey); if( rc!=SQLITE_OK ){ break; } @@ -3081,7 +3086,7 @@ case OP_Found: { /* jump, in3 */ ** ** The P3 register contains an integer record number. Call this ** record number R. The P4 register contains an index key created -** using MakeIdxRec. Call it K. +** using MakeRecord. Call it K. ** ** P1 is an index. So it has no data and its key consists of a ** record generated by OP_MakeRecord where the last field is the @@ -3117,45 +3122,39 @@ case OP_IsUnique: { /* jump, in3 */ pCrsr = pCx->pCursor; if( pCrsr!=0 ){ int res; - i64 v; /* The record number on the P1 entry that matches K */ - 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 */ + i64 v; /* The record number that matches K */ + UnpackedRecord *pIdxKey; /* Unpacked version of P4 */ /* Make sure K is a string and make zKey point to K */ assert( pK->flags & MEM_Blob ); - zKey = pK->z; - nKey = pK->n; + pIdxKey = sqlite3VdbeRecordUnpack(pCx->pKeyInfo, pK->n, pK->z, + zTempSpace, sizeof(zTempSpace)); + if( pIdxKey==0 ){ + goto no_mem; + } + pIdxKey->flags |= UNPACKED_IGNORE_ROWID; - /* sqlite3VdbeIdxRowidLen() only returns other than SQLITE_OK when the - ** record passed as an argument corrupt. Since the record in this case - ** has just been created by an OP_MakeRecord instruction, and not loaded - ** from the database file, it is not possible for it to be corrupt. - ** Therefore, assert(rc==SQLITE_OK). - */ - rc = sqlite3VdbeIdxRowidLen((u8*)zKey, nKey, &szRowid); - assert(rc==SQLITE_OK); - len = nKey-szRowid; - - /* Search for an entry in P1 where all but the last four bytes match K. + /* Search for an entry in P1 where all but the last rowid match K ** If there is no such entry, jump immediately to P2. */ assert( pCx->deferredMoveto==0 ); pCx->cacheStatus = CACHE_STALE; - rc = sqlite3BtreeMoveto(pCrsr, zKey, 0, len, 0, &res); + rc = sqlite3BtreeMovetoUnpacked(pCrsr, pIdxKey, 0, 0, &res); if( rc!=SQLITE_OK ){ + sqlite3VdbeDeleteUnpackedRecord(pIdxKey); goto abort_due_to_error; } if( res<0 ){ rc = sqlite3BtreeNext(pCrsr, &res); if( res ){ pc = pOp->p2 - 1; + sqlite3VdbeDeleteUnpackedRecord(pIdxKey); break; } } - rc = sqlite3VdbeIdxKeyCompare(pCx, 0, len, (u8*)zKey, &res); + rc = sqlite3VdbeIdxKeyCompare(pCx, pIdxKey, &res); + sqlite3VdbeDeleteUnpackedRecord(pIdxKey); if( rc!=SQLITE_OK ) goto abort_due_to_error; if( res>0 ){ pc = pOp->p2 - 1; @@ -3212,7 +3211,7 @@ case OP_NotExists: { /* jump, in3 */ assert( pIn3->flags & MEM_Int ); assert( p->apCsr[i]->isTable ); iKey = intToKey(pIn3->u.i); - rc = sqlite3BtreeMoveto(pCrsr, 0, 0, iKey, 0,&res); + rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0,&res); pC->lastRowid = pIn3->u.i; pC->rowidIsValid = res==0; pC->nullRow = 0; @@ -3389,7 +3388,7 @@ case OP_NewRowid: { /* out2-prerelease */ } if( v==0 ) continue; x = intToKey(v); - rx = sqlite3BtreeMoveto(pC->pCursor, 0, 0, (u64)x, 0, &res); + rx = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)x, 0, &res); cnt++; }while( cnt<100 && rx==SQLITE_OK && res==0 ); db->priorNewRowid = v; @@ -3885,10 +3884,9 @@ case OP_IdxDelete: { UnpackedRecord r; r.pKeyInfo = pC->pKeyInfo; r.nField = pOp->p3; - r.needFree = 0; - r.needDestroy = 0; + r.flags = 0; r.aMem = &p->aMem[pOp->p2]; - rc = sqlite3BtreeMoveto(pCrsr, 0, &r, 0, 0, &res); + rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res); if( rc==SQLITE_OK && res==0 ){ rc = sqlite3BtreeDelete(pCrsr); } @@ -3971,12 +3969,13 @@ case OP_IdxGE: { /* jump, in3 */ assert( pOp->p4type==P4_INT32 ); r.pKeyInfo = pC->pKeyInfo; r.nField = pOp->p4.i; - r.needFree = 0; - r.needDestroy = 0; + if( pOp->p5 ){ + r.flags = UNPACKED_INCRKEY | UNPACKED_IGNORE_ROWID; + }else{ + r.flags = UNPACKED_IGNORE_ROWID; + } r.aMem = &p->aMem[pOp->p3]; - *pC->pIncrKey = pOp->p5; - rc = sqlite3VdbeIdxKeyCompare(pC, &r, 0, 0, &res); - *pC->pIncrKey = 0; + rc = sqlite3VdbeIdxKeyCompare(pC, &r, &res); if( pOp->opcode==OP_IdxLT ){ res = -res; }else{ diff --git a/src/vdbe.h b/src/vdbe.h index 37d9f68639..f82c8b163b 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.136 2008/08/13 14:07:41 drh Exp $ +** $Id: vdbe.h,v 1.137 2008/08/13 19:11:48 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -34,7 +34,6 @@ typedef struct Vdbe Vdbe; */ typedef struct VdbeFunc VdbeFunc; typedef struct Mem Mem; -typedef struct UnpackedRecord UnpackedRecord; /* ** A single instruction of the virtual machine has an opcode @@ -190,7 +189,7 @@ int sqlite3VdbeReleaseMemory(int); #endif UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,void*,int); void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*); -int sqlite3VdbeRecordCompare(int,const void*,int,UnpackedRecord*); +int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); #ifndef NDEBUG diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 6516f131c0..f910e4be1f 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -15,7 +15,7 @@ ** 6000 lines long) it was split up into several smaller files and ** this header information was factored out. ** -** $Id: vdbeInt.h,v 1.153 2008/08/02 03:50:39 drh Exp $ +** $Id: vdbeInt.h,v 1.154 2008/08/13 19:11:48 drh Exp $ */ #ifndef _VDBEINT_H_ #define _VDBEINT_H_ @@ -71,13 +71,11 @@ struct Cursor { Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool isTable; /* True if a table requiring integer keys */ Bool isIndex; /* True if an index containing keys only - no data */ - u8 bogusIncrKey; /* Something for pIncrKey to point to if pKeyInfo==0 */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ Btree *pBt; /* Separate file holding temporary table */ int nData; /* Number of bytes in pData */ char *pData; /* Data for a NEW or OLD pseudo-table */ i64 iKey; /* Key for the NEW or OLD pseudo-table row */ - u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ int nField; /* Number of fields in the header */ i64 seqCount; /* Sequence counter */ @@ -341,28 +339,6 @@ struct Vdbe { #endif }; -/* -** An instance of the following structure holds information about a -** single index record that has already been parsed out into individual -** values. -** -** A record is an object that contains one or more fields of data. -** Records are used to store the content of a table row and to store -** the key of an index. A blob encoding of a record is created by -** the OP_MakeRecord opcode of the VDBE and is disassemblied by the -** OP_Column opcode. -** -** This structure holds a record that has already been disassembled -** into its constitutent fields. -*/ -struct UnpackedRecord { - KeyInfo *pKeyInfo; /* Collation and sort-order information */ - u16 nField; /* Number of entries in apMem[] */ - u8 needFree; /* True if memory obtained from sqlite3_malloc() */ - u8 needDestroy; /* True if apMem[]s should be destroyed on close */ - Mem *aMem; /* Values */ -}; - /* ** The following are allowed values for Vdbe.magic */ @@ -387,10 +363,9 @@ int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); void sqlite3VdbeDeleteAuxData(VdbeFunc*, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); -int sqlite3VdbeIdxKeyCompare(Cursor*,UnpackedRecord *,int,const unsigned char*,int*); +int sqlite3VdbeIdxKeyCompare(Cursor*,UnpackedRecord*,int*); int sqlite3VdbeIdxRowid(BtCursor *, i64 *); int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); -int sqlite3VdbeIdxRowidLen(const u8*, int, int*); int sqlite3VdbeExec(Vdbe*); int sqlite3VdbeList(Vdbe*); int sqlite3VdbeHalt(Vdbe*); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 1282785112..2d8d2a835d 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -14,7 +14,7 @@ ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. ** -** $Id: vdbeaux.c,v 1.406 2008/08/13 14:07:41 drh Exp $ +** $Id: vdbeaux.c,v 1.407 2008/08/13 19:11:48 drh Exp $ */ #include "sqliteInt.h" #include @@ -1850,9 +1850,8 @@ int sqlite3VdbeCursorMoveto(Cursor *p){ extern int sqlite3_search_count; #endif assert( p->isTable ); - rc = sqlite3BtreeMoveto(p->pCursor, 0, 0, p->movetoTarget, 0, &res); + rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res); if( rc ) return rc; - *p->pIncrKey = 0; p->lastRowid = keyToInt(p->movetoTarget); p->rowidIsValid = res==0; if( res<0 ){ @@ -2215,14 +2214,13 @@ UnpackedRecord *sqlite3VdbeRecordUnpack( if( nByte>szSpace ){ p = sqlite3DbMallocRaw(pKeyInfo->db, nByte); if( p==0 ) return 0; - p->needFree = 1; + p->flags = UNPACKED_NEED_FREE | UNPACKED_NEED_DESTROY; }else{ p = pSpace; - p->needFree = 0; + p->flags = UNPACKED_NEED_DESTROY; } p->pKeyInfo = pKeyInfo; p->nField = pKeyInfo->nField + 1; - p->needDestroy = 1; p->aMem = pMem = &((Mem*)p)[1]; idx = getVarint32(aKey, szHdr); d = szHdr; @@ -2249,7 +2247,7 @@ UnpackedRecord *sqlite3VdbeRecordUnpack( */ void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){ if( p ){ - if( p->needDestroy ){ + if( p->flags & UNPACKED_NEED_DESTROY ){ int i; Mem *pMem; for(i=0, pMem=p->aMem; inField; i++, pMem++){ @@ -2258,7 +2256,7 @@ void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){ } } } - if( p->needFree ){ + if( p->flags & UNPACKED_NEED_FREE ){ sqlite3DbFree(p->pKeyInfo->db, p); } } @@ -2267,38 +2265,31 @@ void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){ /* ** This function compares the two table rows or index records ** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero -** or positive integer if {nKey1, pKey1} is less than, equal to or -** greater than pPKey2. The {nKey1, pKey1} key must be a blob +** or positive integer if key1 is less than, equal to or +** greater than key2. The {nKey1, pKey1} key must be a blob ** created by th OP_MakeRecord opcode of the VDBE. The pPKey2 ** key must be a parsed key such as obtained from ** sqlite3VdbeParseRecord. ** ** Key1 and Key2 do not have to contain the same number of fields. -** The key with fewer fields is usually considered lessor than the -** longer. However if pPKey2->pKeyInfo->incrKey is set and -** the common prefixes are equal, then key1 is less than key2. -** Or if pPKey2->pKeyInfo->ckPrefixOnly flag is set and the -** prefixes are equal, then the keys are considered to be equal and +** The key with fewer fields is usually compares less than the +** longer key. However if the UNPACKED_INCRKEY flags in pPKey2 is set +** and the common prefixes are equal, then key1 is less than key2. +** Or if the UNPACKED_MATCH_PREFIX flag is set and the prefixes are +** equal, then the keys are considered to be equal and ** the parts beyond the common prefix are ignored. ** -** The last nHdrIgnore1 bytes of the header of pKey1 are ignored, -** as if they do not exist. Usually nHdrIgnore1 is 0 which means -** that we look at the entire key. But sometimes nHdrIgnore1 is 1. -** When nHdrIgnore1 is 1, the keys are index records and so the last -** column is a rowid. The type code is always one byte in length. -** Hence, setting nHdrIgnore1 to 1 means that the final rowid at the -** end of the record should be treated as if it does not exist. -** -** Historical note: In earlier versions of this routine both Key1 -** and Key2 were blobs obtained from OP_MakeRecord. But we found -** that in typical use the same Key2 would be submitted multiple times -** in a row. So an optimization was added to parse the Key2 key -** separately and submit the parsed version. In this way, we avoid -** parsing the same Key2 multiple times. +** If the UNPACKED_IGNORE_ROWID flag is set, then the last byte of +** the header of pKey1 is ignored. It is assumed that pKey1 is +** an index key, and thus ends with a rowid value. The last byte +** of the header will therefore be the serial type of the rowid: +** one of 1, 2, 3, 4, 5, 6, 8, or 9 - the integer serial types. +** The serial type of the final rowid will always be a single byte. +** By ignoring this last byte of the header, we force the comparison +** to ignore the rowid at the end of key1. */ int sqlite3VdbeRecordCompare( int nKey1, const void *pKey1, /* Left key */ - int nHdrIgnore1, /* Omit this much from end of key1 header */ UnpackedRecord *pPKey2 /* Right key */ ){ u32 d1; /* Offset into aKey[] of next data element */ @@ -2319,7 +2310,9 @@ int sqlite3VdbeRecordCompare( idx1 = getVarint32(aKey1, szHdr1); d1 = szHdr1; - szHdr1 -= nHdrIgnore1; + if( pPKey2->flags & UNPACKED_IGNORE_ROWID ){ + szHdr1--; + } nField = pKeyInfo->nField; while( idx1nField ){ u32 serial_type1; @@ -2345,16 +2338,16 @@ int sqlite3VdbeRecordCompare( if( rc==0 ){ /* rc==0 here means that one of the keys ran out of fields and - ** all the fields up to that point were equal. If the incrKey - ** flag is true, then break the tie by treating the second key - ** as larger. If ckPrefixOnly is true, then keys with common prefixes + ** all the fields up to that point were equal. If the UNPACKED_INCRKEY + ** flag is set, then break the tie by treating key2 as larger. + ** If the UPACKED_PREFIX_MATCH flag is set, then keys with common prefixes ** are considered to be equal. Otherwise, the longer key is the ** larger. As it happens, the pPKey2 will always be the longer ** if there is a difference. */ - if( pKeyInfo->incrKey ){ + if( pPKey2->flags & UNPACKED_INCRKEY ){ rc = -1; - }else if( pKeyInfo->ckPrefixOnly ){ + }else if( pPKey2->flags & UNPACKED_PREFIX_MATCH ){ /* Leave rc==0 */ }else if( idx1nKey ){ - return SQLITE_CORRUPT_BKPT; - } - (void)getVarint32(&aKey[szHdr-1], typeRowid); - *pRowidLen = sqlite3VdbeSerialTypeLen(typeRowid); - return SQLITE_OK; -} /* @@ -2437,15 +2411,12 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){ int sqlite3VdbeIdxKeyCompare( Cursor *pC, /* The cursor to compare against */ UnpackedRecord *pUnpacked, /* Unpacked version of pKey and nKey */ - int nKey, const u8 *pKey, /* The key to compare */ int *res /* Write the comparison result here */ ){ i64 nCellKey = 0; int rc; BtCursor *pCur = pC->pCursor; Mem m; - UnpackedRecord *pRec; - char zSpace[200]; sqlite3BtreeKeySize(pCur, &nCellKey); if( nCellKey<=0 ){ @@ -2459,19 +2430,8 @@ int sqlite3VdbeIdxKeyCompare( if( rc ){ return rc; } - if( !pUnpacked ){ - pRec = sqlite3VdbeRecordUnpack(pC->pKeyInfo, nKey, pKey, - zSpace, sizeof(zSpace)); - }else{ - pRec = pUnpacked; - } - if( pRec==0 ){ - return SQLITE_NOMEM; - } - *res = sqlite3VdbeRecordCompare(m.n, m.z, 1, pRec); - if( !pUnpacked ){ - sqlite3VdbeDeleteUnpackedRecord(pRec); - } + assert( pUnpacked->flags & UNPACKED_IGNORE_ROWID ); + *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked); sqlite3VdbeMemRelease(&m); return SQLITE_OK; }