mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Refactoring the OP_Column opcode for improved performance and
maintainability. FossilOrigin-Name: 7c914e3997d2b28164a2fa7eb4398262b6ddb4b2
This commit is contained in:
19
manifest
19
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Simplifications\sto\sthe\sVdbeCursor\sobject.
|
C Refactoring\sthe\sOP_Column\sopcode\sfor\simproved\sperformance\sand\nmaintainability.
|
||||||
D 2013-11-20T02:53:58.741
|
D 2013-11-20T17:25:55.912
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in 8a07bebafbfda0eb67728f4bd15a36201662d1a1
|
F Makefile.in 8a07bebafbfda0eb67728f4bd15a36201662d1a1
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@@ -280,11 +280,11 @@ F src/update.c c05a0ee658f1a149e0960dfd110f3b8bd846bcb0
|
|||||||
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
||||||
F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
|
F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
|
||||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||||
F src/vdbe.c da810a2b71f26e23d597e3b966166db8f1117fad
|
F src/vdbe.c d4b8a9067a163f18535324c76bafdddff6b93491
|
||||||
F src/vdbe.h c06f0813f853566457ce9cfb1a4a4bc39a5da644
|
F src/vdbe.h c06f0813f853566457ce9cfb1a4a4bc39a5da644
|
||||||
F src/vdbeInt.h 4044cd2e9dc1aef3e15fc68f80cbdf2446eff369
|
F src/vdbeInt.h fbae1c449049a1a26ebbdf44e1beb08344072b72
|
||||||
F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed
|
F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed
|
||||||
F src/vdbeaux.c 91f9e1fb59561fa7ba312b518b6123982c912d6c
|
F src/vdbeaux.c c592609996435944837b8906fbbcfcfac0714c90
|
||||||
F src/vdbeblob.c d883398f7260725147dbf5b40c2b61332aee47f9
|
F src/vdbeblob.c d883398f7260725147dbf5b40c2b61332aee47f9
|
||||||
F src/vdbemem.c cc529bbf4f13e4e181bdb446bf6e6962ab030b4b
|
F src/vdbemem.c cc529bbf4f13e4e181bdb446bf6e6962ab030b4b
|
||||||
F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147
|
F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147
|
||||||
@@ -1140,7 +1140,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
|||||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||||
P 96a65388e75fed96e2e73ef65726f6db88cc5ccd
|
P 5562cd343d8f69242e06a51a7f1aef7ee7d78eec
|
||||||
R ca796b6fcdb020d784b4cd61fedf5893
|
R 71521f10a62f5e2d15e34378a9a872cf
|
||||||
|
T *branch * OP_Column-refactor
|
||||||
|
T *sym-OP_Column-refactor *
|
||||||
|
T -sym-trunk *
|
||||||
U drh
|
U drh
|
||||||
Z 97e722e14aa88f975fca1769e7e16ee6
|
Z 41c0df82986aff89d8eb065b326b79ba
|
||||||
|
@@ -1 +1 @@
|
|||||||
5562cd343d8f69242e06a51a7f1aef7ee7d78eec
|
7c914e3997d2b28164a2fa7eb4398262b6ddb4b2
|
294
src/vdbe.c
294
src/vdbe.c
@@ -214,7 +214,7 @@ static VdbeCursor *allocateCursor(
|
|||||||
nByte =
|
nByte =
|
||||||
ROUND8(sizeof(VdbeCursor)) +
|
ROUND8(sizeof(VdbeCursor)) +
|
||||||
(isBtreeCursor?sqlite3BtreeCursorSize():0) +
|
(isBtreeCursor?sqlite3BtreeCursorSize():0) +
|
||||||
2*nField*sizeof(u32);
|
(2*nField+2)*sizeof(u32);
|
||||||
|
|
||||||
assert( iCur<p->nCursor );
|
assert( iCur<p->nCursor );
|
||||||
if( p->apCsr[iCur] ){
|
if( p->apCsr[iCur] ){
|
||||||
@@ -228,10 +228,11 @@ static VdbeCursor *allocateCursor(
|
|||||||
pCx->nField = nField;
|
pCx->nField = nField;
|
||||||
if( nField ){
|
if( nField ){
|
||||||
pCx->aType = (u32 *)&pMem->z[ROUND8(sizeof(VdbeCursor))];
|
pCx->aType = (u32 *)&pMem->z[ROUND8(sizeof(VdbeCursor))];
|
||||||
|
pCx->aOffset = pCx->aType + nField;
|
||||||
}
|
}
|
||||||
if( isBtreeCursor ){
|
if( isBtreeCursor ){
|
||||||
pCx->pCursor = (BtCursor*)
|
pCx->pCursor = (BtCursor*)
|
||||||
&pMem->z[ROUND8(sizeof(VdbeCursor))+2*nField*sizeof(u32)];
|
&pMem->z[ROUND8(sizeof(VdbeCursor))+(2*nField+2)*sizeof(u32)];
|
||||||
sqlite3BtreeCursorZero(pCx->pCursor);
|
sqlite3BtreeCursorZero(pCx->pCursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2253,151 +2254,101 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
|
|||||||
** skipped for length() and all content loading can be skipped for typeof().
|
** skipped for length() and all content loading can be skipped for typeof().
|
||||||
*/
|
*/
|
||||||
case OP_Column: {
|
case OP_Column: {
|
||||||
u32 payloadSize; /* Number of bytes in the record */
|
|
||||||
i64 payloadSize64; /* Number of bytes in the record */
|
i64 payloadSize64; /* Number of bytes in the record */
|
||||||
int p1; /* P1 value of the opcode */
|
int p1; /* P1 value of the opcode */
|
||||||
int p2; /* column number to retrieve */
|
int p2; /* column number to retrieve */
|
||||||
VdbeCursor *pC; /* The VDBE cursor */
|
VdbeCursor *pC; /* The VDBE cursor */
|
||||||
char *zRec; /* Pointer to complete record-data */
|
|
||||||
BtCursor *pCrsr; /* The BTree cursor */
|
BtCursor *pCrsr; /* The BTree cursor */
|
||||||
u32 *aType; /* aType[i] holds the numeric type of the i-th column */
|
u32 *aType; /* aType[i] holds the numeric type of the i-th column */
|
||||||
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
|
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
|
||||||
int nField; /* number of fields in the record */
|
int nField; /* number of fields in the record */
|
||||||
int len; /* The length of the serialized data for the column */
|
int len; /* The length of the serialized data for the column */
|
||||||
int i; /* Loop counter */
|
int i; /* Loop counter */
|
||||||
char *zData; /* Part of the record being decoded */
|
|
||||||
Mem *pDest; /* Where to write the extracted value */
|
Mem *pDest; /* Where to write the extracted value */
|
||||||
Mem sMem; /* For storing the record being decoded */
|
Mem sMem; /* For storing the record being decoded */
|
||||||
u8 *zIdx; /* Index into header */
|
const u8 *zData; /* Part of the record being decoded */
|
||||||
u8 *zEndHdr; /* Pointer to first byte after the header */
|
const u8 *zHdr; /* Next unparsed byte of the header */
|
||||||
|
const u8 *zEndHdr; /* Pointer to first byte after the header */
|
||||||
u32 offset; /* Offset into the data */
|
u32 offset; /* Offset into the data */
|
||||||
u32 szField; /* Number of bytes in the content of a field */
|
u32 szField; /* Number of bytes in the content of a field */
|
||||||
int szHdr; /* Size of the header size field at start of record */
|
|
||||||
int avail; /* Number of bytes of available data */
|
int avail; /* Number of bytes of available data */
|
||||||
u32 t; /* A type code from the record header */
|
u32 t; /* A type code from the record header */
|
||||||
Mem *pReg; /* PseudoTable input register */
|
Mem *pReg; /* PseudoTable input register */
|
||||||
|
|
||||||
|
|
||||||
p1 = pOp->p1;
|
p1 = pOp->p1;
|
||||||
p2 = pOp->p2;
|
|
||||||
pC = 0;
|
|
||||||
memset(&sMem, 0, sizeof(sMem));
|
|
||||||
assert( p1<p->nCursor );
|
assert( p1<p->nCursor );
|
||||||
|
p2 = pOp->p2;
|
||||||
|
sMem.zMalloc = 0;
|
||||||
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);
|
||||||
zRec = 0;
|
|
||||||
|
|
||||||
/* This block sets the variable payloadSize to be the total number of
|
|
||||||
** bytes in the record.
|
|
||||||
**
|
|
||||||
** zRec is set to be the complete text of the record if it is available.
|
|
||||||
** The complete record text is always available for pseudo-tables
|
|
||||||
** If the record is stored in a cursor, the complete record text
|
|
||||||
** might be available in the pC->aRow cache. Or it might not be.
|
|
||||||
** If the data is unavailable, zRec is set to NULL.
|
|
||||||
**
|
|
||||||
** We also compute the number of columns in the record. For cursors,
|
|
||||||
** the number of columns is stored in the VdbeCursor.nField element.
|
|
||||||
*/
|
|
||||||
pC = p->apCsr[p1];
|
pC = p->apCsr[p1];
|
||||||
assert( pC!=0 );
|
assert( pC!=0 );
|
||||||
|
nField = pC->nField;
|
||||||
|
assert( p2<nField );
|
||||||
|
aType = pC->aType;
|
||||||
|
aOffset = pC->aOffset;
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
assert( pC->pVtabCursor==0 );
|
assert( pC->pVtabCursor==0 );
|
||||||
#endif
|
#endif
|
||||||
pCrsr = pC->pCursor;
|
pCrsr = pC->pCursor;
|
||||||
if( pCrsr!=0 ){
|
assert( pCrsr!=0 || pC->pseudoTableReg>0 );
|
||||||
/* The record is stored in a B-Tree */
|
|
||||||
rc = sqlite3VdbeCursorMoveto(pC);
|
/* If the cursor cache is stale, bring it up-to-date */
|
||||||
if( rc ) goto abort_due_to_error;
|
rc = sqlite3VdbeCursorMoveto(pC);
|
||||||
if( pC->nullRow ){
|
if( rc ) goto abort_due_to_error;
|
||||||
payloadSize = 0;
|
if( pC->cacheStatus!=p->cacheCtr || (pOp->p5&OPFLAG_CLEARCACHE)!=0 ){
|
||||||
}else if( pC->cacheStatus==p->cacheCtr ){
|
if( pCrsr==0 ){
|
||||||
payloadSize = pC->payloadSize;
|
assert( pC->pseudoTableReg>0 );
|
||||||
zRec = (char*)pC->aRow;
|
pReg = &aMem[pC->pseudoTableReg];
|
||||||
}else if( pC->isIndex ){
|
if( pC->multiPseudo ){
|
||||||
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
|
||||||
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
|
Deephemeralize(pDest);
|
||||||
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
|
goto op_column_out;
|
||||||
/* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
|
}
|
||||||
** payload size, so it is impossible for payloadSize64 to be
|
assert( pReg->flags & MEM_Blob );
|
||||||
** larger than 32 bits. */
|
assert( memIsValid(pReg) );
|
||||||
assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 );
|
pC->payloadSize = pC->szRow = avail = pReg->n;
|
||||||
payloadSize = (u32)payloadSize64;
|
pC->aRow = (u8*)pReg->z;
|
||||||
}else{
|
}else if( pC->nullRow ){
|
||||||
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
MemSetTypeFlag(pDest, MEM_Null);
|
||||||
VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &payloadSize);
|
|
||||||
assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
assert( pC->pseudoTableReg>0 );
|
|
||||||
pReg = &aMem[pC->pseudoTableReg];
|
|
||||||
if( pC->multiPseudo ){
|
|
||||||
sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
|
|
||||||
Deephemeralize(pDest);
|
|
||||||
goto op_column_out;
|
goto op_column_out;
|
||||||
}
|
|
||||||
assert( pReg->flags & MEM_Blob );
|
|
||||||
assert( memIsValid(pReg) );
|
|
||||||
payloadSize = pReg->n;
|
|
||||||
zRec = pReg->z;
|
|
||||||
pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr;
|
|
||||||
assert( payloadSize==0 || zRec!=0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If payloadSize is 0, then just store a NULL. This can happen because of
|
|
||||||
** nullRow or because of a corrupt database. */
|
|
||||||
if( payloadSize==0 ){
|
|
||||||
MemSetTypeFlag(pDest, MEM_Null);
|
|
||||||
goto op_column_out;
|
|
||||||
}
|
|
||||||
assert( db->aLimit[SQLITE_LIMIT_LENGTH]>=0 );
|
|
||||||
if( payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
|
||||||
goto too_big;
|
|
||||||
}
|
|
||||||
|
|
||||||
nField = pC->nField;
|
|
||||||
assert( p2<nField );
|
|
||||||
|
|
||||||
/* Read and parse the table header. Store the results of the parse
|
|
||||||
** into the record header cache fields of the cursor.
|
|
||||||
*/
|
|
||||||
aType = pC->aType;
|
|
||||||
if( pC->cacheStatus==p->cacheCtr ){
|
|
||||||
aOffset = pC->aOffset;
|
|
||||||
}else{
|
|
||||||
assert(aType);
|
|
||||||
avail = 0;
|
|
||||||
pC->aOffset = aOffset = &aType[nField];
|
|
||||||
pC->payloadSize = payloadSize;
|
|
||||||
pC->cacheStatus = p->cacheCtr;
|
|
||||||
|
|
||||||
/* Figure out how many bytes are in the header */
|
|
||||||
if( zRec ){
|
|
||||||
zData = zRec;
|
|
||||||
}else{
|
}else{
|
||||||
if( pC->isIndex ){
|
if( pC->isIndex ){
|
||||||
zData = (char*)sqlite3BtreeKeyFetch(pCrsr, &avail);
|
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
||||||
|
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
|
||||||
|
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
|
||||||
|
/* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
|
||||||
|
** payload size, so it is impossible for payloadSize64 to be
|
||||||
|
** larger than 32 bits. */
|
||||||
|
assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 );
|
||||||
|
pC->aRow = sqlite3BtreeKeyFetch(pCrsr, &avail);
|
||||||
|
pC->payloadSize = (u32)payloadSize64;
|
||||||
}else{
|
}else{
|
||||||
zData = (char*)sqlite3BtreeDataFetch(pCrsr, &avail);
|
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
||||||
|
VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &pC->payloadSize);
|
||||||
|
assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
|
||||||
|
pC->aRow = sqlite3BtreeDataFetch(pCrsr, &avail);
|
||||||
}
|
}
|
||||||
/* If KeyFetch()/DataFetch() managed to get the entire payload,
|
assert( avail<=65536 ); /* Maximum page size is 64KiB */
|
||||||
** save the payload in the pC->aRow cache. That will save us from
|
if( pC->payloadSize <= (u32)avail ){
|
||||||
** having to make additional calls to fetch the content portion of
|
pC->szRow = pC->payloadSize;
|
||||||
** the record.
|
|
||||||
*/
|
|
||||||
assert( avail>=0 );
|
|
||||||
if( payloadSize <= (u32)avail ){
|
|
||||||
zRec = zData;
|
|
||||||
pC->aRow = (u8*)zData;
|
|
||||||
}else{
|
}else{
|
||||||
pC->aRow = 0;
|
pC->szRow = avail;
|
||||||
|
}
|
||||||
|
if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||||
|
goto too_big;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* The following assert is true in all cases except when
|
|
||||||
** the database file has been corrupted externally.
|
pC->cacheStatus = p->cacheCtr;
|
||||||
** assert( zRec!=0 || avail>=payloadSize || avail>=9 ); */
|
pC->iHdrOffset = getVarint32(pC->aRow, offset);
|
||||||
szHdr = getVarint32((u8*)zData, offset);
|
pC->nHdrParsed = 0;
|
||||||
|
aOffset[0] = offset;
|
||||||
|
if( avail<offset ){
|
||||||
|
pC->aRow = 0;
|
||||||
|
pC->szRow = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make sure a corrupt database has not given us an oversize header.
|
/* Make sure a corrupt database has not given us an oversize header.
|
||||||
** Do this now to avoid an oversize memory allocation.
|
** Do this now to avoid an oversize memory allocation.
|
||||||
@@ -2408,78 +2359,55 @@ case OP_Column: {
|
|||||||
** 3-byte type for each of the maximum of 32768 columns plus three
|
** 3-byte type for each of the maximum of 32768 columns plus three
|
||||||
** extra bytes for the header length itself. 32768*3 + 3 = 98307.
|
** extra bytes for the header length itself. 32768*3 + 3 = 98307.
|
||||||
*/
|
*/
|
||||||
if( offset > 98307 ){
|
if( offset > 98307 || offset > pC->payloadSize ){
|
||||||
rc = SQLITE_CORRUPT_BKPT;
|
rc = SQLITE_CORRUPT_BKPT;
|
||||||
goto op_column_out;
|
goto op_column_out;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Compute in len the number of bytes of data we need to read in order
|
/* Make sure at least the first p2+1 entries of the header have been
|
||||||
** to get nField type values. offset is an upper bound on this. But
|
** parsed and valid information is in aOffset[] and aType[].
|
||||||
** nField might be significantly less than the true number of columns
|
*/
|
||||||
** in the table, and in that case, 5*nField+3 might be smaller than offset.
|
if( pC->nHdrParsed<=p2 && pC->iHdrOffset<aOffset[0] ){
|
||||||
** We want to minimize len in order to limit the size of the memory
|
/* Make sure zData points to enough of the record to cover the header. */
|
||||||
** allocation, especially if a corrupt database file has caused offset
|
if( pC->aRow==0 ){
|
||||||
** to be oversized. Offset is limited to 98307 above. But 98307 might
|
memset(&sMem, 0, sizeof(sMem));
|
||||||
** still exceed Robson memory allocation limits on some configurations.
|
rc = sqlite3VdbeMemFromBtree(pCrsr, 0, pC->aOffset[0], pC->isIndex,&sMem);
|
||||||
** On systems that cannot tolerate large memory allocations, nField*5+3
|
|
||||||
** will likely be much smaller since nField will likely be less than
|
|
||||||
** 20 or so. This insures that Robson memory allocation limits are
|
|
||||||
** not exceeded even for corrupt database files.
|
|
||||||
*/
|
|
||||||
len = nField*5 + 3;
|
|
||||||
if( len > (int)offset ) len = (int)offset;
|
|
||||||
|
|
||||||
/* The KeyFetch() or DataFetch() above are fast and will get the entire
|
|
||||||
** record header in most cases. But they will fail to get the complete
|
|
||||||
** record header if the record header does not fit on a single page
|
|
||||||
** in the B-Tree. When that happens, use sqlite3VdbeMemFromBtree() to
|
|
||||||
** acquire the complete header text.
|
|
||||||
*/
|
|
||||||
if( !zRec && avail<len ){
|
|
||||||
sMem.flags = 0;
|
|
||||||
sMem.db = 0;
|
|
||||||
rc = sqlite3VdbeMemFromBtree(pCrsr, 0, len, pC->isIndex, &sMem);
|
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
goto op_column_out;
|
goto op_column_out;
|
||||||
}
|
}
|
||||||
zData = sMem.z;
|
zData = (u8*)sMem.z;
|
||||||
|
}else{
|
||||||
|
zData = pC->aRow;
|
||||||
}
|
}
|
||||||
zEndHdr = (u8 *)&zData[len];
|
|
||||||
zIdx = (u8 *)&zData[szHdr];
|
|
||||||
|
|
||||||
/* Scan the header and use it to fill in the aType[] and aOffset[]
|
/* Fill in aType[i] and aOffset[i] values through the p2-th field. */
|
||||||
** arrays. aType[i] will contain the type integer for the i-th
|
i = pC->nHdrParsed;
|
||||||
** column and aOffset[i] will contain the offset from the beginning
|
offset = aOffset[i];
|
||||||
** of the record to the start of the data for the i-th column
|
zHdr = zData + pC->iHdrOffset;
|
||||||
*/
|
zEndHdr = zData + pC->aOffset[0];
|
||||||
for(i=0; i<nField; i++){
|
for(; i<=p2 && zHdr<zEndHdr; i++){
|
||||||
if( zIdx<zEndHdr ){
|
if( zHdr[0]<0x80 ){
|
||||||
aOffset[i] = offset;
|
t = zHdr[0];
|
||||||
if( zIdx[0]<0x80 ){
|
zHdr++;
|
||||||
t = zIdx[0];
|
|
||||||
zIdx++;
|
|
||||||
}else{
|
|
||||||
zIdx += sqlite3GetVarint32(zIdx, &t);
|
|
||||||
}
|
|
||||||
aType[i] = t;
|
|
||||||
szField = sqlite3VdbeSerialTypeLen(t);
|
|
||||||
offset += szField;
|
|
||||||
if( offset<szField ){ /* True if offset overflows */
|
|
||||||
zIdx = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}else{
|
}else{
|
||||||
/* If i is less that nField, then there are fewer fields in this
|
zHdr += sqlite3GetVarint32(zHdr, &t);
|
||||||
** record than SetNumColumns indicated there are columns in the
|
|
||||||
** table. Set the offset for any extra columns not present in
|
|
||||||
** the record to 0. This tells code below to store the default value
|
|
||||||
** for the column instead of deserializing a value from the record.
|
|
||||||
*/
|
|
||||||
aOffset[i] = 0;
|
|
||||||
}
|
}
|
||||||
|
aType[i] = t;
|
||||||
|
szField = sqlite3VdbeSerialTypeLen(t);
|
||||||
|
offset += szField;
|
||||||
|
if( offset<szField ){ /* True if offset overflows */
|
||||||
|
zHdr = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
aOffset[i+1] = offset;
|
||||||
|
}
|
||||||
|
pC->nHdrParsed = i;
|
||||||
|
pC->iHdrOffset = (u32)(zHdr - zData);
|
||||||
|
if( pC->aRow==0 ){
|
||||||
|
sqlite3VdbeMemRelease(&sMem);
|
||||||
|
sMem.flags = MEM_Null;
|
||||||
}
|
}
|
||||||
sqlite3VdbeMemRelease(&sMem);
|
|
||||||
sMem.flags = MEM_Null;
|
|
||||||
|
|
||||||
/* If we have read more header data than was contained in the header,
|
/* If we have read more header data than was contained in the header,
|
||||||
** or if the end of the last field appears to be past the end of the
|
** or if the end of the last field appears to be past the end of the
|
||||||
@@ -2487,8 +2415,10 @@ case OP_Column: {
|
|||||||
** of the record (when all fields present), then we must be dealing
|
** of the record (when all fields present), then we must be dealing
|
||||||
** with a corrupt database.
|
** with a corrupt database.
|
||||||
*/
|
*/
|
||||||
if( (zIdx > zEndHdr) || (offset > payloadSize)
|
if( (zHdr > zEndHdr)
|
||||||
|| (zIdx==zEndHdr && offset!=payloadSize) ){
|
|| (offset > pC->payloadSize)
|
||||||
|
|| (zHdr==zEndHdr && offset!=pC->payloadSize)
|
||||||
|
){
|
||||||
rc = SQLITE_CORRUPT_BKPT;
|
rc = SQLITE_CORRUPT_BKPT;
|
||||||
goto op_column_out;
|
goto op_column_out;
|
||||||
}
|
}
|
||||||
@@ -2500,12 +2430,12 @@ case OP_Column: {
|
|||||||
** request. In this case, set the value NULL or to P4 if P4 is
|
** request. In this case, set the value NULL or to P4 if P4 is
|
||||||
** a pointer to a Mem object.
|
** a pointer to a Mem object.
|
||||||
*/
|
*/
|
||||||
if( aOffset[p2] ){
|
if( p2<pC->nHdrParsed ){
|
||||||
assert( rc==SQLITE_OK );
|
assert( rc==SQLITE_OK );
|
||||||
if( zRec ){
|
if( pC->szRow>=aOffset[p2+1] ){
|
||||||
/* This is the common case where the whole row fits on a single page */
|
/* This is the common case where the whole row fits on a single page */
|
||||||
VdbeMemRelease(pDest);
|
VdbeMemRelease(pDest);
|
||||||
sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], pDest);
|
sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
|
||||||
}else{
|
}else{
|
||||||
/* This branch happens only when the row overflows onto multiple pages */
|
/* This branch happens only when the row overflows onto multiple pages */
|
||||||
t = aType[p2];
|
t = aType[p2];
|
||||||
@@ -2517,18 +2447,19 @@ case OP_Column: {
|
|||||||
** bogus content rather than reading content from disk. NULL works
|
** bogus content rather than reading content from disk. NULL works
|
||||||
** for text and blob and whatever is in the payloadSize64 variable
|
** for text and blob and whatever is in the payloadSize64 variable
|
||||||
** will work for everything else. */
|
** will work for everything else. */
|
||||||
zData = t<12 ? (char*)&payloadSize64 : 0;
|
zData = t<12 ? (u8*)&payloadSize64 : 0;
|
||||||
}else{
|
}else{
|
||||||
len = sqlite3VdbeSerialTypeLen(t);
|
len = sqlite3VdbeSerialTypeLen(t);
|
||||||
|
memset(&sMem, 0, sizeof(sMem));
|
||||||
sqlite3VdbeMemMove(&sMem, pDest);
|
sqlite3VdbeMemMove(&sMem, pDest);
|
||||||
rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex,
|
rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex,
|
||||||
&sMem);
|
&sMem);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
goto op_column_out;
|
goto op_column_out;
|
||||||
}
|
}
|
||||||
zData = sMem.z;
|
zData = (u8*)sMem.z;
|
||||||
}
|
}
|
||||||
sqlite3VdbeSerialGet((u8*)zData, t, pDest);
|
sqlite3VdbeSerialGet(zData, t, pDest);
|
||||||
}
|
}
|
||||||
pDest->enc = encoding;
|
pDest->enc = encoding;
|
||||||
}else{
|
}else{
|
||||||
@@ -3312,6 +3243,8 @@ case OP_OpenWrite: {
|
|||||||
nField = pOp->p4.i;
|
nField = pOp->p4.i;
|
||||||
}
|
}
|
||||||
assert( pOp->p1>=0 );
|
assert( pOp->p1>=0 );
|
||||||
|
assert( nField>=0 );
|
||||||
|
testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */
|
||||||
pCur = allocateCursor(p, pOp->p1, nField, iDb, 1);
|
pCur = allocateCursor(p, pOp->p1, nField, iDb, 1);
|
||||||
if( pCur==0 ) goto no_mem;
|
if( pCur==0 ) goto no_mem;
|
||||||
pCur->nullRow = 1;
|
pCur->nullRow = 1;
|
||||||
@@ -3372,6 +3305,7 @@ case OP_OpenEphemeral: {
|
|||||||
SQLITE_OPEN_DELETEONCLOSE |
|
SQLITE_OPEN_DELETEONCLOSE |
|
||||||
SQLITE_OPEN_TRANSIENT_DB;
|
SQLITE_OPEN_TRANSIENT_DB;
|
||||||
assert( pOp->p1>=0 );
|
assert( pOp->p1>=0 );
|
||||||
|
assert( pOp->p2>=0 );
|
||||||
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
||||||
if( pCx==0 ) goto no_mem;
|
if( pCx==0 ) goto no_mem;
|
||||||
pCx->nullRow = 1;
|
pCx->nullRow = 1;
|
||||||
@@ -3417,6 +3351,8 @@ case OP_OpenEphemeral: {
|
|||||||
case OP_SorterOpen: {
|
case OP_SorterOpen: {
|
||||||
VdbeCursor *pCx;
|
VdbeCursor *pCx;
|
||||||
|
|
||||||
|
assert( pOp->p1>=0 );
|
||||||
|
assert( pOp->p2>=0 );
|
||||||
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
||||||
if( pCx==0 ) goto no_mem;
|
if( pCx==0 ) goto no_mem;
|
||||||
pCx->pKeyInfo = pOp->p4.pKeyInfo;
|
pCx->pKeyInfo = pOp->p4.pKeyInfo;
|
||||||
@@ -3448,6 +3384,7 @@ case OP_OpenPseudo: {
|
|||||||
VdbeCursor *pCx;
|
VdbeCursor *pCx;
|
||||||
|
|
||||||
assert( pOp->p1>=0 );
|
assert( pOp->p1>=0 );
|
||||||
|
assert( pOp->p3>=0 );
|
||||||
pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
|
pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
|
||||||
if( pCx==0 ) goto no_mem;
|
if( pCx==0 ) goto no_mem;
|
||||||
pCx->nullRow = 1;
|
pCx->nullRow = 1;
|
||||||
@@ -4421,6 +4358,7 @@ case OP_NullRow: {
|
|||||||
assert( pC!=0 );
|
assert( pC!=0 );
|
||||||
pC->nullRow = 1;
|
pC->nullRow = 1;
|
||||||
pC->rowidIsValid = 0;
|
pC->rowidIsValid = 0;
|
||||||
|
pC->cacheStatus = CACHE_STALE;
|
||||||
assert( pC->pCursor || pC->pVtabCursor );
|
assert( pC->pCursor || pC->pVtabCursor );
|
||||||
if( pC->pCursor ){
|
if( pC->pCursor ){
|
||||||
sqlite3BtreeClearCursor(pC->pCursor);
|
sqlite3BtreeClearCursor(pC->pCursor);
|
||||||
|
@@ -93,10 +93,14 @@ struct VdbeCursor {
|
|||||||
** be NULL.
|
** be NULL.
|
||||||
*/
|
*/
|
||||||
u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
|
u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
|
||||||
int payloadSize; /* Total number of bytes in the record */
|
u32 payloadSize; /* Total number of bytes in the record */
|
||||||
|
u16 nHdrParsed; /* Number of header fields parsed so far */
|
||||||
|
u16 nFieldPresent; /* Number of fields in the record */
|
||||||
|
u32 szRow; /* Byte available in aRow */
|
||||||
|
u32 iHdrOffset; /* Offset to next unparsed byte of the header */
|
||||||
u32 *aType; /* Type values for all entries in the record */
|
u32 *aType; /* Type values for all entries in the record */
|
||||||
u32 *aOffset; /* Cached offsets to the start of each columns data */
|
u32 *aOffset; /* Cached offsets to the start of each columns data */
|
||||||
u8 *aRow; /* Data for the current row, if all on one page */
|
const u8 *aRow; /* Data for the current row, if all on one page */
|
||||||
};
|
};
|
||||||
typedef struct VdbeCursor VdbeCursor;
|
typedef struct VdbeCursor VdbeCursor;
|
||||||
|
|
||||||
|
@@ -2658,7 +2658,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor *p){
|
|||||||
#endif
|
#endif
|
||||||
p->deferredMoveto = 0;
|
p->deferredMoveto = 0;
|
||||||
p->cacheStatus = CACHE_STALE;
|
p->cacheStatus = CACHE_STALE;
|
||||||
}else if( ALWAYS(p->pCursor) ){
|
}else if( p->pCursor ){
|
||||||
int hasMoved;
|
int hasMoved;
|
||||||
int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved);
|
int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved);
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
|
Reference in New Issue
Block a user