aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2019-07-11 19:22:36 +0000
committerdrh <drh@noemail.net>2019-07-11 19:22:36 +0000
commitc1da4397d6920ebdefbf4eeaf35c780f5478c6fb (patch)
tree5bd9f9f0627429d64578228ea38f5eefe3618a5b /src
parentea7e83b7806773bf6a2c60786ff8f95b218d4622 (diff)
downloadsqlite-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.c84
-rw-r--r--src/vdbeInt.h2
-rw-r--r--src/vdbeaux.c7
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