1
0
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:
drh
2015-11-20 19:22:01 +00:00
parent 5f7dacb443
commit c960dcbace
7 changed files with 225 additions and 171 deletions

View File

@@ -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. C Refactor\sthe\sVdbeCursor\sobject.\s\sIt\sis\snow\sslightly\ssmaller\sand\sfaster\sand\sis\neasier\sto\sunderstand.
D 2015-11-20T13:33:56.212 D 2015-11-20T19:22:01.706
F Makefile.in d828db6afa6c1fa060d01e33e4674408df1942a1 F Makefile.in d828db6afa6c1fa060d01e33e4674408df1942a1
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc e928e68168df69b353300ac87c10105206653a03 F Makefile.msc e928e68168df69b353300ac87c10105206653a03
@@ -402,14 +402,14 @@ F src/update.c 40e51cd0883cb5bfd6abb7d8a7cd8aa47fab2945
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
F src/util.c fc612367108b74573c5fd13a85d0a23027f438bd F src/util.c fc612367108b74573c5fd13a85d0a23027f438bd
F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701 F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
F src/vdbe.c 7a4efb964a050fd3cd733b051ce2ef1c8d609f53 F src/vdbe.c 9ef1b1701e133d1cdb7dc66598863993b925b069
F src/vdbe.h efb7a8c1459e31f3ea4377824c6a7e4cb5068637 F src/vdbe.h efb7a8c1459e31f3ea4377824c6a7e4cb5068637
F src/vdbeInt.h 33403622c6a8feaaac5f0f3f17f5d1bf6df42286 F src/vdbeInt.h 75c2e82ee3357e9210c06474f8d9bdf12c81105d
F src/vdbeapi.c 020681b943e77766b32ae1cddf86d7831b7374ca F src/vdbeapi.c 020681b943e77766b32ae1cddf86d7831b7374ca
F src/vdbeaux.c da9eddc62e025148e30267600a6fe3882d5e912f F src/vdbeaux.c b660c995256e3d3e2cb47ccd20b82a1c342fa093
F src/vdbeblob.c 565fabd302f5fca3bdf3d56cac330483616a39b6 F src/vdbeblob.c fdc4a81605ae7a35ae94a55bd768b66d6be16f15
F src/vdbemem.c fdd1578e47bea61390d472de53c565781d81e045 F src/vdbemem.c fdd1578e47bea61390d472de53c565781d81e045
F src/vdbesort.c 8b23930a1289526f6d2a3a9f2e965bcc963e4a68 F src/vdbesort.c a7ec02da4494c59dfd071126dd3726be5a11459d
F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0 F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0
F src/vtab.c 2a8b44aa372c33f6154208e7a7f6c44254549806 F src/vtab.c 2a8b44aa372c33f6154208e7a7f6c44254549806
F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
@@ -1404,7 +1404,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 5446ae64d7f92444ca40aae2108015d1d77bc03f P 35c7f6cba6febf2480de01fca9d61b8065bf1c12
R a5098759debd354cc66c1a03fdae8b41 R ae691eb0177fe2d5adc77d9ff2c7f6f3
U drh U drh
Z f951ff158d10f4e00f2e4ba144c0ce20 Z 018ade43e937d593f3f9dd76ba8e9c12

View File

@@ -1 +1 @@
35c7f6cba6febf2480de01fca9d61b8065bf1c12 9b1d174d862500a627840008ffac4c8419dc97e2

View File

@@ -165,7 +165,7 @@ int sqlite3_found_count = 0;
&& sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;} && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
/* Return true if the cursor was opened using the OP_OpenSorter opcode. */ /* 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 ** 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 iCur, /* Index of the new VdbeCursor */
int nField, /* Number of fields in the table or index */ int nField, /* Number of fields in the table or index */
int iDb, /* Database the cursor belongs to, or -1 */ 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 /* 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 ** required for this VdbeCursor structure. It is convenient to use a
@@ -202,7 +202,7 @@ static VdbeCursor *allocateCursor(
VdbeCursor *pCx = 0; VdbeCursor *pCx = 0;
nByte = nByte =
ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField + ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
(isBtreeCursor?sqlite3BtreeCursorSize():0); (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
assert( iCur<p->nCursor ); assert( iCur<p->nCursor );
if( p->apCsr[iCur] ){ if( p->apCsr[iCur] ){
@@ -212,13 +212,14 @@ static VdbeCursor *allocateCursor(
if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){ if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z; p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
memset(pCx, 0, sizeof(VdbeCursor)); memset(pCx, 0, sizeof(VdbeCursor));
pCx->eCurType = eCurType;
pCx->iDb = iDb; pCx->iDb = iDb;
pCx->nField = nField; pCx->nField = nField;
pCx->aOffset = &pCx->aType[nField]; pCx->aOffset = &pCx->aType[nField];
if( isBtreeCursor ){ if( eCurType==CURTYPE_BTREE ){
pCx->pCursor = (BtCursor*) pCx->uc.pCursor = (BtCursor*)
&pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
sqlite3BtreeCursorZero(pCx->pCursor); sqlite3BtreeCursorZero(pCx->uc.pCursor);
} }
} }
return pCx; return pCx;
@@ -2383,21 +2384,19 @@ case OP_Column: {
assert( pC!=0 ); assert( pC!=0 );
assert( p2<pC->nField ); assert( p2<pC->nField );
aOffset = pC->aOffset; aOffset = pC->aOffset;
#ifndef SQLITE_OMIT_VIRTUALTABLE assert( pC->eCurType!=CURTYPE_VTAB ); /* OP_Column never called on virtual table */
assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */ assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
#endif assert( pC->eCurType!=CURTYPE_SORTER );
pCrsr = pC->pCursor; pCrsr = pC->uc.pCursor;
assert( pCrsr!=0 || pC->pseudoTableReg>0 ); /* pCrsr NULL on PseudoTables */
assert( pCrsr!=0 || pC->nullRow ); /* pC->nullRow on PseudoTables */
/* If the cursor cache is stale, bring it up-to-date */ /* If the cursor cache is stale, bring it up-to-date */
rc = sqlite3VdbeCursorMoveto(pC); rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error; if( rc ) goto abort_due_to_error;
if( pC->cacheStatus!=p->cacheCtr ){ if( pC->cacheStatus!=p->cacheCtr ){
if( pC->nullRow ){ if( pC->nullRow ){
if( pCrsr==0 ){ if( pC->eCurType==CURTYPE_PSEUDO ){
assert( pC->pseudoTableReg>0 ); assert( pC->uc.pseudoTableReg>0 );
pReg = &aMem[pC->pseudoTableReg]; pReg = &aMem[pC->uc.pseudoTableReg];
assert( pReg->flags & MEM_Blob ); assert( pReg->flags & MEM_Blob );
assert( memIsValid(pReg) ); assert( memIsValid(pReg) );
pC->payloadSize = pC->szRow = avail = pReg->n; pC->payloadSize = pC->szRow = avail = pReg->n;
@@ -2407,6 +2406,7 @@ case OP_Column: {
goto op_column_out; goto op_column_out;
} }
}else{ }else{
assert( pC->eCurType==CURTYPE_BTREE );
assert( pCrsr ); assert( pCrsr );
if( pC->isTable==0 ){ if( pC->isTable==0 ){
assert( sqlite3BtreeCursorIsValid(pCrsr) ); assert( sqlite3BtreeCursorIsValid(pCrsr) );
@@ -2795,7 +2795,8 @@ case OP_Count: { /* out2 */
i64 nEntry; i64 nEntry;
BtCursor *pCrsr; 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 ); assert( pCrsr );
nEntry = 0; /* Not needed. Only used to silence a warning. */ nEntry = 0; /* Not needed. Only used to silence a warning. */
rc = sqlite3BtreeCount(pCrsr, &nEntry); rc = sqlite3BtreeCount(pCrsr, &nEntry);
@@ -3380,12 +3381,12 @@ case OP_OpenWrite:
assert( pOp->p1>=0 ); assert( pOp->p1>=0 );
assert( nField>=0 ); assert( nField>=0 );
testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */ 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; if( pCur==0 ) goto no_mem;
pCur->nullRow = 1; pCur->nullRow = 1;
pCur->isOrdered = 1; pCur->isOrdered = 1;
pCur->pgnoRoot = p2; pCur->pgnoRoot = p2;
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor); rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->uc.pCursor);
pCur->pKeyInfo = pKeyInfo; pCur->pKeyInfo = pKeyInfo;
/* Set the VdbeCursor.isTable variable. Previous versions of /* Set the VdbeCursor.isTable variable. Previous versions of
** SQLite used to check if the root-page flags were sane at this point ** 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 #ifdef SQLITE_ENABLE_CURSOR_HINT
testcase( pOp->p2 & OPFLAG_SEEKEQ ); testcase( pOp->p2 & OPFLAG_SEEKEQ );
#endif #endif
sqlite3BtreeCursorHintFlags(pCur->pCursor, sqlite3BtreeCursorHintFlags(pCur->uc.pCursor,
(pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ))); (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
break; break;
} }
@@ -3444,7 +3445,7 @@ case OP_OpenEphemeral: {
SQLITE_OPEN_TRANSIENT_DB; SQLITE_OPEN_TRANSIENT_DB;
assert( pOp->p1>=0 ); assert( pOp->p1>=0 );
assert( pOp->p2>=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; if( pCx==0 ) goto no_mem;
pCx->nullRow = 1; pCx->nullRow = 1;
pCx->isEphemeral = 1; pCx->isEphemeral = 1;
@@ -3468,11 +3469,11 @@ case OP_OpenEphemeral: {
assert( pKeyInfo->db==db ); assert( pKeyInfo->db==db );
assert( pKeyInfo->enc==ENC(db) ); assert( pKeyInfo->enc==ENC(db) );
pCx->pKeyInfo = pKeyInfo; 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; pCx->isTable = 0;
}else{ }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; pCx->isTable = 1;
} }
} }
@@ -3495,7 +3496,7 @@ case OP_SorterOpen: {
assert( pOp->p1>=0 ); assert( pOp->p1>=0 );
assert( pOp->p2>=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; if( pCx==0 ) goto no_mem;
pCx->pKeyInfo = pOp->p4.pKeyInfo; pCx->pKeyInfo = pOp->p4.pKeyInfo;
assert( pCx->pKeyInfo->db==db ); assert( pCx->pKeyInfo->db==db );
@@ -3515,7 +3516,7 @@ case OP_SequenceTest: {
VdbeCursor *pC; VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC->pSorter ); assert( isSorter(pC) );
if( (pC->seqCount++)==0 ){ if( (pC->seqCount++)==0 ){
goto jump_to_p2; goto jump_to_p2;
} }
@@ -3543,10 +3544,10 @@ case OP_OpenPseudo: {
assert( pOp->p1>=0 ); assert( pOp->p1>=0 );
assert( pOp->p3>=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; if( pCx==0 ) goto no_mem;
pCx->nullRow = 1; pCx->nullRow = 1;
pCx->pseudoTableReg = pOp->p2; pCx->uc.pseudoTableReg = pOp->p2;
pCx->isTable = 1; pCx->isTable = 1;
assert( pOp->p5==0 ); assert( pOp->p5==0 );
break; break;
@@ -3578,7 +3579,7 @@ case OP_Close: {
case OP_ColumnsUsed: { case OP_ColumnsUsed: {
VdbeCursor *pC; VdbeCursor *pC;
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC->pCursor ); assert( pC->eCurType==CURTYPE_BTREE );
pC->maskUsed = *(u64*)pOp->p4.pI64; pC->maskUsed = *(u64*)pOp->p4.pI64;
break; break;
} }
@@ -3686,12 +3687,12 @@ case OP_SeekGT: { /* jump, in3 */
assert( pOp->p2!=0 ); assert( pOp->p2!=0 );
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC!=0 ); assert( pC!=0 );
assert( pC->pseudoTableReg==0 ); assert( pC->eCurType==CURTYPE_BTREE );
assert( OP_SeekLE == OP_SeekLT+1 ); assert( OP_SeekLE == OP_SeekLT+1 );
assert( OP_SeekGE == OP_SeekLT+2 ); assert( OP_SeekGE == OP_SeekLT+2 );
assert( OP_SeekGT == OP_SeekLT+3 ); assert( OP_SeekGT == OP_SeekLT+3 );
assert( pC->isOrdered ); assert( pC->isOrdered );
assert( pC->pCursor!=0 ); assert( pC->uc.pCursor!=0 );
oc = pOp->opcode; oc = pOp->opcode;
eqOnly = 0; eqOnly = 0;
pC->nullRow = 0; pC->nullRow = 0;
@@ -3701,7 +3702,7 @@ case OP_SeekGT: { /* jump, in3 */
if( pC->isTable ){ if( pC->isTable ){
/* The BTREE_SEEK_EQ flag is only set on index cursors */ /* 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, /* 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 ** 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++; 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 */ pC->movetoTarget = iKey; /* Used by OP_Delete */
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto abort_due_to_error; 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 ** OP_SeekLE opcodes are allowed, and these must be immediately followed
** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key. ** 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; eqOnly = 1;
assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE ); assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT ); assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
@@ -3790,7 +3791,7 @@ case OP_SeekGT: { /* jump, in3 */
#endif #endif
ExpandBlob(r.aMem); ExpandBlob(r.aMem);
r.eqSeen = 0; r.eqSeen = 0;
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res); rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, &r, 0, 0, &res);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto abort_due_to_error; 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( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT );
if( res<0 || (res==0 && oc==OP_SeekGT) ){ if( res<0 || (res==0 && oc==OP_SeekGT) ){
res = 0; res = 0;
rc = sqlite3BtreeNext(pC->pCursor, &res); rc = sqlite3BtreeNext(pC->uc.pCursor, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error; if( rc!=SQLITE_OK ) goto abort_due_to_error;
}else{ }else{
res = 0; res = 0;
@@ -3816,13 +3817,13 @@ case OP_SeekGT: { /* jump, in3 */
assert( oc==OP_SeekLT || oc==OP_SeekLE ); assert( oc==OP_SeekLT || oc==OP_SeekLE );
if( res>0 || (res==0 && oc==OP_SeekLT) ){ if( res>0 || (res==0 && oc==OP_SeekLT) ){
res = 0; res = 0;
rc = sqlite3BtreePrevious(pC->pCursor, &res); rc = sqlite3BtreePrevious(pC->uc.pCursor, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error; if( rc!=SQLITE_OK ) goto abort_due_to_error;
}else{ }else{
/* res might be negative because the table is empty. Check to /* res might be negative because the table is empty. Check to
** see if this is the case. ** see if this is the case.
*/ */
res = sqlite3BtreeEof(pC->pCursor); res = sqlite3BtreeEof(pC->uc.pCursor);
} }
} }
seek_not_found: seek_not_found:
@@ -3853,7 +3854,8 @@ case OP_Seek: { /* in2 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC!=0 ); assert( pC!=0 );
assert( pC->pCursor!=0 ); assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0 );
assert( pC->isTable ); assert( pC->isTable );
pC->nullRow = 0; pC->nullRow = 0;
pIn2 = &aMem[pOp->p2]; pIn2 = &aMem[pOp->p2];
@@ -3947,7 +3949,8 @@ case OP_Found: { /* jump, in3 */
pC->seekOp = pOp->opcode; pC->seekOp = pOp->opcode;
#endif #endif
pIn3 = &aMem[pOp->p3]; pIn3 = &aMem[pOp->p3];
assert( pC->pCursor!=0 ); assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0 );
assert( pC->isTable==0 ); assert( pC->isTable==0 );
pFree = 0; pFree = 0;
if( pOp->p4.i>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); sqlite3DbFree(db, pFree);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
break; break;
@@ -4038,8 +4041,8 @@ case OP_NotExists: { /* jump, in3 */
pC->seekOp = 0; pC->seekOp = 0;
#endif #endif
assert( pC->isTable ); assert( pC->isTable );
assert( pC->pseudoTableReg==0 ); assert( pC->eCurType==CURTYPE_BTREE );
pCrsr = pC->pCursor; pCrsr = pC->uc.pCursor;
assert( pCrsr!=0 ); assert( pCrsr!=0 );
res = 0; res = 0;
iKey = pIn3->u.i; iKey = pIn3->u.i;
@@ -4073,6 +4076,7 @@ case OP_NotExists: { /* jump, in3 */
case OP_Sequence: { /* out2 */ case OP_Sequence: { /* out2 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( p->apCsr[pOp->p1]!=0 ); assert( p->apCsr[pOp->p1]!=0 );
assert( p->apCsr[pOp->p1]->eCurType!=CURTYPE_VTAB );
pOut = out2Prerelease(p, pOp); pOut = out2Prerelease(p, pOp);
pOut->u.i = p->apCsr[pOp->p1]->seqCount++; pOut->u.i = p->apCsr[pOp->p1]->seqCount++;
break; break;
@@ -4108,7 +4112,8 @@ case OP_NewRowid: { /* out2 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC!=0 ); 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 /* The next rowid or record number (different terms for the same
** thing) is obtained in a two-step algorithm. ** thing) is obtained in a two-step algorithm.
@@ -4136,15 +4141,15 @@ case OP_NewRowid: { /* out2 */
#endif #endif
if( !pC->useRandomRowid ){ if( !pC->useRandomRowid ){
rc = sqlite3BtreeLast(pC->pCursor, &res); rc = sqlite3BtreeLast(pC->uc.pCursor, &res);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto abort_due_to_error; goto abort_due_to_error;
} }
if( res ){ if( res ){
v = 1; /* IMP: R-61914-48074 */ v = 1; /* IMP: R-61914-48074 */
}else{ }else{
assert( sqlite3BtreeCursorIsValid(pC->pCursor) ); assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) );
rc = sqlite3BtreeKeySize(pC->pCursor, &v); rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v);
assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */ assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */
if( v>=MAX_ROWID ){ if( v>=MAX_ROWID ){
pC->useRandomRowid = 1; pC->useRandomRowid = 1;
@@ -4195,7 +4200,7 @@ case OP_NewRowid: { /* out2 */
do{ do{
sqlite3_randomness(sizeof(v), &v); sqlite3_randomness(sizeof(v), &v);
v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */ 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) 0, &res))==SQLITE_OK)
&& (res==0) && (res==0)
&& (++cnt<100)); && (++cnt<100));
@@ -4275,8 +4280,8 @@ case OP_InsertInt: {
assert( memIsValid(pData) ); assert( memIsValid(pData) );
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC!=0 ); assert( pC!=0 );
assert( pC->pCursor!=0 ); assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->pseudoTableReg==0 ); assert( pC->uc.pCursor!=0 );
assert( pC->isTable ); assert( pC->isTable );
REGISTER_TRACE(pOp->p2, pData); REGISTER_TRACE(pOp->p2, pData);
@@ -4305,7 +4310,7 @@ case OP_InsertInt: {
}else{ }else{
nZero = 0; nZero = 0;
} }
rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, rc = sqlite3BtreeInsert(pC->uc.pCursor, 0, iKey,
pData->z, pData->n, nZero, pData->z, pData->n, nZero,
(pOp->p5 & OPFLAG_APPEND)!=0, seekResult (pOp->p5 & OPFLAG_APPEND)!=0, seekResult
); );
@@ -4352,12 +4357,13 @@ case OP_Delete: {
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC!=0 ); 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 ); assert( pC->deferredMoveto==0 );
hasUpdateCallback = db->xUpdateCallback && pOp->p4.z && pC->isTable; hasUpdateCallback = db->xUpdateCallback && pOp->p4.z && pC->isTable;
if( pOp->p5 && hasUpdateCallback ){ if( pOp->p5 && hasUpdateCallback ){
sqlite3BtreeKeySize(pC->pCursor, &pC->movetoTarget); sqlite3BtreeKeySize(pC->uc.pCursor, &pC->movetoTarget);
} }
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
@@ -4366,12 +4372,12 @@ case OP_Delete: {
** is being deleted */ ** is being deleted */
if( pOp->p4.z && pC->isTable && pOp->p5==0 ){ if( pOp->p4.z && pC->isTable && pOp->p5==0 ){
i64 iKey = 0; i64 iKey = 0;
sqlite3BtreeKeySize(pC->pCursor, &iKey); sqlite3BtreeKeySize(pC->uc.pCursor, &iKey);
assert( pC->movetoTarget==iKey ); assert( pC->movetoTarget==iKey );
} }
#endif #endif
rc = sqlite3BtreeDelete(pC->pCursor, pOp->p5); rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
pC->cacheStatus = CACHE_STALE; pC->cacheStatus = CACHE_STALE;
/* Invoke the update-hook if required. */ /* Invoke the update-hook if required. */
@@ -4488,14 +4494,14 @@ case OP_RowData: {
/* Note that RowKey and RowData are really exactly the same instruction */ /* Note that RowKey and RowData are really exactly the same instruction */
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->eCurType==CURTYPE_BTREE );
assert( isSorter(pC)==0 ); assert( isSorter(pC)==0 );
assert( pC->isTable || pOp->opcode!=OP_RowData ); assert( pC->isTable || pOp->opcode!=OP_RowData );
assert( pC->isTable==0 || pOp->opcode==OP_RowData ); assert( pC->isTable==0 || pOp->opcode==OP_RowData );
assert( pC!=0 );
assert( pC->nullRow==0 ); assert( pC->nullRow==0 );
assert( pC->pseudoTableReg==0 ); assert( pC->uc.pCursor!=0 );
assert( pC->pCursor!=0 ); pCrsr = pC->uc.pCursor;
pCrsr = pC->pCursor;
/* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or
** OP_Rewind/Op_Next with no intervening instructions that might invalidate ** 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 ); assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC!=0 ); assert( pC!=0 );
assert( pC->pseudoTableReg==0 || pC->nullRow ); assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
if( pC->nullRow ){ if( pC->nullRow ){
pOut->flags = MEM_Null; pOut->flags = MEM_Null;
break; break;
}else if( pC->deferredMoveto ){ }else if( pC->deferredMoveto ){
v = pC->movetoTarget; v = pC->movetoTarget;
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
}else if( pC->pVtabCursor ){ }else if( pC->eCurType==CURTYPE_VTAB ){
pVtab = pC->pVtabCursor->pVtab; assert( pC->uc.pVCur!=0 );
pVtab = pC->uc.pVCur->pVtab;
pModule = pVtab->pModule; pModule = pVtab->pModule;
assert( pModule->xRowid ); assert( pModule->xRowid );
rc = pModule->xRowid(pC->pVtabCursor, &v); rc = pModule->xRowid(pC->uc.pVCur, &v);
sqlite3VtabImportErrmsg(p, pVtab); sqlite3VtabImportErrmsg(p, pVtab);
#endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* SQLITE_OMIT_VIRTUALTABLE */
}else{ }else{
assert( pC->pCursor!=0 ); assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0 );
rc = sqlite3VdbeCursorRestore(pC); rc = sqlite3VdbeCursorRestore(pC);
if( rc ) goto abort_due_to_error; if( rc ) goto abort_due_to_error;
if( pC->nullRow ){ if( pC->nullRow ){
pOut->flags = MEM_Null; pOut->flags = MEM_Null;
break; break;
} }
rc = sqlite3BtreeKeySize(pC->pCursor, &v); rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v);
assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */ assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */
} }
pOut->u.i = v; pOut->u.i = v;
@@ -4606,8 +4614,9 @@ case OP_NullRow: {
assert( pC!=0 ); assert( pC!=0 );
pC->nullRow = 1; pC->nullRow = 1;
pC->cacheStatus = CACHE_STALE; pC->cacheStatus = CACHE_STALE;
if( pC->pCursor ){ if( pC->eCurType==CURTYPE_BTREE ){
sqlite3BtreeClearCursor(pC->pCursor); assert( pC->uc.pCursor!=0 );
sqlite3BtreeClearCursor(pC->uc.pCursor);
} }
break; break;
} }
@@ -4632,7 +4641,8 @@ case OP_Last: { /* jump */
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC!=0 ); assert( pC!=0 );
pCrsr = pC->pCursor; assert( pC->eCurType==CURTYPE_BTREE );
pCrsr = pC->uc.pCursor;
res = 0; res = 0;
assert( pCrsr!=0 ); assert( pCrsr!=0 );
rc = sqlite3BtreeLast(pCrsr, &res); rc = sqlite3BtreeLast(pCrsr, &res);
@@ -4700,7 +4710,8 @@ case OP_Rewind: { /* jump */
if( isSorter(pC) ){ if( isSorter(pC) ){
rc = sqlite3VdbeSorterRewind(pC, &res); rc = sqlite3VdbeSorterRewind(pC, &res);
}else{ }else{
pCrsr = pC->pCursor; assert( pC->eCurType==CURTYPE_BTREE );
pCrsr = pC->uc.pCursor;
assert( pCrsr ); assert( pCrsr );
rc = sqlite3BtreeFirst(pCrsr, &res); rc = sqlite3BtreeFirst(pCrsr, &res);
pC->deferredMoveto = 0; pC->deferredMoveto = 0;
@@ -4797,7 +4808,7 @@ case OP_Next: /* jump */
res = pOp->p3; res = pOp->p3;
assert( pC!=0 ); assert( pC!=0 );
assert( pC->deferredMoveto==0 ); assert( pC->deferredMoveto==0 );
assert( pC->pCursor ); assert( pC->eCurType==CURTYPE_BTREE );
assert( res==0 || (res==1 && pC->isTable==0) ); assert( res==0 || (res==1 && pC->isTable==0) );
testcase( res==1 ); testcase( res==1 );
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext ); 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_SeekLT || pC->seekOp==OP_SeekLE
|| pC->seekOp==OP_Last ); || pC->seekOp==OP_Last );
rc = pOp->p4.xAdvance(pC->pCursor, &res); rc = pOp->p4.xAdvance(pC->uc.pCursor, &res);
next_tail: next_tail:
pC->cacheStatus = CACHE_STALE; pC->cacheStatus = CACHE_STALE;
VdbeBranchTaken(res==0,2); VdbeBranchTaken(res==0,2);
@@ -4865,7 +4876,7 @@ case OP_IdxInsert: { /* in2 */
pIn2 = &aMem[pOp->p2]; pIn2 = &aMem[pOp->p2];
assert( pIn2->flags & MEM_Blob ); assert( pIn2->flags & MEM_Blob );
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
assert( pC->pCursor!=0 ); assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert );
assert( pC->isTable==0 ); assert( pC->isTable==0 );
rc = ExpandBlob(pIn2); rc = ExpandBlob(pIn2);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
@@ -4874,7 +4885,7 @@ case OP_IdxInsert: { /* in2 */
}else{ }else{
nKey = pIn2->n; nKey = pIn2->n;
zKey = pIn2->z; 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) ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
); );
assert( pC->deferredMoveto==0 ); assert( pC->deferredMoveto==0 );
@@ -4902,7 +4913,8 @@ case OP_IdxDelete: {
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC!=0 ); assert( pC!=0 );
pCrsr = pC->pCursor; assert( pC->eCurType==CURTYPE_BTREE );
pCrsr = pC->uc.pCursor;
assert( pCrsr!=0 ); assert( pCrsr!=0 );
assert( pOp->p5==0 ); assert( pOp->p5==0 );
r.pKeyInfo = pC->pKeyInfo; r.pKeyInfo = pC->pKeyInfo;
@@ -4939,7 +4951,8 @@ case OP_IdxRowid: { /* out2 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC!=0 ); assert( pC!=0 );
pCrsr = pC->pCursor; assert( pC->eCurType==CURTYPE_BTREE );
pCrsr = pC->uc.pCursor;
assert( pCrsr!=0 ); assert( pCrsr!=0 );
pOut->flags = MEM_Null; pOut->flags = MEM_Null;
assert( pC->isTable==0 ); assert( pC->isTable==0 );
@@ -5020,7 +5033,8 @@ case OP_IdxGE: { /* jump */
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC!=0 ); assert( pC!=0 );
assert( pC->isOrdered ); assert( pC->isOrdered );
assert( pC->pCursor!=0); assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0);
assert( pC->deferredMoveto==0 ); assert( pC->deferredMoveto==0 );
assert( pOp->p5==0 || pOp->p5==1 ); assert( pOp->p5==0 || pOp->p5==1 );
assert( pOp->p4type==P4_INT32 ); assert( pOp->p4type==P4_INT32 );
@@ -5153,11 +5167,12 @@ case OP_ResetSorter: {
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC!=0 ); assert( pC!=0 );
if( pC->pSorter ){ if( isSorter(pC) ){
sqlite3VdbeSorterReset(db, pC->pSorter); sqlite3VdbeSorterReset(db, pC->uc.pSorter);
}else{ }else{
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->isEphemeral ); assert( pC->isEphemeral );
rc = sqlite3BtreeClearTableOfCursor(pC->pCursor); rc = sqlite3BtreeClearTableOfCursor(pC->uc.pCursor);
} }
break; break;
} }
@@ -6231,33 +6246,33 @@ case OP_VDestroy: {
*/ */
case OP_VOpen: { case OP_VOpen: {
VdbeCursor *pCur; VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor; sqlite3_vtab_cursor *pVCur;
sqlite3_vtab *pVtab; sqlite3_vtab *pVtab;
const sqlite3_module *pModule; const sqlite3_module *pModule;
assert( p->bIsReader ); assert( p->bIsReader );
pCur = 0; pCur = 0;
pVtabCursor = 0; pVCur = 0;
pVtab = pOp->p4.pVtab->pVtab; pVtab = pOp->p4.pVtab->pVtab;
if( pVtab==0 || NEVER(pVtab->pModule==0) ){ if( pVtab==0 || NEVER(pVtab->pModule==0) ){
rc = SQLITE_LOCKED; rc = SQLITE_LOCKED;
break; break;
} }
pModule = pVtab->pModule; pModule = pVtab->pModule;
rc = pModule->xOpen(pVtab, &pVtabCursor); rc = pModule->xOpen(pVtab, &pVCur);
sqlite3VtabImportErrmsg(p, pVtab); sqlite3VtabImportErrmsg(p, pVtab);
if( SQLITE_OK==rc ){ if( SQLITE_OK==rc ){
/* Initialize sqlite3_vtab_cursor base class */ /* Initialize sqlite3_vtab_cursor base class */
pVtabCursor->pVtab = pVtab; pVCur->pVtab = pVtab;
/* Initialize vdbe cursor object */ /* Initialize vdbe cursor object */
pCur = allocateCursor(p, pOp->p1, 0, -1, 0); pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB);
if( pCur ){ if( pCur ){
pCur->pVtabCursor = pVtabCursor; pCur->uc.pVCur = pVCur;
pVtab->nRef++; pVtab->nRef++;
}else{ }else{
assert( db->mallocFailed ); assert( db->mallocFailed );
pModule->xClose(pVtabCursor); pModule->xClose(pVCur);
goto no_mem; goto no_mem;
} }
} }
@@ -6291,7 +6306,7 @@ case OP_VFilter: { /* jump */
const sqlite3_module *pModule; const sqlite3_module *pModule;
Mem *pQuery; Mem *pQuery;
Mem *pArgc; Mem *pArgc;
sqlite3_vtab_cursor *pVtabCursor; sqlite3_vtab_cursor *pVCur;
sqlite3_vtab *pVtab; sqlite3_vtab *pVtab;
VdbeCursor *pCur; VdbeCursor *pCur;
int res; int res;
@@ -6303,9 +6318,9 @@ case OP_VFilter: { /* jump */
pCur = p->apCsr[pOp->p1]; pCur = p->apCsr[pOp->p1];
assert( memIsValid(pQuery) ); assert( memIsValid(pQuery) );
REGISTER_TRACE(pOp->p3, pQuery); REGISTER_TRACE(pOp->p3, pQuery);
assert( pCur->pVtabCursor ); assert( pCur->eCurType==CURTYPE_VTAB );
pVtabCursor = pCur->pVtabCursor; pVCur = pCur->uc.pVCur;
pVtab = pVtabCursor->pVtab; pVtab = pVCur->pVtab;
pModule = pVtab->pModule; pModule = pVtab->pModule;
/* Grab the index number and argc parameters */ /* Grab the index number and argc parameters */
@@ -6319,10 +6334,10 @@ case OP_VFilter: { /* jump */
for(i = 0; i<nArg; i++){ for(i = 0; i<nArg; i++){
apArg[i] = &pArgc[i+1]; 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); sqlite3VtabImportErrmsg(p, pVtab);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
res = pModule->xEof(pVtabCursor); res = pModule->xEof(pVCur);
} }
pCur->nullRow = 0; pCur->nullRow = 0;
VdbeBranchTaken(res!=0,2); VdbeBranchTaken(res!=0,2);
@@ -6346,7 +6361,7 @@ case OP_VColumn: {
sqlite3_context sContext; sqlite3_context sContext;
VdbeCursor *pCur = p->apCsr[pOp->p1]; VdbeCursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor ); assert( pCur->eCurType==CURTYPE_VTAB );
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pDest = &aMem[pOp->p3]; pDest = &aMem[pOp->p3];
memAboutToChange(p, pDest); memAboutToChange(p, pDest);
@@ -6354,13 +6369,13 @@ case OP_VColumn: {
sqlite3VdbeMemSetNull(pDest); sqlite3VdbeMemSetNull(pDest);
break; break;
} }
pVtab = pCur->pVtabCursor->pVtab; pVtab = pCur->uc.pVCur->pVtab;
pModule = pVtab->pModule; pModule = pVtab->pModule;
assert( pModule->xColumn ); assert( pModule->xColumn );
memset(&sContext, 0, sizeof(sContext)); memset(&sContext, 0, sizeof(sContext));
sContext.pOut = pDest; sContext.pOut = pDest;
MemSetTypeFlag(pDest, MEM_Null); MemSetTypeFlag(pDest, MEM_Null);
rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2); rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2);
sqlite3VtabImportErrmsg(p, pVtab); sqlite3VtabImportErrmsg(p, pVtab);
if( sContext.isError ){ if( sContext.isError ){
rc = sContext.isError; rc = sContext.isError;
@@ -6391,11 +6406,11 @@ case OP_VNext: { /* jump */
res = 0; res = 0;
pCur = p->apCsr[pOp->p1]; pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor ); assert( pCur->eCurType==CURTYPE_VTAB );
if( pCur->nullRow ){ if( pCur->nullRow ){
break; break;
} }
pVtab = pCur->pVtabCursor->pVtab; pVtab = pCur->uc.pVCur->pVtab;
pModule = pVtab->pModule; pModule = pVtab->pModule;
assert( pModule->xNext ); assert( pModule->xNext );
@@ -6405,10 +6420,10 @@ case OP_VNext: { /* jump */
** data is available) and the error code returned when xColumn or ** data is available) and the error code returned when xColumn or
** some other method is next invoked on the save virtual table cursor. ** 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); sqlite3VtabImportErrmsg(p, pVtab);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
res = pModule->xEof(pCur->pVtabCursor); res = pModule->xEof(pCur->uc.pVCur);
} }
VdbeBranchTaken(!res,2); VdbeBranchTaken(!res,2);
if( !res ){ if( !res ){
@@ -6632,7 +6647,8 @@ case OP_CursorHint: {
assert( pOp->p4type==P4_EXPR ); assert( pOp->p4type==P4_EXPR );
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
if( pC ){ 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; break;
} }

View File

@@ -58,42 +58,48 @@ typedef struct Explain Explain;
/* Elements of the linked list at Vdbe.pAuxData */ /* Elements of the linked list at Vdbe.pAuxData */
typedef struct AuxData AuxData; 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. ** A VdbeCursor is an superclass (a wrapper) for various cursor objects:
** 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.
** **
** Cursors can also point to virtual tables, sorters, or "pseudo-tables". ** * A b-tree cursor
** A pseudo-table is a single-row table implemented by registers. ** - In the main database or in an ephemeral database
** ** - On either an index or a table
** Every cursor that the virtual machine has open is represented by an ** * A sorter
** instance of the following structure. ** * A virtual table
** * A one-row "pseudotable" stored in a single register
*/ */
struct VdbeCursor { struct VdbeCursor {
BtCursor *pCursor; /* The cursor structure of the backend */ u8 eCurType; /* One of the CURTYPE_* values above */
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
i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
u8 nullRow; /* True if pointing to a row with no data */ u8 nullRow; /* True if pointing to a row with no data */
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ 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 isEphemeral:1; /* True for an ephemeral table */
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */ 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 */ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
Pgno pgnoRoot; /* Root page of the open btree cursor */ 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 seqCount; /* Sequence counter */
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK #ifdef SQLITE_ENABLE_COLUMN_USED_MASK
u64 maskUsed; /* Mask of columns used by this cursor */ u64 maskUsed; /* Mask of columns used by this cursor */
#endif #endif

View File

@@ -1930,23 +1930,34 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
if( pCx==0 ){ if( pCx==0 ){
return; return;
} }
sqlite3VdbeSorterClose(p->db, pCx); assert( pCx->pBt==0 || pCx->eCurType==CURTYPE_BTREE );
if( pCx->pBt ){ switch( pCx->eCurType ){
sqlite3BtreeClose(pCx->pBt); case CURTYPE_SORTER: {
/* The pCx->pCursor will be close automatically, if it exists, by sqlite3VdbeSorterClose(p->db, pCx);
** the call above. */ break;
}else if( pCx->pCursor ){ }
sqlite3BtreeCloseCursor(pCx->pCursor); case CURTYPE_BTREE: {
} if( pCx->pBt ){
sqlite3BtreeClose(pCx->pBt);
/* The pCx->pCursor will be close automatically, if it exists, by
** the call above. */
}else{
assert( pCx->uc.pCursor!=0 );
sqlite3BtreeCloseCursor(pCx->uc.pCursor);
}
break;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
else if( pCx->pVtabCursor ){ case CURTYPE_VTAB: {
sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor; sqlite3_vtab_cursor *pVCur = pCx->uc.pVCur;
const sqlite3_module *pModule = pVtabCursor->pVtab->pModule; const sqlite3_module *pModule = pVCur->pVtab->pModule;
assert( pVtabCursor->pVtab->nRef>0 ); assert( pVCur->pVtab->nRef>0 );
pVtabCursor->pVtab->nRef--; pVCur->pVtab->nRef--;
pModule->xClose(pVtabCursor); pModule->xClose(pVCur);
} break;
}
#endif #endif
}
} }
/* /*
@@ -2933,7 +2944,8 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
#endif #endif
assert( p->deferredMoveto ); assert( p->deferredMoveto );
assert( p->isTable ); 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( rc ) return rc;
if( res!=0 ) return SQLITE_CORRUPT_BKPT; if( res!=0 ) return SQLITE_CORRUPT_BKPT;
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
@@ -2953,9 +2965,10 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
*/ */
static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){ static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
int isDifferentRow, rc; int isDifferentRow, rc;
assert( p->pCursor!=0 ); assert( p->eCurType==CURTYPE_BTREE );
assert( sqlite3BtreeCursorHasMoved(p->pCursor) ); assert( p->uc.pCursor!=0 );
rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow); assert( sqlite3BtreeCursorHasMoved(p->uc.pCursor) );
rc = sqlite3BtreeCursorRestore(p->uc.pCursor, &isDifferentRow);
p->cacheStatus = CACHE_STALE; p->cacheStatus = CACHE_STALE;
if( isDifferentRow ) p->nullRow = 1; if( isDifferentRow ) p->nullRow = 1;
return rc; 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. ** if need be. Return any I/O error from the restore operation.
*/ */
int sqlite3VdbeCursorRestore(VdbeCursor *p){ int sqlite3VdbeCursorRestore(VdbeCursor *p){
if( sqlite3BtreeCursorHasMoved(p->pCursor) ){ assert( p->eCurType==CURTYPE_BTREE );
if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
return handleMovedCursor(p); return handleMovedCursor(p);
} }
return SQLITE_OK; return SQLITE_OK;
@@ -2986,11 +3000,13 @@ int sqlite3VdbeCursorRestore(VdbeCursor *p){
** not been deleted out from under the cursor, then this routine is a no-op. ** not been deleted out from under the cursor, then this routine is a no-op.
*/ */
int sqlite3VdbeCursorMoveto(VdbeCursor *p){ int sqlite3VdbeCursorMoveto(VdbeCursor *p){
if( p->deferredMoveto ){ if( p->eCurType==CURTYPE_BTREE ){
return handleDeferredMoveto(p); if( p->deferredMoveto ){
} return handleDeferredMoveto(p);
if( p->pCursor && sqlite3BtreeCursorHasMoved(p->pCursor) ){ }
return handleMovedCursor(p); if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
return handleMovedCursor(p);
}
} }
return SQLITE_OK; return SQLITE_OK;
} }
@@ -4303,9 +4319,11 @@ int sqlite3VdbeIdxKeyCompare(
){ ){
i64 nCellKey = 0; i64 nCellKey = 0;
int rc; int rc;
BtCursor *pCur = pC->pCursor; BtCursor *pCur;
Mem m; Mem m;
assert( pC->eCurType==CURTYPE_BTREE );
pCur = pC->uc.pCursor;
assert( sqlite3BtreeCursorIsValid(pCur) ); assert( sqlite3BtreeCursorIsValid(pCur) );
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey); VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */
@@ -4316,7 +4334,7 @@ int sqlite3VdbeIdxKeyCompare(
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
} }
sqlite3VdbeMemInit(&m, db, 0); sqlite3VdbeMemInit(&m, db, 0);
rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (u32)nCellKey, 1, &m); rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
if( rc ){ if( rc ){
return rc; return rc;
} }

View File

@@ -76,7 +76,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
}else{ }else{
p->iOffset = pC->aType[p->iCol + pC->nField]; p->iOffset = pC->aType[p->iCol + pC->nField];
p->nByte = sqlite3VdbeSerialTypeLen(type); p->nByte = sqlite3VdbeSerialTypeLen(type);
p->pCsr = pC->pCursor; p->pCsr = pC->uc.pCursor;
sqlite3BtreeIncrblobCursor(p->pCsr); sqlite3BtreeIncrblobCursor(p->pCsr);
} }
} }

View File

@@ -961,11 +961,12 @@ int sqlite3VdbeSorterInit(
#endif #endif
assert( pCsr->pKeyInfo && pCsr->pBt==0 ); assert( pCsr->pKeyInfo && pCsr->pBt==0 );
assert( pCsr->eCurType==CURTYPE_SORTER );
szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*); szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*);
sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
pCsr->pSorter = pSorter; pCsr->uc.pSorter = pSorter;
if( pSorter==0 ){ if( pSorter==0 ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
}else{ }else{
@@ -1249,12 +1250,14 @@ void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
** Free any cursor components allocated by sqlite3VdbeSorterXXX routines. ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
*/ */
void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
VdbeSorter *pSorter = pCsr->pSorter; VdbeSorter *pSorter;
assert( pCsr->eCurType==CURTYPE_SORTER );
pSorter = pCsr->uc.pSorter;
if( pSorter ){ if( pSorter ){
sqlite3VdbeSorterReset(db, pSorter); sqlite3VdbeSorterReset(db, pSorter);
sqlite3_free(pSorter->list.aMemory); sqlite3_free(pSorter->list.aMemory);
sqlite3DbFree(db, pSorter); sqlite3DbFree(db, pSorter);
pCsr->pSorter = 0; pCsr->uc.pSorter = 0;
} }
} }
@@ -1752,15 +1755,16 @@ int sqlite3VdbeSorterWrite(
const VdbeCursor *pCsr, /* Sorter cursor */ const VdbeCursor *pCsr, /* Sorter cursor */
Mem *pVal /* Memory cell containing record */ Mem *pVal /* Memory cell containing record */
){ ){
VdbeSorter *pSorter = pCsr->pSorter; VdbeSorter *pSorter;
int rc = SQLITE_OK; /* Return Code */ int rc = SQLITE_OK; /* Return Code */
SorterRecord *pNew; /* New list element */ SorterRecord *pNew; /* New list element */
int bFlush; /* True to flush contents of memory to PMA */ int bFlush; /* True to flush contents of memory to PMA */
int nReq; /* Bytes of memory required */ int nReq; /* Bytes of memory required */
int nPMA; /* Bytes of PMA space required */ int nPMA; /* Bytes of PMA space required */
int t; /* serial type of first record field */ int t; /* serial type of first record field */
assert( pCsr->eCurType==CURTYPE_SORTER );
pSorter = pCsr->uc.pSorter;
getVarint32((const u8*)&pVal->z[1], t); getVarint32((const u8*)&pVal->z[1], t);
if( t>0 && t<10 && t!=7 ){ if( t>0 && t<10 && t!=7 ){
pSorter->typeMask &= SORTER_TYPE_INTEGER; pSorter->typeMask &= SORTER_TYPE_INTEGER;
@@ -2552,9 +2556,11 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
** in sorted order. ** in sorted order.
*/ */
int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){ int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
VdbeSorter *pSorter = pCsr->pSorter; VdbeSorter *pSorter;
int rc = SQLITE_OK; /* Return code */ int rc = SQLITE_OK; /* Return code */
assert( pCsr->eCurType==CURTYPE_SORTER );
pSorter = pCsr->uc.pSorter;
assert( pSorter ); assert( pSorter );
/* If no data has been written to disk, then do not do so now. Instead, /* 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. ** Advance to the next element in the sorter.
*/ */
int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){ int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
VdbeSorter *pSorter = pCsr->pSorter; VdbeSorter *pSorter;
int rc; /* Return code */ int rc; /* Return code */
assert( pCsr->eCurType==CURTYPE_SORTER );
pSorter = pCsr->uc.pSorter;
assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) ); assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) );
if( pSorter->bUsePMA ){ if( pSorter->bUsePMA ){
assert( pSorter->pReader==0 || pSorter->pMerger==0 ); assert( pSorter->pReader==0 || pSorter->pMerger==0 );
@@ -2660,9 +2668,11 @@ static void *vdbeSorterRowkey(
** Copy the current sorter key into the memory cell pOut. ** Copy the current sorter key into the memory cell pOut.
*/ */
int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){
VdbeSorter *pSorter = pCsr->pSorter; VdbeSorter *pSorter;
void *pKey; int nKey; /* Sorter key to copy into pOut */ void *pKey; int nKey; /* Sorter key to copy into pOut */
assert( pCsr->eCurType==CURTYPE_SORTER );
pSorter = pCsr->uc.pSorter;
pKey = vdbeSorterRowkey(pSorter, &nKey); pKey = vdbeSorterRowkey(pSorter, &nKey);
if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){ if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
@@ -2696,12 +2706,16 @@ int sqlite3VdbeSorterCompare(
int nKeyCol, /* Compare this many columns */ int nKeyCol, /* Compare this many columns */
int *pRes /* OUT: Result of comparison */ int *pRes /* OUT: Result of comparison */
){ ){
VdbeSorter *pSorter = pCsr->pSorter; VdbeSorter *pSorter;
UnpackedRecord *r2 = pSorter->pUnpacked; UnpackedRecord *r2;
KeyInfo *pKeyInfo = pCsr->pKeyInfo; KeyInfo *pKeyInfo;
int i; int i;
void *pKey; int nKey; /* Sorter key to compare pVal with */ 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 ){ if( r2==0 ){
char *p; char *p;
r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p); r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p);