1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Additional changes toward fixing ticket #3292. (CVS 5562)

FossilOrigin-Name: 0b92cbf5255020d4fde382f81590ff0488936667
This commit is contained in:
drh
2008-08-13 19:11:48 +00:00
parent ec1fc80ca3
commit e63d999189
10 changed files with 189 additions and 222 deletions

View File

@@ -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) C Additional\schanges\stoward\sfixing\sticket\s#3292.\s(CVS\s5562)
D 2008-08-13T14:07:40 D 2008-08-13T19:11:48
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 2713ea64947be3b35f35d9a3158bb8299c90b019 F Makefile.in 2713ea64947be3b35f35d9a3158bb8299c90b019
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -96,8 +96,8 @@ F src/attach.c a85c14612e7e3410e0c3d2e0241832fa9688bd14
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
F src/bitvec.c 95c86bd18d8fedf0533f5af196192546e10a7e7d F src/bitvec.c 95c86bd18d8fedf0533f5af196192546e10a7e7d
F src/btmutex.c 709cad2cdca0afd013f0f612363810e53f59ec53 F src/btmutex.c 709cad2cdca0afd013f0f612363810e53f59ec53
F src/btree.c 2ae1092eee58d2d89e5d2f59f711f805dec59bbc F src/btree.c c38431aed9dcdf62916c9009d6f9971e588189fe
F src/btree.h 03256ed7ee42b5ecacbe887070b0f8249e7d069d F src/btree.h 6371c5e599fab391a150c96afbc10062b276d107
F src/btreeInt.h ab18c7b4980314e9e4b402e5dcde09f3c2545576 F src/btreeInt.h ab18c7b4980314e9e4b402e5dcde09f3c2545576
F src/build.c 931ed94fd3bbd67b6ac9d5ac6a45dc01e9f01726 F src/build.c 931ed94fd3bbd67b6ac9d5ac6a45dc01e9f01726
F src/callback.c c9f75a4c403f166af3761df47d78a806587d63af F src/callback.c c9f75a4c403f166af3761df47d78a806587d63af
@@ -146,14 +146,14 @@ F src/select.c 390d1bdde0c24f0225e369896da8e60ef2aeffbe
F src/shell.c d83b578a8ccdd3e0e7fef4388a0887ce9f810967 F src/shell.c d83b578a8ccdd3e0e7fef4388a0887ce9f810967
F src/sqlite.h.in 54e51c22e2294c5989156b0aec87aa44168ac1f0 F src/sqlite.h.in 54e51c22e2294c5989156b0aec87aa44168ac1f0
F src/sqlite3ext.h 1e3887c9bd3ae66cb599e922824b04cd0d0f2c3e F src/sqlite3ext.h 1e3887c9bd3ae66cb599e922824b04cd0d0f2c3e
F src/sqliteInt.h df48efd8c4cb7b833bd7299a41c59c6651be0072 F src/sqliteInt.h 7c68cacc760e8038ba6221c4d9ee3a7f0580e181
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
F src/status.c 8caa772cd9310bc297280f7cf0ede4d69ed5b801 F src/status.c 8caa772cd9310bc297280f7cf0ede4d69ed5b801
F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8 F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8
F src/tclsqlite.c ec46084184f033ba396a9ee7b5514b695083d0f3 F src/tclsqlite.c ec46084184f033ba396a9ee7b5514b695083d0f3
F src/test1.c 0ae2203b03dec8ecf8ad731038df47ba27bfe68c F src/test1.c 0ae2203b03dec8ecf8ad731038df47ba27bfe68c
F src/test2.c 7a634c1e044be3ea5845e65155fdd1cab13936cb F src/test2.c 7a634c1e044be3ea5845e65155fdd1cab13936cb
F src/test3.c e00795839be38f0345a4845170426fb17d828bf9 F src/test3.c e85b7ce5c28c3ce7fbdbf7f98e1467b19786c62b
F src/test4.c 41056378671e7b00e6305fa9ac6fa27e6f96f406 F src/test4.c 41056378671e7b00e6305fa9ac6fa27e6f96f406
F src/test5.c 162a1cea2105a2c460a3f39fa6919617b562a288 F src/test5.c 162a1cea2105a2c460a3f39fa6919617b562a288
F src/test6.c 0a0304a69cfa4962a429d084c6d451ff9e4fb572 F src/test6.c 0a0304a69cfa4962a429d084c6d451ff9e4fb572
@@ -183,11 +183,11 @@ F src/update.c 79b77a3cc8ed5f8903a7f37055fcedd69388dcae
F src/utf.c c63e6f69082f85c19ab88d62dedaf91d71ac1a50 F src/utf.c c63e6f69082f85c19ab88d62dedaf91d71ac1a50
F src/util.c afe659ccc05d1f8af9e8631dabfec3ee3a7144af F src/util.c afe659ccc05d1f8af9e8631dabfec3ee3a7144af
F src/vacuum.c ef342828002debc97514617af3424aea8ef8522c F src/vacuum.c ef342828002debc97514617af3424aea8ef8522c
F src/vdbe.c cda10a8e6ac05c783d6cd8a1d4852754fa73cf3b F src/vdbe.c e2dd0c78c5579e23db49ed8265f0b44d7b22c51d
F src/vdbe.h ccca49ce3db3486ae27f9baec68a77ccc29c43a9 F src/vdbe.h 17bcc2b41082f9b99718b3757cbf97145a72023a
F src/vdbeInt.h 6f04c2bf65a0d5c2bb8318b226278a35d1f7a8f5 F src/vdbeInt.h b48c74d86a9fb62b707a3186ccca76bb32f1c6be
F src/vdbeapi.c f21971516880fd3a10821b2cdd0e64a5a63952c9 F src/vdbeapi.c f21971516880fd3a10821b2cdd0e64a5a63952c9
F src/vdbeaux.c 7b25fbbbdbd548b71c0a44d2f90fd3d0b06e70b8 F src/vdbeaux.c 3e2e1f36c25eae32bdd605456c8be99f73e71eaf
F src/vdbeblob.c f93110888ddc246215e9ba1f831d3d375bfd8355 F src/vdbeblob.c f93110888ddc246215e9ba1f831d3d375bfd8355
F src/vdbefifo.c 20fda2a7c4c0bcee1b90eb7e545fefcdbf2e1de7 F src/vdbefifo.c 20fda2a7c4c0bcee1b90eb7e545fefcdbf2e1de7
F src/vdbemem.c c37b2a266a49eaf0c0f5080157f9f1a908fdaac3 F src/vdbemem.c c37b2a266a49eaf0c0f5080157f9f1a908fdaac3
@@ -618,7 +618,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1 F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
P d6aacc5dc7c06f97fb5faa3d85a8f2d8ab0dd554 P 055f173ab1b6fb657bf817faa3a37335d8fa60d5
R 9b480ed8f28854c07567551a082c6f07 R 3660b918f4cbadc772ff6c9bb7d03fb8
U drh U drh
Z d0f90d7840e7d910b5f941e8ef52ae1d Z ef96eabf3e6f46a636feb3cbdfe8a28b

View File

@@ -1 +1 @@
055f173ab1b6fb657bf817faa3a37335d8fa60d5 0b92cbf5255020d4fde382f81590ff0488936667

View File

@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give. ** 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. ** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information. ** See the header comment on "btreeInt.h" for additional information.
@@ -375,7 +375,7 @@ int sqlite3BtreeRestoreCursorPosition(BtCursor *pCur){
return pCur->skip; return pCur->skip;
} }
pCur->eState = CURSOR_INVALID; 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 ){ if( rc==SQLITE_OK ){
sqlite3_free(pCur->pKey); sqlite3_free(pCur->pKey);
pCur->pKey = 0; 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 /* 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 ** For INTKEY tables, the intKey parameter is used. pIdxKey
** and pUnKey must be NULL. For index tables, either pUnKey ** must be NULL. For index tables, pIdxKey is used and intKey
** must point to a key that has already been unpacked, or else ** is ignored.
** pKey/nKey describes a blob containing the key.
** **
** If an exact match is not found, then the cursor is always ** 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 ** 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. ** is larger than pKey.
** **
*/ */
int sqlite3BtreeMoveto( int sqlite3BtreeMovetoUnpacked(
BtCursor *pCur, /* The cursor to be moved */ BtCursor *pCur, /* The cursor to be moved */
const void *pKey, /* The key content for indices. Not used by tables */ UnpackedRecord *pIdxKey, /* Unpacked index key */
UnpackedRecord *pUnKey,/* Unpacked version of pKey */ i64 intKey, /* The table key */
i64 nKey, /* Size of pKey. Or the key for tables */ int biasRight, /* If true, bias the search to the high end */
int biasRight, /* If true, bias the search to the high end */ int *pRes /* Write search results here */
int *pRes /* Search result flag */
){ ){
int rc; int rc;
char aSpace[200];
assert( cursorHoldsMutex(pCur) ); assert( cursorHoldsMutex(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); 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 /* If the cursor is already positioned at the point we are trying
** to move to, then just return without doing any work */ ** to move to, then just return without doing any work */
if( pCur->eState==CURSOR_VALID && pCur->validNKey && pCur->pPage->intKey ){ if( pCur->eState==CURSOR_VALID && pCur->validNKey && pCur->pPage->intKey ){
if( pCur->info.nKey==nKey ){ if( pCur->info.nKey==intKey ){
*pRes = 0; *pRes = 0;
return SQLITE_OK; return SQLITE_OK;
} }
if( pCur->atLast && pCur->info.nKey<nKey ){ if( pCur->atLast && pCur->info.nKey<intKey ){
*pRes = -1; *pRes = -1;
return SQLITE_OK; return SQLITE_OK;
} }
@@ -3714,24 +3711,7 @@ int sqlite3BtreeMoveto(
assert( pCur->pPage->nCell==0 ); assert( pCur->pPage->nCell==0 );
return SQLITE_OK; return SQLITE_OK;
} }
if( pCur->pPage->intKey ){ assert( pCur->pPage->intKey || pIdxKey );
/* 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 );
}
for(;;){ for(;;){
int lwr, upr; int lwr, upr;
Pgno chldPg; Pgno chldPg;
@@ -3739,7 +3719,7 @@ int sqlite3BtreeMoveto(
int c = -1; /* pRes return if table is empty must be -1 */ int c = -1; /* pRes return if table is empty must be -1 */
lwr = 0; lwr = 0;
upr = pPage->nCell-1; upr = pPage->nCell-1;
if( !pPage->intKey && pUnKey==0 ){ if( !pPage->intKey && pIdxKey==0 ){
rc = SQLITE_CORRUPT_BKPT; rc = SQLITE_CORRUPT_BKPT;
goto moveto_finish; goto moveto_finish;
} }
@@ -3761,12 +3741,12 @@ int sqlite3BtreeMoveto(
pCell += getVarint32(pCell, dummy); pCell += getVarint32(pCell, dummy);
} }
getVarint(pCell, (u64*)&nCellKey); getVarint(pCell, (u64*)&nCellKey);
if( nCellKey==nKey ){ if( nCellKey==intKey ){
c = 0; c = 0;
}else if( nCellKey<nKey ){ }else if( nCellKey<intKey ){
c = -1; c = -1;
}else{ }else{
assert( nCellKey>nKey ); assert( nCellKey>intKey );
c = +1; c = +1;
} }
}else{ }else{
@@ -3774,7 +3754,7 @@ int sqlite3BtreeMoveto(
pCellKey = (void *)fetchPayload(pCur, &available, 0); pCellKey = (void *)fetchPayload(pCur, &available, 0);
nCellKey = pCur->info.nKey; nCellKey = pCur->info.nKey;
if( available>=nCellKey ){ if( available>=nCellKey ){
c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, 0, pUnKey); c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, pIdxKey);
}else{ }else{
pCellKey = sqlite3Malloc( nCellKey ); pCellKey = sqlite3Malloc( nCellKey );
if( pCellKey==0 ){ if( pCellKey==0 ){
@@ -3782,7 +3762,7 @@ int sqlite3BtreeMoveto(
goto moveto_finish; goto moveto_finish;
} }
rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey); rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey);
c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, 0, pUnKey); c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, pIdxKey);
sqlite3_free(pCellKey); sqlite3_free(pCellKey);
if( rc ) goto moveto_finish; if( rc ) goto moveto_finish;
} }
@@ -3832,10 +3812,35 @@ int sqlite3BtreeMoveto(
if( rc ) goto moveto_finish; if( rc ) goto moveto_finish;
} }
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( pKey ){
/* If we created our own unpacked key at the top of this pIdxKey = sqlite3VdbeRecordUnpack(pCur->pKeyInfo, nKey, pKey,
** procedure, then destroy that key before returning. */ aSpace, sizeof(aSpace));
sqlite3VdbeDeleteUnpackedRecord(pUnKey); if( pIdxKey==0 ) return SQLITE_NOMEM;
}else{
pIdxKey = 0;
}
rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes);
if( pKey ){
sqlite3VdbeDeleteUnpackedRecord(pIdxKey);
} }
return rc; return rc;
} }
@@ -5836,7 +5841,7 @@ int sqlite3BtreeInsert(
clearCursorPosition(pCur); clearCursorPosition(pCur);
if( if(
SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) || 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; return rc;
} }

View File

@@ -13,7 +13,7 @@
** subsystem. See comments in the source code for a detailed description ** subsystem. See comments in the source code for a detailed description
** of what each interface routine does. ** 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_ #ifndef _BTREE_H_
#define _BTREE_H_ #define _BTREE_H_
@@ -122,8 +122,6 @@ int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
void sqlite3BtreeTripAllCursors(Btree*, int); void sqlite3BtreeTripAllCursors(Btree*, int);
struct UnpackedRecord; /* Forward declaration. Definition in vdbeaux.c. */
int sqlite3BtreeCursor( int sqlite3BtreeCursor(
Btree*, /* BTree containing table to open */ Btree*, /* BTree containing table to open */
int iTable, /* Index of root page */ int iTable, /* Index of root page */
@@ -137,11 +135,17 @@ int sqlite3BtreeCloseCursor(BtCursor*);
int sqlite3BtreeMoveto( int sqlite3BtreeMoveto(
BtCursor*, BtCursor*,
const void *pKey, const void *pKey,
struct UnpackedRecord *pUnKey,
i64 nKey, i64 nKey,
int bias, int bias,
int *pRes int *pRes
); );
int sqlite3BtreeMovetoUnpacked(
BtCursor*,
UnpackedRecord *pUnKey,
i64 intKey,
int bias,
int *pRes
);
int sqlite3BtreeCursorHasMoved(BtCursor*, int*); int sqlite3BtreeCursorHasMoved(BtCursor*, int*);
int sqlite3BtreeDelete(BtCursor*); int sqlite3BtreeDelete(BtCursor*);
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** 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_ #ifndef _SQLITEINT_H_
#define _SQLITEINT_H_ #define _SQLITEINT_H_
@@ -470,6 +470,7 @@ typedef struct Token Token;
typedef struct TriggerStack TriggerStack; typedef struct TriggerStack TriggerStack;
typedef struct TriggerStep TriggerStep; typedef struct TriggerStep TriggerStep;
typedef struct Trigger Trigger; typedef struct Trigger Trigger;
typedef struct UnpackedRecord UnpackedRecord;
typedef struct WhereInfo WhereInfo; typedef struct WhereInfo WhereInfo;
typedef struct WhereLevel WhereLevel; typedef struct WhereLevel WhereLevel;
@@ -1037,21 +1038,45 @@ struct FKey {
** An instance of the following structure is passed as the first ** An instance of the following structure is passed as the first
** argument to sqlite3VdbeKeyCompare and is used to control the ** argument to sqlite3VdbeKeyCompare and is used to control the
** comparison of the two index keys. ** 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 { struct KeyInfo {
sqlite3 *db; /* The database connection */ sqlite3 *db; /* The database connection */
u8 enc; /* Text encoding - one of the TEXT_Utf* values */ u8 enc; /* Text encoding - one of the TEXT_Utf* values */
u8 incrKey; /* Increase 2nd key by epsilon before comparison */ u16 nField; /* Number of entries in aColl[] */
u8 ckPrefixOnly; /* Records are equal if shorter is a prefix of longer */
int nField; /* Number of entries in aColl[] */
u8 *aSortOrder; /* If defined an aSortOrder[i] is true, sort DESC */ u8 *aSortOrder; /* If defined an aSortOrder[i] is true, sort DESC */
CollSeq *aColl[1]; /* Collating sequence for each term of the key */ 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 ** Each SQL index is represented in memory by an
** instance of the following structure. ** instance of the following structure.

View File

@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated ** is not included in the SQLite library. It is used for automated
** testing of the SQLite library. ** 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 "sqliteInt.h"
#include "btreeInt.h" #include "btreeInt.h"
@@ -697,9 +697,9 @@ static int btree_move_to(
sqlite3BtreeLeave(pCur->pBtree); sqlite3BtreeLeave(pCur->pBtree);
return TCL_ERROR; return TCL_ERROR;
} }
rc = sqlite3BtreeMoveto(pCur, 0, 0, iKey, 0, &res); rc = sqlite3BtreeMovetoUnpacked(pCur, 0, iKey, 0, &res);
}else{ }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); sqlite3BtreeLeave(pCur->pBtree);
if( rc ){ if( rc ){

View File

@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** 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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -555,6 +555,8 @@ int sqlite3VdbeExec(
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
int nProgressOps = 0; /* Opcodes executed since progress callback. */ int nProgressOps = 0; /* Opcodes executed since progress callback. */
#endif #endif
char zTempSpace[200]; /* Space to hold a transient UnpackedRecord */
assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */ assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */
assert( db->magic==SQLITE_MAGIC_BUSY ); assert( db->magic==SQLITE_MAGIC_BUSY );
@@ -2705,11 +2707,9 @@ case OP_OpenWrite: {
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pOp->p4.p, pCur->pCursor); rc = sqlite3BtreeCursor(pX, p2, wrFlag, pOp->p4.p, pCur->pCursor);
if( pOp->p4type==P4_KEYINFO ){ if( pOp->p4type==P4_KEYINFO ){
pCur->pKeyInfo = pOp->p4.pKeyInfo; pCur->pKeyInfo = pOp->p4.pKeyInfo;
pCur->pIncrKey = &pCur->pKeyInfo->incrKey;
pCur->pKeyInfo->enc = ENC(p->db); pCur->pKeyInfo->enc = ENC(p->db);
}else{ }else{
pCur->pKeyInfo = 0; pCur->pKeyInfo = 0;
pCur->pIncrKey = &pCur->bogusIncrKey;
} }
switch( rc ){ switch( rc ){
case SQLITE_BUSY: { case SQLITE_BUSY: {
@@ -2809,13 +2809,11 @@ case OP_OpenEphemeral: {
(KeyInfo*)pOp->p4.z, pCx->pCursor); (KeyInfo*)pOp->p4.z, pCx->pCursor);
pCx->pKeyInfo = pOp->p4.pKeyInfo; pCx->pKeyInfo = pOp->p4.pKeyInfo;
pCx->pKeyInfo->enc = ENC(p->db); pCx->pKeyInfo->enc = ENC(p->db);
pCx->pIncrKey = &pCx->pKeyInfo->incrKey;
} }
pCx->isTable = 0; pCx->isTable = 0;
}else{ }else{
rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, pCx->pCursor); rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, pCx->pCursor);
pCx->isTable = 1; pCx->isTable = 1;
pCx->pIncrKey = &pCx->bogusIncrKey;
} }
} }
pCx->isIndex = !pCx->isTable; pCx->isIndex = !pCx->isTable;
@@ -2851,7 +2849,6 @@ case OP_OpenPseudo: {
pCx->nullRow = 1; pCx->nullRow = 1;
pCx->pseudoTable = 1; pCx->pseudoTable = 1;
pCx->ephemPseudoTable = pOp->p2; pCx->ephemPseudoTable = pOp->p2;
pCx->pIncrKey = &pCx->bogusIncrKey;
pCx->isTable = 1; pCx->isTable = 1;
pCx->isIndex = 0; pCx->isIndex = 0;
break; break;
@@ -2943,7 +2940,6 @@ case OP_MoveGt: { /* jump, in3 */
int res, oc; int res, oc;
oc = pOp->opcode; oc = pOp->opcode;
pC->nullRow = 0; pC->nullRow = 0;
*pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe;
if( pC->isTable ){ if( pC->isTable ){
i64 iKey = sqlite3VdbeIntValue(pIn3); i64 iKey = sqlite3VdbeIntValue(pIn3);
if( pOp->p2==0 ){ if( pOp->p2==0 ){
@@ -2953,7 +2949,7 @@ case OP_MoveGt: { /* jump, in3 */
pC->deferredMoveto = 1; pC->deferredMoveto = 1;
break; break;
} }
rc = sqlite3BtreeMoveto(pC->pCursor, 0, 0, (u64)iKey, 0, &res); rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto abort_due_to_error; goto abort_due_to_error;
} }
@@ -2966,10 +2962,13 @@ case OP_MoveGt: { /* jump, in3 */
assert( nField>0 ); assert( nField>0 );
r.pKeyInfo = pC->pKeyInfo; r.pKeyInfo = pC->pKeyInfo;
r.nField = nField; r.nField = nField;
r.needFree = 0; if( oc==OP_MoveGt || oc==OP_MoveLe ){
r.needDestroy = 0; r.flags = UNPACKED_INCRKEY;
}else{
r.flags = 0;
}
r.aMem = &p->aMem[pOp->p3]; 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 ){ if( rc!=SQLITE_OK ){
goto abort_due_to_error; goto abort_due_to_error;
} }
@@ -2977,7 +2976,6 @@ case OP_MoveGt: { /* jump, in3 */
} }
pC->deferredMoveto = 0; pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE; pC->cacheStatus = CACHE_STALE;
*pC->pIncrKey = 0;
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
sqlite3_search_count++; sqlite3_search_count++;
#endif #endif
@@ -3055,13 +3053,20 @@ case OP_Found: { /* jump, in3 */
assert( p->apCsr[i]!=0 ); assert( p->apCsr[i]!=0 );
if( (pC = p->apCsr[i])->pCursor!=0 ){ if( (pC = p->apCsr[i])->pCursor!=0 ){
int res; int res;
UnpackedRecord *pIdxKey;
assert( pC->isTable==0 ); assert( pC->isTable==0 );
assert( pIn3->flags & MEM_Blob ); assert( pIn3->flags & MEM_Blob );
if( pOp->opcode==OP_Found ){ pIdxKey = sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z,
pC->pKeyInfo->ckPrefixOnly = 1; zTempSpace, sizeof(zTempSpace));
if( pIdxKey==0 ){
goto no_mem;
} }
rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, 0, pIn3->n, 0, &res); if( pOp->opcode==OP_Found ){
pC->pKeyInfo->ckPrefixOnly = 0; pIdxKey->flags |= UNPACKED_PREFIX_MATCH;
}
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res);
sqlite3VdbeDeleteUnpackedRecord(pIdxKey);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
break; break;
} }
@@ -3081,7 +3086,7 @@ case OP_Found: { /* jump, in3 */
** **
** The P3 register contains an integer record number. Call this ** The P3 register contains an integer record number. Call this
** record number R. The P4 register contains an index key created ** 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 ** 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 ** record generated by OP_MakeRecord where the last field is the
@@ -3117,45 +3122,39 @@ case OP_IsUnique: { /* jump, in3 */
pCrsr = pCx->pCursor; pCrsr = pCx->pCursor;
if( pCrsr!=0 ){ if( pCrsr!=0 ){
int res; int res;
i64 v; /* The record number on the P1 entry that matches K */ i64 v; /* The record number that matches K */
char *zKey; /* The value of K */ UnpackedRecord *pIdxKey; /* Unpacked version of P4 */
int nKey; /* Number of bytes in K */
int len; /* Number of bytes in K without the rowid at the end */
int szRowid; /* Size of the rowid column at the end of zKey */
/* Make sure K is a string and make zKey point to K /* Make sure K is a string and make zKey point to K
*/ */
assert( pK->flags & MEM_Blob ); assert( pK->flags & MEM_Blob );
zKey = pK->z; pIdxKey = sqlite3VdbeRecordUnpack(pCx->pKeyInfo, pK->n, pK->z,
nKey = pK->n; zTempSpace, sizeof(zTempSpace));
if( pIdxKey==0 ){
goto no_mem;
}
pIdxKey->flags |= UNPACKED_IGNORE_ROWID;
/* sqlite3VdbeIdxRowidLen() only returns other than SQLITE_OK when the /* Search for an entry in P1 where all but the last rowid match K
** 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.
** If there is no such entry, jump immediately to P2. ** If there is no such entry, jump immediately to P2.
*/ */
assert( pCx->deferredMoveto==0 ); assert( pCx->deferredMoveto==0 );
pCx->cacheStatus = CACHE_STALE; pCx->cacheStatus = CACHE_STALE;
rc = sqlite3BtreeMoveto(pCrsr, zKey, 0, len, 0, &res); rc = sqlite3BtreeMovetoUnpacked(pCrsr, pIdxKey, 0, 0, &res);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
sqlite3VdbeDeleteUnpackedRecord(pIdxKey);
goto abort_due_to_error; goto abort_due_to_error;
} }
if( res<0 ){ if( res<0 ){
rc = sqlite3BtreeNext(pCrsr, &res); rc = sqlite3BtreeNext(pCrsr, &res);
if( res ){ if( res ){
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
sqlite3VdbeDeleteUnpackedRecord(pIdxKey);
break; 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( rc!=SQLITE_OK ) goto abort_due_to_error;
if( res>0 ){ if( res>0 ){
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
@@ -3212,7 +3211,7 @@ case OP_NotExists: { /* jump, in3 */
assert( pIn3->flags & MEM_Int ); assert( pIn3->flags & MEM_Int );
assert( p->apCsr[i]->isTable ); assert( p->apCsr[i]->isTable );
iKey = intToKey(pIn3->u.i); 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->lastRowid = pIn3->u.i;
pC->rowidIsValid = res==0; pC->rowidIsValid = res==0;
pC->nullRow = 0; pC->nullRow = 0;
@@ -3389,7 +3388,7 @@ case OP_NewRowid: { /* out2-prerelease */
} }
if( v==0 ) continue; if( v==0 ) continue;
x = intToKey(v); x = intToKey(v);
rx = sqlite3BtreeMoveto(pC->pCursor, 0, 0, (u64)x, 0, &res); rx = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)x, 0, &res);
cnt++; cnt++;
}while( cnt<100 && rx==SQLITE_OK && res==0 ); }while( cnt<100 && rx==SQLITE_OK && res==0 );
db->priorNewRowid = v; db->priorNewRowid = v;
@@ -3885,10 +3884,9 @@ case OP_IdxDelete: {
UnpackedRecord r; UnpackedRecord r;
r.pKeyInfo = pC->pKeyInfo; r.pKeyInfo = pC->pKeyInfo;
r.nField = pOp->p3; r.nField = pOp->p3;
r.needFree = 0; r.flags = 0;
r.needDestroy = 0;
r.aMem = &p->aMem[pOp->p2]; 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 ){ if( rc==SQLITE_OK && res==0 ){
rc = sqlite3BtreeDelete(pCrsr); rc = sqlite3BtreeDelete(pCrsr);
} }
@@ -3971,12 +3969,13 @@ case OP_IdxGE: { /* jump, in3 */
assert( pOp->p4type==P4_INT32 ); assert( pOp->p4type==P4_INT32 );
r.pKeyInfo = pC->pKeyInfo; r.pKeyInfo = pC->pKeyInfo;
r.nField = pOp->p4.i; r.nField = pOp->p4.i;
r.needFree = 0; if( pOp->p5 ){
r.needDestroy = 0; r.flags = UNPACKED_INCRKEY | UNPACKED_IGNORE_ROWID;
}else{
r.flags = UNPACKED_IGNORE_ROWID;
}
r.aMem = &p->aMem[pOp->p3]; r.aMem = &p->aMem[pOp->p3];
*pC->pIncrKey = pOp->p5; rc = sqlite3VdbeIdxKeyCompare(pC, &r, &res);
rc = sqlite3VdbeIdxKeyCompare(pC, &r, 0, 0, &res);
*pC->pIncrKey = 0;
if( pOp->opcode==OP_IdxLT ){ if( pOp->opcode==OP_IdxLT ){
res = -res; res = -res;
}else{ }else{

View File

@@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a ** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database. ** 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_ #ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_
@@ -34,7 +34,6 @@ typedef struct Vdbe Vdbe;
*/ */
typedef struct VdbeFunc VdbeFunc; typedef struct VdbeFunc VdbeFunc;
typedef struct Mem Mem; typedef struct Mem Mem;
typedef struct UnpackedRecord UnpackedRecord;
/* /*
** A single instruction of the virtual machine has an opcode ** A single instruction of the virtual machine has an opcode
@@ -190,7 +189,7 @@ int sqlite3VdbeReleaseMemory(int);
#endif #endif
UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,void*,int); UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,void*,int);
void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*); void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*);
int sqlite3VdbeRecordCompare(int,const void*,int,UnpackedRecord*); int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
#ifndef NDEBUG #ifndef NDEBUG

View File

@@ -15,7 +15,7 @@
** 6000 lines long) it was split up into several smaller files and ** 6000 lines long) it was split up into several smaller files and
** this header information was factored out. ** 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_ #ifndef _VDBEINT_H_
#define _VDBEINT_H_ #define _VDBEINT_H_
@@ -71,13 +71,11 @@ struct Cursor {
Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
Bool isTable; /* True if a table requiring integer keys */ Bool isTable; /* True if a table requiring integer keys */
Bool isIndex; /* True if an index containing keys only - no data */ 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() */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
Btree *pBt; /* Separate file holding temporary table */ Btree *pBt; /* Separate file holding temporary table */
int nData; /* Number of bytes in pData */ int nData; /* Number of bytes in pData */
char *pData; /* Data for a NEW or OLD pseudo-table */ char *pData; /* Data for a NEW or OLD pseudo-table */
i64 iKey; /* Key for the NEW or OLD pseudo-table row */ 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 */ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
int nField; /* Number of fields in the header */ int nField; /* Number of fields in the header */
i64 seqCount; /* Sequence counter */ i64 seqCount; /* Sequence counter */
@@ -341,28 +339,6 @@ struct Vdbe {
#endif #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 ** The following are allowed values for Vdbe.magic
*/ */
@@ -387,10 +363,9 @@ int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int); void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, 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 sqlite3VdbeIdxRowid(BtCursor *, i64 *);
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
int sqlite3VdbeIdxRowidLen(const u8*, int, int*);
int sqlite3VdbeExec(Vdbe*); int sqlite3VdbeExec(Vdbe*);
int sqlite3VdbeList(Vdbe*); int sqlite3VdbeList(Vdbe*);
int sqlite3VdbeHalt(Vdbe*); int sqlite3VdbeHalt(Vdbe*);

View File

@@ -14,7 +14,7 @@
** to version 2.8.7, all this code was combined into the vdbe.c source file. ** 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. ** 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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -1850,9 +1850,8 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
extern int sqlite3_search_count; extern int sqlite3_search_count;
#endif #endif
assert( p->isTable ); 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; if( rc ) return rc;
*p->pIncrKey = 0;
p->lastRowid = keyToInt(p->movetoTarget); p->lastRowid = keyToInt(p->movetoTarget);
p->rowidIsValid = res==0; p->rowidIsValid = res==0;
if( res<0 ){ if( res<0 ){
@@ -2215,14 +2214,13 @@ UnpackedRecord *sqlite3VdbeRecordUnpack(
if( nByte>szSpace ){ if( nByte>szSpace ){
p = sqlite3DbMallocRaw(pKeyInfo->db, nByte); p = sqlite3DbMallocRaw(pKeyInfo->db, nByte);
if( p==0 ) return 0; if( p==0 ) return 0;
p->needFree = 1; p->flags = UNPACKED_NEED_FREE | UNPACKED_NEED_DESTROY;
}else{ }else{
p = pSpace; p = pSpace;
p->needFree = 0; p->flags = UNPACKED_NEED_DESTROY;
} }
p->pKeyInfo = pKeyInfo; p->pKeyInfo = pKeyInfo;
p->nField = pKeyInfo->nField + 1; p->nField = pKeyInfo->nField + 1;
p->needDestroy = 1;
p->aMem = pMem = &((Mem*)p)[1]; p->aMem = pMem = &((Mem*)p)[1];
idx = getVarint32(aKey, szHdr); idx = getVarint32(aKey, szHdr);
d = szHdr; d = szHdr;
@@ -2249,7 +2247,7 @@ UnpackedRecord *sqlite3VdbeRecordUnpack(
*/ */
void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){ void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){
if( p ){ if( p ){
if( p->needDestroy ){ if( p->flags & UNPACKED_NEED_DESTROY ){
int i; int i;
Mem *pMem; Mem *pMem;
for(i=0, pMem=p->aMem; i<p->nField; i++, pMem++){ for(i=0, pMem=p->aMem; i<p->nField; i++, pMem++){
@@ -2258,7 +2256,7 @@ void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){
} }
} }
} }
if( p->needFree ){ if( p->flags & UNPACKED_NEED_FREE ){
sqlite3DbFree(p->pKeyInfo->db, p); sqlite3DbFree(p->pKeyInfo->db, p);
} }
} }
@@ -2267,38 +2265,31 @@ void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){
/* /*
** This function compares the two table rows or index records ** This function compares the two table rows or index records
** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero ** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero
** or positive integer if {nKey1, pKey1} is less than, equal to or ** or positive integer if key1 is less than, equal to or
** greater than pPKey2. The {nKey1, pKey1} key must be a blob ** greater than key2. The {nKey1, pKey1} key must be a blob
** created by th OP_MakeRecord opcode of the VDBE. The pPKey2 ** created by th OP_MakeRecord opcode of the VDBE. The pPKey2
** key must be a parsed key such as obtained from ** key must be a parsed key such as obtained from
** sqlite3VdbeParseRecord. ** sqlite3VdbeParseRecord.
** **
** Key1 and Key2 do not have to contain the same number of fields. ** Key1 and Key2 do not have to contain the same number of fields.
** The key with fewer fields is usually considered lessor than the ** The key with fewer fields is usually compares less than the
** longer. However if pPKey2->pKeyInfo->incrKey is set and ** longer key. However if the UNPACKED_INCRKEY flags in pPKey2 is set
** the common prefixes are equal, then key1 is less than key2. ** and the common prefixes are equal, then key1 is less than key2.
** Or if pPKey2->pKeyInfo->ckPrefixOnly flag is set and the ** Or if the UNPACKED_MATCH_PREFIX flag is set and the prefixes are
** prefixes are equal, then the keys are considered to be equal and ** equal, then the keys are considered to be equal and
** the parts beyond the common prefix are ignored. ** the parts beyond the common prefix are ignored.
** **
** The last nHdrIgnore1 bytes of the header of pKey1 are ignored, ** If the UNPACKED_IGNORE_ROWID flag is set, then the last byte of
** as if they do not exist. Usually nHdrIgnore1 is 0 which means ** the header of pKey1 is ignored. It is assumed that pKey1 is
** that we look at the entire key. But sometimes nHdrIgnore1 is 1. ** an index key, and thus ends with a rowid value. The last byte
** When nHdrIgnore1 is 1, the keys are index records and so the last ** of the header will therefore be the serial type of the rowid:
** column is a rowid. The type code is always one byte in length. ** one of 1, 2, 3, 4, 5, 6, 8, or 9 - the integer serial types.
** Hence, setting nHdrIgnore1 to 1 means that the final rowid at the ** The serial type of the final rowid will always be a single byte.
** end of the record should be treated as if it does not exist. ** By ignoring this last byte of the header, we force the comparison
** ** to ignore the rowid at the end of key1.
** 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.
*/ */
int sqlite3VdbeRecordCompare( int sqlite3VdbeRecordCompare(
int nKey1, const void *pKey1, /* Left key */ int nKey1, const void *pKey1, /* Left key */
int nHdrIgnore1, /* Omit this much from end of key1 header */
UnpackedRecord *pPKey2 /* Right key */ UnpackedRecord *pPKey2 /* Right key */
){ ){
u32 d1; /* Offset into aKey[] of next data element */ u32 d1; /* Offset into aKey[] of next data element */
@@ -2319,7 +2310,9 @@ int sqlite3VdbeRecordCompare(
idx1 = getVarint32(aKey1, szHdr1); idx1 = getVarint32(aKey1, szHdr1);
d1 = szHdr1; d1 = szHdr1;
szHdr1 -= nHdrIgnore1; if( pPKey2->flags & UNPACKED_IGNORE_ROWID ){
szHdr1--;
}
nField = pKeyInfo->nField; nField = pKeyInfo->nField;
while( idx1<szHdr1 && i<pPKey2->nField ){ while( idx1<szHdr1 && i<pPKey2->nField ){
u32 serial_type1; u32 serial_type1;
@@ -2345,16 +2338,16 @@ int sqlite3VdbeRecordCompare(
if( rc==0 ){ if( rc==0 ){
/* rc==0 here means that one of the keys ran out of fields and /* 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 ** all the fields up to that point were equal. If the UNPACKED_INCRKEY
** flag is true, then break the tie by treating the second key ** flag is set, then break the tie by treating key2 as larger.
** as larger. If ckPrefixOnly is true, then keys with common prefixes ** If the UPACKED_PREFIX_MATCH flag is set, then keys with common prefixes
** are considered to be equal. Otherwise, the longer key is the ** are considered to be equal. Otherwise, the longer key is the
** larger. As it happens, the pPKey2 will always be the longer ** larger. As it happens, the pPKey2 will always be the longer
** if there is a difference. ** if there is a difference.
*/ */
if( pKeyInfo->incrKey ){ if( pPKey2->flags & UNPACKED_INCRKEY ){
rc = -1; rc = -1;
}else if( pKeyInfo->ckPrefixOnly ){ }else if( pPKey2->flags & UNPACKED_PREFIX_MATCH ){
/* Leave rc==0 */ /* Leave rc==0 */
}else if( idx1<szHdr1 ){ }else if( idx1<szHdr1 ){
rc = 1; rc = 1;
@@ -2367,25 +2360,6 @@ int sqlite3VdbeRecordCompare(
return rc; return rc;
} }
/*
** The argument is an index entry composed using the OP_MakeRecord opcode.
** The last entry in this record should be an integer (specifically
** an integer rowid). This routine returns the number of bytes in
** that integer.
*/
int sqlite3VdbeIdxRowidLen(const u8 *aKey, int nKey, int *pRowidLen){
u32 szHdr; /* Size of the header */
u32 typeRowid; /* Serial type of the rowid */
(void)getVarint32(aKey, szHdr);
if( szHdr>nKey ){
return SQLITE_CORRUPT_BKPT;
}
(void)getVarint32(&aKey[szHdr-1], typeRowid);
*pRowidLen = sqlite3VdbeSerialTypeLen(typeRowid);
return SQLITE_OK;
}
/* /*
** pCur points at an index entry created using the OP_MakeRecord opcode. ** pCur points at an index entry created using the OP_MakeRecord opcode.
@@ -2437,15 +2411,12 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
int sqlite3VdbeIdxKeyCompare( int sqlite3VdbeIdxKeyCompare(
Cursor *pC, /* The cursor to compare against */ Cursor *pC, /* The cursor to compare against */
UnpackedRecord *pUnpacked, /* Unpacked version of pKey and nKey */ UnpackedRecord *pUnpacked, /* Unpacked version of pKey and nKey */
int nKey, const u8 *pKey, /* The key to compare */
int *res /* Write the comparison result here */ int *res /* Write the comparison result here */
){ ){
i64 nCellKey = 0; i64 nCellKey = 0;
int rc; int rc;
BtCursor *pCur = pC->pCursor; BtCursor *pCur = pC->pCursor;
Mem m; Mem m;
UnpackedRecord *pRec;
char zSpace[200];
sqlite3BtreeKeySize(pCur, &nCellKey); sqlite3BtreeKeySize(pCur, &nCellKey);
if( nCellKey<=0 ){ if( nCellKey<=0 ){
@@ -2459,19 +2430,8 @@ int sqlite3VdbeIdxKeyCompare(
if( rc ){ if( rc ){
return rc; return rc;
} }
if( !pUnpacked ){ assert( pUnpacked->flags & UNPACKED_IGNORE_ROWID );
pRec = sqlite3VdbeRecordUnpack(pC->pKeyInfo, nKey, pKey, *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked);
zSpace, sizeof(zSpace));
}else{
pRec = pUnpacked;
}
if( pRec==0 ){
return SQLITE_NOMEM;
}
*res = sqlite3VdbeRecordCompare(m.n, m.z, 1, pRec);
if( !pUnpacked ){
sqlite3VdbeDeleteUnpackedRecord(pRec);
}
sqlite3VdbeMemRelease(&m); sqlite3VdbeMemRelease(&m);
return SQLITE_OK; return SQLITE_OK;
} }