diff options
author | drh <drh@noemail.net> | 2019-07-11 19:22:36 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2019-07-11 19:22:36 +0000 |
commit | c1da4397d6920ebdefbf4eeaf35c780f5478c6fb (patch) | |
tree | 5bd9f9f0627429d64578228ea38f5eefe3618a5b /src | |
parent | ea7e83b7806773bf6a2c60786ff8f95b218d4622 (diff) | |
download | sqlite-c1da4397d6920ebdefbf4eeaf35c780f5478c6fb.tar.gz sqlite-c1da4397d6920ebdefbf4eeaf35c780f5478c6fb.zip |
Move the sqlite3VdbeSerialType() routine in-line in the OP_MakeRecord opcode.
Optimizing compilers were doing this already. By doing it manually, we can
omit some redundant tests and make the whole thing run a million cycles faster
and use about 80 bytes less code space.
FossilOrigin-Name: d837ab0da52632699abc09320980606aef020df5020c253f99c97e24bf3c6d00
Diffstat (limited to 'src')
-rw-r--r-- | src/vdbe.c | 84 | ||||
-rw-r--r-- | src/vdbeInt.h | 2 | ||||
-rw-r--r-- | src/vdbeaux.c | 7 |
3 files changed, 80 insertions, 13 deletions
diff --git a/src/vdbe.c b/src/vdbe.c index d697d6b1e..6c34fb020 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2932,9 +2932,8 @@ case OP_MakeRecord: { pRec = pLast; do{ assert( memIsValid(pRec) ); - serial_type = sqlite3VdbeSerialType(pRec, file_format, &len); - if( pRec->flags & MEM_Zero ){ - if( serial_type==0 ){ + if( pRec->flags & MEM_Null ){ + if( pRec->flags & MEM_Zero ){ /* Values with MEM_Null and MEM_Zero are created by xColumn virtual ** table methods that never invoke sqlite3_result_xxxxx() while ** computing an unchanging column value in an UPDATE statement. @@ -2942,19 +2941,78 @@ case OP_MakeRecord: { ** so that they can be passed through to xUpdate and have ** a true sqlite3_value_nochange(). */ assert( pOp->p5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB ); - serial_type = 10; - }else if( nData ){ - if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem; + pRec->uTemp = 10; }else{ - nZero += pRec->u.nZero; - len -= pRec->u.nZero; + pRec->uTemp = 0; /* Serial-type 0 means NULL */ } + nHdr++; + }else if( pRec->flags & (MEM_Int|MEM_IntReal) ){ + /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ + i64 i = pRec->u.i; + u64 u; + testcase( pRec->flags & MEM_Int ); + testcase( pRec->flags & MEM_IntReal ); + if( i<0 ){ + u = ~i; + }else{ + u = i; + } + nHdr++; + if( u<=127 ){ + if( (i&1)==i && file_format>=4 ){ + pRec->uTemp = 8+(u32)u; + }else{ + nData++; + pRec->uTemp = 1; + } + }else if( u<=32767 ){ + nData += 2; + pRec->uTemp = 2; + }else if( u<=8388607 ){ + nData += 3; + pRec->uTemp = 3; + }else if( u<=2147483647 ){ + nData += 4; + pRec->uTemp = 4; + }else if( u<=140737488355327LL ){ + nData += 6; + pRec->uTemp = 5; + }else{ + nData += 8; + if( pRec->flags & MEM_IntReal ){ + /* If the value is IntReal and is going to take up 8 bytes to store + ** as an integer, then we might as well make it an 8-byte floating + ** point value */ + pRec->u.r = (double)pRec->u.i; + pRec->flags &= ~MEM_IntReal; + pRec->flags |= MEM_Real; + pRec->uTemp = 7; + }else{ + pRec->uTemp = 6; + } + } + }else if( pRec->flags & MEM_Real ){ + nHdr++; + nData += 8; + pRec->uTemp = 7; + }else{ + assert( db->mallocFailed || pRec->flags&(MEM_Str|MEM_Blob) ); + assert( pRec->n>=0 ); + len = (u32)pRec->n; + serial_type = (len*2) + 12 + ((pRec->flags & MEM_Str)!=0); + if( pRec->flags & MEM_Zero ){ + serial_type += pRec->u.nZero*2; + if( nData ){ + if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem; + len += pRec->u.nZero; + }else{ + nZero += pRec->u.nZero; + } + } + nData += len; + nHdr += sqlite3VarintLen(serial_type); + pRec->uTemp = serial_type; } - nData += len; - testcase( serial_type==127 ); - testcase( serial_type==128 ); - nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type); - pRec->uTemp = serial_type; if( pRec==pData0 ) break; pRec--; }while(1); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 17e057b18..3332b4838 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -486,7 +486,9 @@ int sqlite3VdbeCursorMoveto(VdbeCursor**, int*); int sqlite3VdbeCursorRestore(VdbeCursor*); u32 sqlite3VdbeSerialTypeLen(u32); u8 sqlite3VdbeOneByteSerialTypeLen(u8); +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 u32 sqlite3VdbeSerialType(Mem*, int, u32*); +#endif u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32); u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 8dd2b421a..c21d7db40 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3430,10 +3430,16 @@ int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){ ** of SQLite will not understand those serial types. */ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 /* ** Return the serial-type for the value stored in pMem. ** ** This routine might convert a large MEM_IntReal value into MEM_Real. +** +** 2019-07-11: The primary user of this subroutine was the OP_MakeRecord +** opcode in the byte-code engine. But by moving this routine in-line, we +** can omit some redundant tests and make that opcode a lot faster. So +** this routine is now only used by the STAT3/4 logic. */ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ int flags = pMem->flags; @@ -3494,6 +3500,7 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ *pLen = n; return ((n*2) + 12 + ((flags&MEM_Str)!=0)); } +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ /* ** The sizes for serial types less than 128 |