mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Refactor the VdbeCursor object. It is now slightly smaller and faster and is
easier to understand. FossilOrigin-Name: 9b1d174d862500a627840008ffac4c8419dc97e2
This commit is contained in:
20
manifest
20
manifest
@@ -1,5 +1,5 @@
|
||||
C In\sthe\sOP_Column\sopcode,\sonly\stest\sthe\sbtree\spayload\ssize\sfor\sexceeding\sthe\nstring\slength\slimit\sif\sthe\spayload\sdoes\snot\sfit\son\sa\ssingle\spage.
|
||||
D 2015-11-20T13:33:56.212
|
||||
C Refactor\sthe\sVdbeCursor\sobject.\s\sIt\sis\snow\sslightly\ssmaller\sand\sfaster\sand\sis\neasier\sto\sunderstand.
|
||||
D 2015-11-20T19:22:01.706
|
||||
F Makefile.in d828db6afa6c1fa060d01e33e4674408df1942a1
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc e928e68168df69b353300ac87c10105206653a03
|
||||
@@ -402,14 +402,14 @@ F src/update.c 40e51cd0883cb5bfd6abb7d8a7cd8aa47fab2945
|
||||
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
|
||||
F src/util.c fc612367108b74573c5fd13a85d0a23027f438bd
|
||||
F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
|
||||
F src/vdbe.c 7a4efb964a050fd3cd733b051ce2ef1c8d609f53
|
||||
F src/vdbe.c 9ef1b1701e133d1cdb7dc66598863993b925b069
|
||||
F src/vdbe.h efb7a8c1459e31f3ea4377824c6a7e4cb5068637
|
||||
F src/vdbeInt.h 33403622c6a8feaaac5f0f3f17f5d1bf6df42286
|
||||
F src/vdbeInt.h 75c2e82ee3357e9210c06474f8d9bdf12c81105d
|
||||
F src/vdbeapi.c 020681b943e77766b32ae1cddf86d7831b7374ca
|
||||
F src/vdbeaux.c da9eddc62e025148e30267600a6fe3882d5e912f
|
||||
F src/vdbeblob.c 565fabd302f5fca3bdf3d56cac330483616a39b6
|
||||
F src/vdbeaux.c b660c995256e3d3e2cb47ccd20b82a1c342fa093
|
||||
F src/vdbeblob.c fdc4a81605ae7a35ae94a55bd768b66d6be16f15
|
||||
F src/vdbemem.c fdd1578e47bea61390d472de53c565781d81e045
|
||||
F src/vdbesort.c 8b23930a1289526f6d2a3a9f2e965bcc963e4a68
|
||||
F src/vdbesort.c a7ec02da4494c59dfd071126dd3726be5a11459d
|
||||
F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0
|
||||
F src/vtab.c 2a8b44aa372c33f6154208e7a7f6c44254549806
|
||||
F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
|
||||
@@ -1404,7 +1404,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 5446ae64d7f92444ca40aae2108015d1d77bc03f
|
||||
R a5098759debd354cc66c1a03fdae8b41
|
||||
P 35c7f6cba6febf2480de01fca9d61b8065bf1c12
|
||||
R ae691eb0177fe2d5adc77d9ff2c7f6f3
|
||||
U drh
|
||||
Z f951ff158d10f4e00f2e4ba144c0ce20
|
||||
Z 018ade43e937d593f3f9dd76ba8e9c12
|
||||
|
@@ -1 +1 @@
|
||||
35c7f6cba6febf2480de01fca9d61b8065bf1c12
|
||||
9b1d174d862500a627840008ffac4c8419dc97e2
|
212
src/vdbe.c
212
src/vdbe.c
@@ -165,7 +165,7 @@ int sqlite3_found_count = 0;
|
||||
&& sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
|
||||
|
||||
/* Return true if the cursor was opened using the OP_OpenSorter opcode. */
|
||||
#define isSorter(x) ((x)->pSorter!=0)
|
||||
#define isSorter(x) ((x)->eCurType==CURTYPE_SORTER)
|
||||
|
||||
/*
|
||||
** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL
|
||||
@@ -176,7 +176,7 @@ static VdbeCursor *allocateCursor(
|
||||
int iCur, /* Index of the new VdbeCursor */
|
||||
int nField, /* Number of fields in the table or index */
|
||||
int iDb, /* Database the cursor belongs to, or -1 */
|
||||
int isBtreeCursor /* True for B-Tree. False for pseudo-table or vtab */
|
||||
u8 eCurType /* Type of the new cursor */
|
||||
){
|
||||
/* Find the memory cell that will be used to store the blob of memory
|
||||
** required for this VdbeCursor structure. It is convenient to use a
|
||||
@@ -202,7 +202,7 @@ static VdbeCursor *allocateCursor(
|
||||
VdbeCursor *pCx = 0;
|
||||
nByte =
|
||||
ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
|
||||
(isBtreeCursor?sqlite3BtreeCursorSize():0);
|
||||
(eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
|
||||
|
||||
assert( iCur<p->nCursor );
|
||||
if( p->apCsr[iCur] ){
|
||||
@@ -212,13 +212,14 @@ static VdbeCursor *allocateCursor(
|
||||
if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
|
||||
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
|
||||
memset(pCx, 0, sizeof(VdbeCursor));
|
||||
pCx->eCurType = eCurType;
|
||||
pCx->iDb = iDb;
|
||||
pCx->nField = nField;
|
||||
pCx->aOffset = &pCx->aType[nField];
|
||||
if( isBtreeCursor ){
|
||||
pCx->pCursor = (BtCursor*)
|
||||
if( eCurType==CURTYPE_BTREE ){
|
||||
pCx->uc.pCursor = (BtCursor*)
|
||||
&pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
|
||||
sqlite3BtreeCursorZero(pCx->pCursor);
|
||||
sqlite3BtreeCursorZero(pCx->uc.pCursor);
|
||||
}
|
||||
}
|
||||
return pCx;
|
||||
@@ -2383,21 +2384,19 @@ case OP_Column: {
|
||||
assert( pC!=0 );
|
||||
assert( p2<pC->nField );
|
||||
aOffset = pC->aOffset;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */
|
||||
#endif
|
||||
pCrsr = pC->pCursor;
|
||||
assert( pCrsr!=0 || pC->pseudoTableReg>0 ); /* pCrsr NULL on PseudoTables */
|
||||
assert( pCrsr!=0 || pC->nullRow ); /* pC->nullRow on PseudoTables */
|
||||
assert( pC->eCurType!=CURTYPE_VTAB ); /* OP_Column never called on virtual table */
|
||||
assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
|
||||
assert( pC->eCurType!=CURTYPE_SORTER );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
|
||||
/* If the cursor cache is stale, bring it up-to-date */
|
||||
rc = sqlite3VdbeCursorMoveto(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( pC->cacheStatus!=p->cacheCtr ){
|
||||
if( pC->nullRow ){
|
||||
if( pCrsr==0 ){
|
||||
assert( pC->pseudoTableReg>0 );
|
||||
pReg = &aMem[pC->pseudoTableReg];
|
||||
if( pC->eCurType==CURTYPE_PSEUDO ){
|
||||
assert( pC->uc.pseudoTableReg>0 );
|
||||
pReg = &aMem[pC->uc.pseudoTableReg];
|
||||
assert( pReg->flags & MEM_Blob );
|
||||
assert( memIsValid(pReg) );
|
||||
pC->payloadSize = pC->szRow = avail = pReg->n;
|
||||
@@ -2407,6 +2406,7 @@ case OP_Column: {
|
||||
goto op_column_out;
|
||||
}
|
||||
}else{
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pCrsr );
|
||||
if( pC->isTable==0 ){
|
||||
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
||||
@@ -2795,7 +2795,8 @@ case OP_Count: { /* out2 */
|
||||
i64 nEntry;
|
||||
BtCursor *pCrsr;
|
||||
|
||||
pCrsr = p->apCsr[pOp->p1]->pCursor;
|
||||
assert( p->apCsr[pOp->p1]->eCurType==CURTYPE_BTREE );
|
||||
pCrsr = p->apCsr[pOp->p1]->uc.pCursor;
|
||||
assert( pCrsr );
|
||||
nEntry = 0; /* Not needed. Only used to silence a warning. */
|
||||
rc = sqlite3BtreeCount(pCrsr, &nEntry);
|
||||
@@ -3380,12 +3381,12 @@ case OP_OpenWrite:
|
||||
assert( pOp->p1>=0 );
|
||||
assert( nField>=0 );
|
||||
testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */
|
||||
pCur = allocateCursor(p, pOp->p1, nField, iDb, 1);
|
||||
pCur = allocateCursor(p, pOp->p1, nField, iDb, CURTYPE_BTREE);
|
||||
if( pCur==0 ) goto no_mem;
|
||||
pCur->nullRow = 1;
|
||||
pCur->isOrdered = 1;
|
||||
pCur->pgnoRoot = p2;
|
||||
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
|
||||
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->uc.pCursor);
|
||||
pCur->pKeyInfo = pKeyInfo;
|
||||
/* Set the VdbeCursor.isTable variable. Previous versions of
|
||||
** SQLite used to check if the root-page flags were sane at this point
|
||||
@@ -3400,7 +3401,7 @@ open_cursor_set_hints:
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINT
|
||||
testcase( pOp->p2 & OPFLAG_SEEKEQ );
|
||||
#endif
|
||||
sqlite3BtreeCursorHintFlags(pCur->pCursor,
|
||||
sqlite3BtreeCursorHintFlags(pCur->uc.pCursor,
|
||||
(pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
|
||||
break;
|
||||
}
|
||||
@@ -3444,7 +3445,7 @@ case OP_OpenEphemeral: {
|
||||
SQLITE_OPEN_TRANSIENT_DB;
|
||||
assert( pOp->p1>=0 );
|
||||
assert( pOp->p2>=0 );
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
pCx->isEphemeral = 1;
|
||||
@@ -3468,11 +3469,11 @@ case OP_OpenEphemeral: {
|
||||
assert( pKeyInfo->db==db );
|
||||
assert( pKeyInfo->enc==ENC(db) );
|
||||
pCx->pKeyInfo = pKeyInfo;
|
||||
rc = sqlite3BtreeCursor(pCx->pBt, pgno, BTREE_WRCSR, pKeyInfo, pCx->pCursor);
|
||||
rc = sqlite3BtreeCursor(pCx->pBt, pgno, BTREE_WRCSR, pKeyInfo, pCx->uc.pCursor);
|
||||
}
|
||||
pCx->isTable = 0;
|
||||
}else{
|
||||
rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, BTREE_WRCSR, 0, pCx->pCursor);
|
||||
rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, BTREE_WRCSR, 0, pCx->uc.pCursor);
|
||||
pCx->isTable = 1;
|
||||
}
|
||||
}
|
||||
@@ -3495,7 +3496,7 @@ case OP_SorterOpen: {
|
||||
|
||||
assert( pOp->p1>=0 );
|
||||
assert( pOp->p2>=0 );
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_SORTER);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->pKeyInfo = pOp->p4.pKeyInfo;
|
||||
assert( pCx->pKeyInfo->db==db );
|
||||
@@ -3515,7 +3516,7 @@ case OP_SequenceTest: {
|
||||
VdbeCursor *pC;
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC->pSorter );
|
||||
assert( isSorter(pC) );
|
||||
if( (pC->seqCount++)==0 ){
|
||||
goto jump_to_p2;
|
||||
}
|
||||
@@ -3543,10 +3544,10 @@ case OP_OpenPseudo: {
|
||||
|
||||
assert( pOp->p1>=0 );
|
||||
assert( pOp->p3>=0 );
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, CURTYPE_PSEUDO);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
pCx->pseudoTableReg = pOp->p2;
|
||||
pCx->uc.pseudoTableReg = pOp->p2;
|
||||
pCx->isTable = 1;
|
||||
assert( pOp->p5==0 );
|
||||
break;
|
||||
@@ -3578,7 +3579,7 @@ case OP_Close: {
|
||||
case OP_ColumnsUsed: {
|
||||
VdbeCursor *pC;
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC->pCursor );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
pC->maskUsed = *(u64*)pOp->p4.pI64;
|
||||
break;
|
||||
}
|
||||
@@ -3686,12 +3687,12 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
assert( pOp->p2!=0 );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->pseudoTableReg==0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( OP_SeekLE == OP_SeekLT+1 );
|
||||
assert( OP_SeekGE == OP_SeekLT+2 );
|
||||
assert( OP_SeekGT == OP_SeekLT+3 );
|
||||
assert( pC->isOrdered );
|
||||
assert( pC->pCursor!=0 );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
oc = pOp->opcode;
|
||||
eqOnly = 0;
|
||||
pC->nullRow = 0;
|
||||
@@ -3701,7 +3702,7 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
|
||||
if( pC->isTable ){
|
||||
/* The BTREE_SEEK_EQ flag is only set on index cursors */
|
||||
assert( sqlite3BtreeCursorHasHint(pC->pCursor, BTREE_SEEK_EQ)==0 );
|
||||
assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0 );
|
||||
|
||||
/* The input value in P3 might be of any type: integer, real, string,
|
||||
** blob, or NULL. But it needs to be an integer before we can do
|
||||
@@ -3745,7 +3746,7 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++;
|
||||
}
|
||||
}
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res);
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res);
|
||||
pC->movetoTarget = iKey; /* Used by OP_Delete */
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
@@ -3755,7 +3756,7 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
** OP_SeekLE opcodes are allowed, and these must be immediately followed
|
||||
** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key.
|
||||
*/
|
||||
if( sqlite3BtreeCursorHasHint(pC->pCursor, BTREE_SEEK_EQ) ){
|
||||
if( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ) ){
|
||||
eqOnly = 1;
|
||||
assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
|
||||
assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
|
||||
@@ -3790,7 +3791,7 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
#endif
|
||||
ExpandBlob(r.aMem);
|
||||
r.eqSeen = 0;
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res);
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, &r, 0, 0, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
@@ -3807,7 +3808,7 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT );
|
||||
if( res<0 || (res==0 && oc==OP_SeekGT) ){
|
||||
res = 0;
|
||||
rc = sqlite3BtreeNext(pC->pCursor, &res);
|
||||
rc = sqlite3BtreeNext(pC->uc.pCursor, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
}else{
|
||||
res = 0;
|
||||
@@ -3816,13 +3817,13 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
assert( oc==OP_SeekLT || oc==OP_SeekLE );
|
||||
if( res>0 || (res==0 && oc==OP_SeekLT) ){
|
||||
res = 0;
|
||||
rc = sqlite3BtreePrevious(pC->pCursor, &res);
|
||||
rc = sqlite3BtreePrevious(pC->uc.pCursor, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
}else{
|
||||
/* res might be negative because the table is empty. Check to
|
||||
** see if this is the case.
|
||||
*/
|
||||
res = sqlite3BtreeEof(pC->pCursor);
|
||||
res = sqlite3BtreeEof(pC->uc.pCursor);
|
||||
}
|
||||
}
|
||||
seek_not_found:
|
||||
@@ -3853,7 +3854,8 @@ case OP_Seek: { /* in2 */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->pCursor!=0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
assert( pC->isTable );
|
||||
pC->nullRow = 0;
|
||||
pIn2 = &aMem[pOp->p2];
|
||||
@@ -3947,7 +3949,8 @@ case OP_Found: { /* jump, in3 */
|
||||
pC->seekOp = pOp->opcode;
|
||||
#endif
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
assert( pC->pCursor!=0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
assert( pC->isTable==0 );
|
||||
pFree = 0;
|
||||
if( pOp->p4.i>0 ){
|
||||
@@ -3984,7 +3987,7 @@ case OP_Found: { /* jump, in3 */
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res);
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res);
|
||||
sqlite3DbFree(db, pFree);
|
||||
if( rc!=SQLITE_OK ){
|
||||
break;
|
||||
@@ -4038,8 +4041,8 @@ case OP_NotExists: { /* jump, in3 */
|
||||
pC->seekOp = 0;
|
||||
#endif
|
||||
assert( pC->isTable );
|
||||
assert( pC->pseudoTableReg==0 );
|
||||
pCrsr = pC->pCursor;
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pCrsr!=0 );
|
||||
res = 0;
|
||||
iKey = pIn3->u.i;
|
||||
@@ -4073,6 +4076,7 @@ case OP_NotExists: { /* jump, in3 */
|
||||
case OP_Sequence: { /* out2 */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
assert( p->apCsr[pOp->p1]!=0 );
|
||||
assert( p->apCsr[pOp->p1]->eCurType!=CURTYPE_VTAB );
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOut->u.i = p->apCsr[pOp->p1]->seqCount++;
|
||||
break;
|
||||
@@ -4108,7 +4112,8 @@ case OP_NewRowid: { /* out2 */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->pCursor!=0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
{
|
||||
/* The next rowid or record number (different terms for the same
|
||||
** thing) is obtained in a two-step algorithm.
|
||||
@@ -4136,15 +4141,15 @@ case OP_NewRowid: { /* out2 */
|
||||
#endif
|
||||
|
||||
if( !pC->useRandomRowid ){
|
||||
rc = sqlite3BtreeLast(pC->pCursor, &res);
|
||||
rc = sqlite3BtreeLast(pC->uc.pCursor, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
if( res ){
|
||||
v = 1; /* IMP: R-61914-48074 */
|
||||
}else{
|
||||
assert( sqlite3BtreeCursorIsValid(pC->pCursor) );
|
||||
rc = sqlite3BtreeKeySize(pC->pCursor, &v);
|
||||
assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) );
|
||||
rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v);
|
||||
assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */
|
||||
if( v>=MAX_ROWID ){
|
||||
pC->useRandomRowid = 1;
|
||||
@@ -4195,7 +4200,7 @@ case OP_NewRowid: { /* out2 */
|
||||
do{
|
||||
sqlite3_randomness(sizeof(v), &v);
|
||||
v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */
|
||||
}while( ((rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)v,
|
||||
}while( ((rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)v,
|
||||
0, &res))==SQLITE_OK)
|
||||
&& (res==0)
|
||||
&& (++cnt<100));
|
||||
@@ -4275,8 +4280,8 @@ case OP_InsertInt: {
|
||||
assert( memIsValid(pData) );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->pCursor!=0 );
|
||||
assert( pC->pseudoTableReg==0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
assert( pC->isTable );
|
||||
REGISTER_TRACE(pOp->p2, pData);
|
||||
|
||||
@@ -4305,7 +4310,7 @@ case OP_InsertInt: {
|
||||
}else{
|
||||
nZero = 0;
|
||||
}
|
||||
rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
|
||||
rc = sqlite3BtreeInsert(pC->uc.pCursor, 0, iKey,
|
||||
pData->z, pData->n, nZero,
|
||||
(pOp->p5 & OPFLAG_APPEND)!=0, seekResult
|
||||
);
|
||||
@@ -4352,12 +4357,13 @@ case OP_Delete: {
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
assert( pC->deferredMoveto==0 );
|
||||
|
||||
hasUpdateCallback = db->xUpdateCallback && pOp->p4.z && pC->isTable;
|
||||
if( pOp->p5 && hasUpdateCallback ){
|
||||
sqlite3BtreeKeySize(pC->pCursor, &pC->movetoTarget);
|
||||
sqlite3BtreeKeySize(pC->uc.pCursor, &pC->movetoTarget);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -4366,12 +4372,12 @@ case OP_Delete: {
|
||||
** is being deleted */
|
||||
if( pOp->p4.z && pC->isTable && pOp->p5==0 ){
|
||||
i64 iKey = 0;
|
||||
sqlite3BtreeKeySize(pC->pCursor, &iKey);
|
||||
sqlite3BtreeKeySize(pC->uc.pCursor, &iKey);
|
||||
assert( pC->movetoTarget==iKey );
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = sqlite3BtreeDelete(pC->pCursor, pOp->p5);
|
||||
rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
|
||||
/* Invoke the update-hook if required. */
|
||||
@@ -4488,14 +4494,14 @@ case OP_RowData: {
|
||||
/* Note that RowKey and RowData are really exactly the same instruction */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( isSorter(pC)==0 );
|
||||
assert( pC->isTable || pOp->opcode!=OP_RowData );
|
||||
assert( pC->isTable==0 || pOp->opcode==OP_RowData );
|
||||
assert( pC!=0 );
|
||||
assert( pC->nullRow==0 );
|
||||
assert( pC->pseudoTableReg==0 );
|
||||
assert( pC->pCursor!=0 );
|
||||
pCrsr = pC->pCursor;
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
|
||||
/* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or
|
||||
** OP_Rewind/Op_Next with no intervening instructions that might invalidate
|
||||
@@ -4563,29 +4569,31 @@ case OP_Rowid: { /* out2 */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->pseudoTableReg==0 || pC->nullRow );
|
||||
assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
|
||||
if( pC->nullRow ){
|
||||
pOut->flags = MEM_Null;
|
||||
break;
|
||||
}else if( pC->deferredMoveto ){
|
||||
v = pC->movetoTarget;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
}else if( pC->pVtabCursor ){
|
||||
pVtab = pC->pVtabCursor->pVtab;
|
||||
}else if( pC->eCurType==CURTYPE_VTAB ){
|
||||
assert( pC->uc.pVCur!=0 );
|
||||
pVtab = pC->uc.pVCur->pVtab;
|
||||
pModule = pVtab->pModule;
|
||||
assert( pModule->xRowid );
|
||||
rc = pModule->xRowid(pC->pVtabCursor, &v);
|
||||
rc = pModule->xRowid(pC->uc.pVCur, &v);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
}else{
|
||||
assert( pC->pCursor!=0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
rc = sqlite3VdbeCursorRestore(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( pC->nullRow ){
|
||||
pOut->flags = MEM_Null;
|
||||
break;
|
||||
}
|
||||
rc = sqlite3BtreeKeySize(pC->pCursor, &v);
|
||||
rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v);
|
||||
assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */
|
||||
}
|
||||
pOut->u.i = v;
|
||||
@@ -4606,8 +4614,9 @@ case OP_NullRow: {
|
||||
assert( pC!=0 );
|
||||
pC->nullRow = 1;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
if( pC->pCursor ){
|
||||
sqlite3BtreeClearCursor(pC->pCursor);
|
||||
if( pC->eCurType==CURTYPE_BTREE ){
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
sqlite3BtreeClearCursor(pC->uc.pCursor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -4632,7 +4641,8 @@ case OP_Last: { /* jump */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
pCrsr = pC->pCursor;
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
res = 0;
|
||||
assert( pCrsr!=0 );
|
||||
rc = sqlite3BtreeLast(pCrsr, &res);
|
||||
@@ -4700,7 +4710,8 @@ case OP_Rewind: { /* jump */
|
||||
if( isSorter(pC) ){
|
||||
rc = sqlite3VdbeSorterRewind(pC, &res);
|
||||
}else{
|
||||
pCrsr = pC->pCursor;
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pCrsr );
|
||||
rc = sqlite3BtreeFirst(pCrsr, &res);
|
||||
pC->deferredMoveto = 0;
|
||||
@@ -4797,7 +4808,7 @@ case OP_Next: /* jump */
|
||||
res = pOp->p3;
|
||||
assert( pC!=0 );
|
||||
assert( pC->deferredMoveto==0 );
|
||||
assert( pC->pCursor );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( res==0 || (res==1 && pC->isTable==0) );
|
||||
testcase( res==1 );
|
||||
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
|
||||
@@ -4814,7 +4825,7 @@ case OP_Next: /* jump */
|
||||
|| pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
|
||||
|| pC->seekOp==OP_Last );
|
||||
|
||||
rc = pOp->p4.xAdvance(pC->pCursor, &res);
|
||||
rc = pOp->p4.xAdvance(pC->uc.pCursor, &res);
|
||||
next_tail:
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
VdbeBranchTaken(res==0,2);
|
||||
@@ -4865,7 +4876,7 @@ case OP_IdxInsert: { /* in2 */
|
||||
pIn2 = &aMem[pOp->p2];
|
||||
assert( pIn2->flags & MEM_Blob );
|
||||
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
|
||||
assert( pC->pCursor!=0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert );
|
||||
assert( pC->isTable==0 );
|
||||
rc = ExpandBlob(pIn2);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -4874,7 +4885,7 @@ case OP_IdxInsert: { /* in2 */
|
||||
}else{
|
||||
nKey = pIn2->n;
|
||||
zKey = pIn2->z;
|
||||
rc = sqlite3BtreeInsert(pC->pCursor, zKey, nKey, "", 0, 0, pOp->p3,
|
||||
rc = sqlite3BtreeInsert(pC->uc.pCursor, zKey, nKey, "", 0, 0, pOp->p3,
|
||||
((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
|
||||
);
|
||||
assert( pC->deferredMoveto==0 );
|
||||
@@ -4902,7 +4913,8 @@ case OP_IdxDelete: {
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
pCrsr = pC->pCursor;
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pCrsr!=0 );
|
||||
assert( pOp->p5==0 );
|
||||
r.pKeyInfo = pC->pKeyInfo;
|
||||
@@ -4939,7 +4951,8 @@ case OP_IdxRowid: { /* out2 */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
pCrsr = pC->pCursor;
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pCrsr!=0 );
|
||||
pOut->flags = MEM_Null;
|
||||
assert( pC->isTable==0 );
|
||||
@@ -5020,7 +5033,8 @@ case OP_IdxGE: { /* jump */
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->isOrdered );
|
||||
assert( pC->pCursor!=0);
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->uc.pCursor!=0);
|
||||
assert( pC->deferredMoveto==0 );
|
||||
assert( pOp->p5==0 || pOp->p5==1 );
|
||||
assert( pOp->p4type==P4_INT32 );
|
||||
@@ -5153,11 +5167,12 @@ case OP_ResetSorter: {
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
if( pC->pSorter ){
|
||||
sqlite3VdbeSorterReset(db, pC->pSorter);
|
||||
if( isSorter(pC) ){
|
||||
sqlite3VdbeSorterReset(db, pC->uc.pSorter);
|
||||
}else{
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->isEphemeral );
|
||||
rc = sqlite3BtreeClearTableOfCursor(pC->pCursor);
|
||||
rc = sqlite3BtreeClearTableOfCursor(pC->uc.pCursor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -6231,33 +6246,33 @@ case OP_VDestroy: {
|
||||
*/
|
||||
case OP_VOpen: {
|
||||
VdbeCursor *pCur;
|
||||
sqlite3_vtab_cursor *pVtabCursor;
|
||||
sqlite3_vtab_cursor *pVCur;
|
||||
sqlite3_vtab *pVtab;
|
||||
const sqlite3_module *pModule;
|
||||
|
||||
assert( p->bIsReader );
|
||||
pCur = 0;
|
||||
pVtabCursor = 0;
|
||||
pVCur = 0;
|
||||
pVtab = pOp->p4.pVtab->pVtab;
|
||||
if( pVtab==0 || NEVER(pVtab->pModule==0) ){
|
||||
rc = SQLITE_LOCKED;
|
||||
break;
|
||||
}
|
||||
pModule = pVtab->pModule;
|
||||
rc = pModule->xOpen(pVtab, &pVtabCursor);
|
||||
rc = pModule->xOpen(pVtab, &pVCur);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
if( SQLITE_OK==rc ){
|
||||
/* Initialize sqlite3_vtab_cursor base class */
|
||||
pVtabCursor->pVtab = pVtab;
|
||||
pVCur->pVtab = pVtab;
|
||||
|
||||
/* Initialize vdbe cursor object */
|
||||
pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
|
||||
pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB);
|
||||
if( pCur ){
|
||||
pCur->pVtabCursor = pVtabCursor;
|
||||
pCur->uc.pVCur = pVCur;
|
||||
pVtab->nRef++;
|
||||
}else{
|
||||
assert( db->mallocFailed );
|
||||
pModule->xClose(pVtabCursor);
|
||||
pModule->xClose(pVCur);
|
||||
goto no_mem;
|
||||
}
|
||||
}
|
||||
@@ -6291,7 +6306,7 @@ case OP_VFilter: { /* jump */
|
||||
const sqlite3_module *pModule;
|
||||
Mem *pQuery;
|
||||
Mem *pArgc;
|
||||
sqlite3_vtab_cursor *pVtabCursor;
|
||||
sqlite3_vtab_cursor *pVCur;
|
||||
sqlite3_vtab *pVtab;
|
||||
VdbeCursor *pCur;
|
||||
int res;
|
||||
@@ -6303,9 +6318,9 @@ case OP_VFilter: { /* jump */
|
||||
pCur = p->apCsr[pOp->p1];
|
||||
assert( memIsValid(pQuery) );
|
||||
REGISTER_TRACE(pOp->p3, pQuery);
|
||||
assert( pCur->pVtabCursor );
|
||||
pVtabCursor = pCur->pVtabCursor;
|
||||
pVtab = pVtabCursor->pVtab;
|
||||
assert( pCur->eCurType==CURTYPE_VTAB );
|
||||
pVCur = pCur->uc.pVCur;
|
||||
pVtab = pVCur->pVtab;
|
||||
pModule = pVtab->pModule;
|
||||
|
||||
/* Grab the index number and argc parameters */
|
||||
@@ -6319,10 +6334,10 @@ case OP_VFilter: { /* jump */
|
||||
for(i = 0; i<nArg; i++){
|
||||
apArg[i] = &pArgc[i+1];
|
||||
}
|
||||
rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
|
||||
rc = pModule->xFilter(pVCur, iQuery, pOp->p4.z, nArg, apArg);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
if( rc==SQLITE_OK ){
|
||||
res = pModule->xEof(pVtabCursor);
|
||||
res = pModule->xEof(pVCur);
|
||||
}
|
||||
pCur->nullRow = 0;
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
@@ -6346,7 +6361,7 @@ case OP_VColumn: {
|
||||
sqlite3_context sContext;
|
||||
|
||||
VdbeCursor *pCur = p->apCsr[pOp->p1];
|
||||
assert( pCur->pVtabCursor );
|
||||
assert( pCur->eCurType==CURTYPE_VTAB );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
@@ -6354,13 +6369,13 @@ case OP_VColumn: {
|
||||
sqlite3VdbeMemSetNull(pDest);
|
||||
break;
|
||||
}
|
||||
pVtab = pCur->pVtabCursor->pVtab;
|
||||
pVtab = pCur->uc.pVCur->pVtab;
|
||||
pModule = pVtab->pModule;
|
||||
assert( pModule->xColumn );
|
||||
memset(&sContext, 0, sizeof(sContext));
|
||||
sContext.pOut = pDest;
|
||||
MemSetTypeFlag(pDest, MEM_Null);
|
||||
rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
|
||||
rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
if( sContext.isError ){
|
||||
rc = sContext.isError;
|
||||
@@ -6391,11 +6406,11 @@ case OP_VNext: { /* jump */
|
||||
|
||||
res = 0;
|
||||
pCur = p->apCsr[pOp->p1];
|
||||
assert( pCur->pVtabCursor );
|
||||
assert( pCur->eCurType==CURTYPE_VTAB );
|
||||
if( pCur->nullRow ){
|
||||
break;
|
||||
}
|
||||
pVtab = pCur->pVtabCursor->pVtab;
|
||||
pVtab = pCur->uc.pVCur->pVtab;
|
||||
pModule = pVtab->pModule;
|
||||
assert( pModule->xNext );
|
||||
|
||||
@@ -6405,10 +6420,10 @@ case OP_VNext: { /* jump */
|
||||
** data is available) and the error code returned when xColumn or
|
||||
** some other method is next invoked on the save virtual table cursor.
|
||||
*/
|
||||
rc = pModule->xNext(pCur->pVtabCursor);
|
||||
rc = pModule->xNext(pCur->uc.pVCur);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
if( rc==SQLITE_OK ){
|
||||
res = pModule->xEof(pCur->pVtabCursor);
|
||||
res = pModule->xEof(pCur->uc.pVCur);
|
||||
}
|
||||
VdbeBranchTaken(!res,2);
|
||||
if( !res ){
|
||||
@@ -6632,7 +6647,8 @@ case OP_CursorHint: {
|
||||
assert( pOp->p4type==P4_EXPR );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
if( pC ){
|
||||
sqlite3BtreeCursorHint(pC->pCursor, BTREE_HINT_RANGE, pOp->p4.pExpr, aMem);
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
sqlite3BtreeCursorHint(pC->uc.pCursor, BTREE_HINT_RANGE, pOp->p4.pExpr, aMem);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@@ -58,42 +58,48 @@ typedef struct Explain Explain;
|
||||
/* Elements of the linked list at Vdbe.pAuxData */
|
||||
typedef struct AuxData AuxData;
|
||||
|
||||
/* Types of VDBE cursors */
|
||||
#define CURTYPE_BTREE 0
|
||||
#define CURTYPE_SORTER 1
|
||||
#define CURTYPE_VTAB 2
|
||||
#define CURTYPE_PSEUDO 3
|
||||
|
||||
/*
|
||||
** A cursor is a pointer into a single BTree within a database file.
|
||||
** The cursor can seek to a BTree entry with a particular key, or
|
||||
** loop over all entries of the Btree. You can also insert new BTree
|
||||
** entries or retrieve the key or data from the entry that the cursor
|
||||
** is currently pointing to.
|
||||
** A VdbeCursor is an superclass (a wrapper) for various cursor objects:
|
||||
**
|
||||
** Cursors can also point to virtual tables, sorters, or "pseudo-tables".
|
||||
** A pseudo-table is a single-row table implemented by registers.
|
||||
**
|
||||
** Every cursor that the virtual machine has open is represented by an
|
||||
** instance of the following structure.
|
||||
** * A b-tree cursor
|
||||
** - In the main database or in an ephemeral database
|
||||
** - On either an index or a table
|
||||
** * A sorter
|
||||
** * A virtual table
|
||||
** * A one-row "pseudotable" stored in a single register
|
||||
*/
|
||||
struct VdbeCursor {
|
||||
BtCursor *pCursor; /* The cursor structure of the backend */
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
|
||||
int seekResult; /* Result of previous sqlite3BtreeMoveto() */
|
||||
int pseudoTableReg; /* Register holding pseudotable content. */
|
||||
i16 nField; /* Number of fields in the header */
|
||||
u16 nHdrParsed; /* Number of header fields parsed so far */
|
||||
#ifdef SQLITE_DEBUG
|
||||
u8 seekOp; /* Most recent seek operation on this cursor */
|
||||
#endif
|
||||
u8 eCurType; /* One of the CURTYPE_* values above */
|
||||
i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
|
||||
u8 nullRow; /* True if pointing to a row with no data */
|
||||
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
|
||||
u8 isTable; /* True for rowid tables. False for indexes */
|
||||
#ifdef SQLITE_DEBUG
|
||||
u8 seekOp; /* Most recent seek operation on this cursor */
|
||||
#endif
|
||||
Bool isEphemeral:1; /* True for an ephemeral table */
|
||||
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
|
||||
Bool isTable:1; /* True if a table requiring integer keys */
|
||||
Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
|
||||
Pgno pgnoRoot; /* Root page of the open btree cursor */
|
||||
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
|
||||
i16 nField; /* Number of fields in the header */
|
||||
u16 nHdrParsed; /* Number of header fields parsed so far */
|
||||
union {
|
||||
BtCursor *pCursor; /* CURTYPE_BTREE. Btree cursor */
|
||||
sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */
|
||||
int pseudoTableReg; /* CURTYPE_PSEUDO. Reg holding content. */
|
||||
VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */
|
||||
} uc;
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
|
||||
int seekResult; /* Result of previous sqlite3BtreeMoveto() */
|
||||
i64 seqCount; /* Sequence counter */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
|
||||
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
|
||||
u64 maskUsed; /* Mask of columns used by this cursor */
|
||||
#endif
|
||||
|
@@ -1930,23 +1930,34 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
||||
if( pCx==0 ){
|
||||
return;
|
||||
}
|
||||
assert( pCx->pBt==0 || pCx->eCurType==CURTYPE_BTREE );
|
||||
switch( pCx->eCurType ){
|
||||
case CURTYPE_SORTER: {
|
||||
sqlite3VdbeSorterClose(p->db, pCx);
|
||||
break;
|
||||
}
|
||||
case CURTYPE_BTREE: {
|
||||
if( pCx->pBt ){
|
||||
sqlite3BtreeClose(pCx->pBt);
|
||||
/* The pCx->pCursor will be close automatically, if it exists, by
|
||||
** the call above. */
|
||||
}else if( pCx->pCursor ){
|
||||
sqlite3BtreeCloseCursor(pCx->pCursor);
|
||||
}else{
|
||||
assert( pCx->uc.pCursor!=0 );
|
||||
sqlite3BtreeCloseCursor(pCx->uc.pCursor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
else if( pCx->pVtabCursor ){
|
||||
sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
|
||||
const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
|
||||
assert( pVtabCursor->pVtab->nRef>0 );
|
||||
pVtabCursor->pVtab->nRef--;
|
||||
pModule->xClose(pVtabCursor);
|
||||
case CURTYPE_VTAB: {
|
||||
sqlite3_vtab_cursor *pVCur = pCx->uc.pVCur;
|
||||
const sqlite3_module *pModule = pVCur->pVtab->pModule;
|
||||
assert( pVCur->pVtab->nRef>0 );
|
||||
pVCur->pVtab->nRef--;
|
||||
pModule->xClose(pVCur);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2933,7 +2944,8 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
|
||||
#endif
|
||||
assert( p->deferredMoveto );
|
||||
assert( p->isTable );
|
||||
rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
|
||||
assert( p->eCurType==CURTYPE_BTREE );
|
||||
rc = sqlite3BtreeMovetoUnpacked(p->uc.pCursor, 0, p->movetoTarget, 0, &res);
|
||||
if( rc ) return rc;
|
||||
if( res!=0 ) return SQLITE_CORRUPT_BKPT;
|
||||
#ifdef SQLITE_TEST
|
||||
@@ -2953,9 +2965,10 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
|
||||
*/
|
||||
static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
|
||||
int isDifferentRow, rc;
|
||||
assert( p->pCursor!=0 );
|
||||
assert( sqlite3BtreeCursorHasMoved(p->pCursor) );
|
||||
rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow);
|
||||
assert( p->eCurType==CURTYPE_BTREE );
|
||||
assert( p->uc.pCursor!=0 );
|
||||
assert( sqlite3BtreeCursorHasMoved(p->uc.pCursor) );
|
||||
rc = sqlite3BtreeCursorRestore(p->uc.pCursor, &isDifferentRow);
|
||||
p->cacheStatus = CACHE_STALE;
|
||||
if( isDifferentRow ) p->nullRow = 1;
|
||||
return rc;
|
||||
@@ -2966,7 +2979,8 @@ static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
|
||||
** if need be. Return any I/O error from the restore operation.
|
||||
*/
|
||||
int sqlite3VdbeCursorRestore(VdbeCursor *p){
|
||||
if( sqlite3BtreeCursorHasMoved(p->pCursor) ){
|
||||
assert( p->eCurType==CURTYPE_BTREE );
|
||||
if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
|
||||
return handleMovedCursor(p);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
@@ -2986,12 +3000,14 @@ int sqlite3VdbeCursorRestore(VdbeCursor *p){
|
||||
** not been deleted out from under the cursor, then this routine is a no-op.
|
||||
*/
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor *p){
|
||||
if( p->eCurType==CURTYPE_BTREE ){
|
||||
if( p->deferredMoveto ){
|
||||
return handleDeferredMoveto(p);
|
||||
}
|
||||
if( p->pCursor && sqlite3BtreeCursorHasMoved(p->pCursor) ){
|
||||
if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
|
||||
return handleMovedCursor(p);
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -4303,9 +4319,11 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
){
|
||||
i64 nCellKey = 0;
|
||||
int rc;
|
||||
BtCursor *pCur = pC->pCursor;
|
||||
BtCursor *pCur;
|
||||
Mem m;
|
||||
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
pCur = pC->uc.pCursor;
|
||||
assert( sqlite3BtreeCursorIsValid(pCur) );
|
||||
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
|
||||
assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */
|
||||
@@ -4316,7 +4334,7 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
sqlite3VdbeMemInit(&m, db, 0);
|
||||
rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (u32)nCellKey, 1, &m);
|
||||
rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
|
@@ -76,7 +76,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
|
||||
}else{
|
||||
p->iOffset = pC->aType[p->iCol + pC->nField];
|
||||
p->nByte = sqlite3VdbeSerialTypeLen(type);
|
||||
p->pCsr = pC->pCursor;
|
||||
p->pCsr = pC->uc.pCursor;
|
||||
sqlite3BtreeIncrblobCursor(p->pCsr);
|
||||
}
|
||||
}
|
||||
|
@@ -961,11 +961,12 @@ int sqlite3VdbeSorterInit(
|
||||
#endif
|
||||
|
||||
assert( pCsr->pKeyInfo && pCsr->pBt==0 );
|
||||
assert( pCsr->eCurType==CURTYPE_SORTER );
|
||||
szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*);
|
||||
sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
|
||||
|
||||
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
|
||||
pCsr->pSorter = pSorter;
|
||||
pCsr->uc.pSorter = pSorter;
|
||||
if( pSorter==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1249,12 +1250,14 @@ void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
|
||||
** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
|
||||
*/
|
||||
void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
|
||||
VdbeSorter *pSorter = pCsr->pSorter;
|
||||
VdbeSorter *pSorter;
|
||||
assert( pCsr->eCurType==CURTYPE_SORTER );
|
||||
pSorter = pCsr->uc.pSorter;
|
||||
if( pSorter ){
|
||||
sqlite3VdbeSorterReset(db, pSorter);
|
||||
sqlite3_free(pSorter->list.aMemory);
|
||||
sqlite3DbFree(db, pSorter);
|
||||
pCsr->pSorter = 0;
|
||||
pCsr->uc.pSorter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1752,15 +1755,16 @@ int sqlite3VdbeSorterWrite(
|
||||
const VdbeCursor *pCsr, /* Sorter cursor */
|
||||
Mem *pVal /* Memory cell containing record */
|
||||
){
|
||||
VdbeSorter *pSorter = pCsr->pSorter;
|
||||
VdbeSorter *pSorter;
|
||||
int rc = SQLITE_OK; /* Return Code */
|
||||
SorterRecord *pNew; /* New list element */
|
||||
|
||||
int bFlush; /* True to flush contents of memory to PMA */
|
||||
int nReq; /* Bytes of memory required */
|
||||
int nPMA; /* Bytes of PMA space required */
|
||||
int t; /* serial type of first record field */
|
||||
|
||||
assert( pCsr->eCurType==CURTYPE_SORTER );
|
||||
pSorter = pCsr->uc.pSorter;
|
||||
getVarint32((const u8*)&pVal->z[1], t);
|
||||
if( t>0 && t<10 && t!=7 ){
|
||||
pSorter->typeMask &= SORTER_TYPE_INTEGER;
|
||||
@@ -2552,9 +2556,11 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
|
||||
** in sorted order.
|
||||
*/
|
||||
int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
|
||||
VdbeSorter *pSorter = pCsr->pSorter;
|
||||
VdbeSorter *pSorter;
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
|
||||
assert( pCsr->eCurType==CURTYPE_SORTER );
|
||||
pSorter = pCsr->uc.pSorter;
|
||||
assert( pSorter );
|
||||
|
||||
/* If no data has been written to disk, then do not do so now. Instead,
|
||||
@@ -2598,9 +2604,11 @@ int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
|
||||
** Advance to the next element in the sorter.
|
||||
*/
|
||||
int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
|
||||
VdbeSorter *pSorter = pCsr->pSorter;
|
||||
VdbeSorter *pSorter;
|
||||
int rc; /* Return code */
|
||||
|
||||
assert( pCsr->eCurType==CURTYPE_SORTER );
|
||||
pSorter = pCsr->uc.pSorter;
|
||||
assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) );
|
||||
if( pSorter->bUsePMA ){
|
||||
assert( pSorter->pReader==0 || pSorter->pMerger==0 );
|
||||
@@ -2660,9 +2668,11 @@ static void *vdbeSorterRowkey(
|
||||
** Copy the current sorter key into the memory cell pOut.
|
||||
*/
|
||||
int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){
|
||||
VdbeSorter *pSorter = pCsr->pSorter;
|
||||
VdbeSorter *pSorter;
|
||||
void *pKey; int nKey; /* Sorter key to copy into pOut */
|
||||
|
||||
assert( pCsr->eCurType==CURTYPE_SORTER );
|
||||
pSorter = pCsr->uc.pSorter;
|
||||
pKey = vdbeSorterRowkey(pSorter, &nKey);
|
||||
if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){
|
||||
return SQLITE_NOMEM;
|
||||
@@ -2696,12 +2706,16 @@ int sqlite3VdbeSorterCompare(
|
||||
int nKeyCol, /* Compare this many columns */
|
||||
int *pRes /* OUT: Result of comparison */
|
||||
){
|
||||
VdbeSorter *pSorter = pCsr->pSorter;
|
||||
UnpackedRecord *r2 = pSorter->pUnpacked;
|
||||
KeyInfo *pKeyInfo = pCsr->pKeyInfo;
|
||||
VdbeSorter *pSorter;
|
||||
UnpackedRecord *r2;
|
||||
KeyInfo *pKeyInfo;
|
||||
int i;
|
||||
void *pKey; int nKey; /* Sorter key to compare pVal with */
|
||||
|
||||
assert( pCsr->eCurType==CURTYPE_SORTER );
|
||||
pSorter = pCsr->uc.pSorter;
|
||||
r2 = pSorter->pUnpacked;
|
||||
pKeyInfo = pCsr->pKeyInfo;
|
||||
if( r2==0 ){
|
||||
char *p;
|
||||
r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p);
|
||||
|
Reference in New Issue
Block a user