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.
|
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
|
||||||
|
@@ -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;}
|
&& 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;
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
Reference in New Issue
Block a user