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)
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

View File

@ -1 +1 @@
055f173ab1b6fb657bf817faa3a37335d8fa60d5
0b92cbf5255020d4fde382f81590ff0488936667

View File

@ -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.nKey<nKey ){
if( pCur->atLast && pCur->info.nKey<intKey ){
*pRes = -1;
return SQLITE_OK;
}
@ -3714,24 +3711,7 @@ int sqlite3BtreeMoveto(
assert( pCur->pPage->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( nCellKey<nKey ){
}else if( nCellKey<intKey ){
c = -1;
}else{
assert( nCellKey>nKey );
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;
}

View File

@ -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,

View File

@ -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.

View File

@ -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 ){

View File

@ -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 <ctype.h>
@ -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{

View File

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.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

View File

@ -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*);

View File

@ -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 <ctype.h>
@ -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; 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);
}
}
@ -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( idx1<szHdr1 && i<pPKey2->nField ){
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( idx1<szHdr1 ){
rc = 1;
@ -2366,25 +2359,6 @@ int sqlite3VdbeRecordCompare(
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;
}
/*
@ -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;
}