-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
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
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
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
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
-055f173ab1b6fb657bf817faa3a37335d8fa60d5
\ No newline at end of file
+0b92cbf5255020d4fde382f81590ff0488936667
\ No newline at end of file
** 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.
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;
}
/* 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
** 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) );
/* 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;
}
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;
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;
}
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{
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 ){
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;
}
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 ){
+ 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 ){
- /* If we created our own unpacked key at the top of this
- ** procedure, then destroy that key before returning. */
- sqlite3VdbeDeleteUnpackedRecord(pUnKey);
+ sqlite3VdbeDeleteUnpackedRecord(pIdxKey);
}
return rc;
}
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;
}
** 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_
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 */
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,
*************************************************************************
** 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_
typedef struct TriggerStack TriggerStack;
typedef struct TriggerStep TriggerStep;
typedef struct Trigger Trigger;
+typedef struct UnpackedRecord UnpackedRecord;
typedef struct WhereInfo WhereInfo;
typedef struct WhereLevel WhereLevel;
** 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.
** 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"
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 ){
** 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>
#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 );
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: {
(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;
pCx->nullRow = 1;
pCx->pseudoTable = 1;
pCx->ephemPseudoTable = pOp->p2;
- pCx->pIncrKey = &pCx->bogusIncrKey;
pCx->isTable = 1;
pCx->isIndex = 0;
break;
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 ){
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;
}
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;
}
}
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
- *pC->pIncrKey = 0;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
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 );
+ pIdxKey = sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z,
+ zTempSpace, sizeof(zTempSpace));
+ if( pIdxKey==0 ){
+ goto no_mem;
+ }
if( pOp->opcode==OP_Found ){
- pC->pKeyInfo->ckPrefixOnly = 1;
+ pIdxKey->flags |= UNPACKED_PREFIX_MATCH;
}
- rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, 0, pIn3->n, 0, &res);
- pC->pKeyInfo->ckPrefixOnly = 0;
+ rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res);
+ sqlite3VdbeDeleteUnpackedRecord(pIdxKey);
if( rc!=SQLITE_OK ){
break;
}
**
** 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
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;
-
- /* 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;
+ pIdxKey = sqlite3VdbeRecordUnpack(pCx->pKeyInfo, pK->n, pK->z,
+ zTempSpace, sizeof(zTempSpace));
+ if( pIdxKey==0 ){
+ goto no_mem;
+ }
+ pIdxKey->flags |= UNPACKED_IGNORE_ROWID;
- /* 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;
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;
}
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;
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);
}
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{
** 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_
*/
typedef struct VdbeFunc VdbeFunc;
typedef struct Mem Mem;
-typedef struct UnpackedRecord UnpackedRecord;
/*
** A single instruction of the virtual machine has an opcode
#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
** 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_
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 */
#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
*/
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*);
** 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>
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 ){
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;
*/
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++){
}
}
}
- if( p->needFree ){
+ if( p->flags & UNPACKED_NEED_FREE ){
sqlite3DbFree(p->pKeyInfo->db, 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 */
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;
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;
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;
-}
/*
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 ){
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;
}