Make MEM_IntReal a completely independent type, meaning a floating point

value stored as an integer.  This fixes a problem with arithmetic within
arguments to string functions on indexes of expressions.  But it is a big
change and needs lots of new testcase() macros for MC/DC and so it is
initially put on this branch.

FossilOrigin-Name: dba836e31cb29d339b4520acb06188a892a52e45c50aba9742966b01108e251a
This commit is contained in:
drh 2019-05-02 21:36:26 +00:00
parent de7109e61b
commit 169f077e07
7 changed files with 80 additions and 63 deletions

View File

@ -1,5 +1,5 @@
C Ensure\sthat\sthe\stypeof()\sfunction\salways\sreturns\sSQLITE_FLOAT\sfor\sfloating\npoint\svalues\seven\swhen\sthe\svalue\sis\sstored\sas\san\sinteger\sto\ssave\sspace.
D 2019-05-02T17:45:52.902
C Make\sMEM_IntReal\sa\scompletely\sindependent\stype,\smeaning\sa\sfloating\spoint\nvalue\sstored\sas\san\sinteger.\s\sThis\sfixes\sa\sproblem\swith\sarithmetic\swithin\narguments\sto\sstring\sfunctions\son\sindexes\sof\sexpressions.\s\sBut\sit\sis\sa\sbig\nchange\sand\sneeds\slots\sof\snew\stestcase()\smacros\sfor\sMC/DC\sand\sso\sit\sis\ninitially\sput\son\sthis\sbranch.
D 2019-05-02T21:36:26.172
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -591,15 +591,15 @@ F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507
F src/util.c 5061987401c2e8003177fa30d73196aa036727c8f04bf36a2df0c82b1904a236
F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf
F src/vdbe.c 36993059b87e7c2adf671aaa4ef5e0f826b6f4d95be15b019aee14308f0047b5
F src/vdbe.c ddb6bb7289e017870636a60914bca64a545f70413e71c0e791513211b22f307c
F src/vdbe.h 712bca562eaed1c25506b9faf9680bdc75fc42e2f4a1cd518d883fa79c7a4237
F src/vdbeInt.h 3ba14553508d66f58753952d6dd287dce4ec735de02c6440858b4891aed51c17
F src/vdbeapi.c 5ef992332225d8b6151137fcaf33b4ba4d38db7e7c51f871d2e9ecb960f3709a
F src/vdbeaux.c f873b5c2efcf8a4d6ecfc5b1a5b06fd810419198f3bd882175d371cc03801873
F src/vdbeapi.c 76b8fcedce6d6299599580d98ce71f6d806e297c6e584d27d0356de44df3b307
F src/vdbeaux.c 326e049995ca75ba158bbc09ef59347fd600c8e7bb3958db9e66d575fdcc243d
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
F src/vdbemem.c df36fd36c7585e42869f3a44f5da5dc70e13306bc97ba52eebe069e174ba55db
F src/vdbemem.c e102c625dae2d5657a086b97f46ea7645cce23379fcae74737fbe00454399a81
F src/vdbesort.c 66592d478dbb46f19aed0b42222325eadb84deb40a90eebe25c6e7c1d8468f47
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0
F src/vtab.c 1fa256c6ddad7a81e2a4dc080d015d4b0a7135767717d311298e47f6fca64bb3
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c b09a2a9cab50efa08451a8c81d47052120ad5da174048c6d0b08d405384abdf2
@ -1822,7 +1822,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 005a169406ccea6e3cc42271620870d985e8bada1ad49a63656003db4911cb51
R 1a712fa3e334798d542297677e583b67
P 48889530a9de22fee536edfd1627be62396ed18d842d5fd6d91e010b4337be95
R 5d33250f3b2797d2fce07efa1f0f1900
T *branch * int-real
T *sym-int-real *
T -sym-trunk *
U drh
Z 11e98b9b34589d0e8654b135f89f5a58
Z 3590ba61495883d222cfb9f777b00293

View File

@ -1 +1 @@
48889530a9de22fee536edfd1627be62396ed18d842d5fd6d91e010b4337be95
dba836e31cb29d339b4520acb06188a892a52e45c50aba9742966b01108e251a

View File

@ -295,7 +295,7 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
double rValue;
i64 iValue;
u8 enc = pRec->enc;
assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str );
assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str );
if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return;
if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){
pRec->u.i = iValue;
@ -352,11 +352,11 @@ static void applyAffinity(
** there is already a string rep, but it is pointless to waste those
** CPU cycles. */
if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/
if( (pRec->flags&(MEM_Real|MEM_Int)) ){
if( (pRec->flags&(MEM_Real|MEM_Int|MEM_IntReal)) ){
sqlite3VdbeMemStringify(pRec, enc, 1);
}
}
pRec->flags &= ~(MEM_Real|MEM_Int);
pRec->flags &= ~(MEM_Real|MEM_Int|MEM_IntReal);
}
}
@ -395,7 +395,7 @@ void sqlite3ValueApplyAffinity(
** accordingly.
*/
static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
assert( (pMem->flags & (MEM_Int|MEM_Real))==0 );
assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 );
assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 );
ExpandBlob(pMem);
if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){
@ -415,8 +415,8 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
** But it does set pMem->u.r and pMem->u.i appropriately.
*/
static u16 numericType(Mem *pMem){
if( pMem->flags & (MEM_Int|MEM_Real) ){
return pMem->flags & (MEM_Int|MEM_Real);
if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal) ){
return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal);
}
if( pMem->flags & (MEM_Str|MEM_Blob) ){
return computeNumericType(pMem);
@ -514,7 +514,7 @@ static void memTracePrint(Mem *p){
printf(p->flags & MEM_Zero ? " NULL-nochng" : " NULL");
}else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
printf(" si:%lld", p->u.i);
}else if( (p->flags & (MEM_Int|MEM_IntReal))==(MEM_Int|MEM_IntReal) ){
}else if( (p->flags & (MEM_IntReal))!=0 ){
printf(" ir:%lld", p->u.i);
}else if( p->flags & MEM_Int ){
printf(" i:%lld", p->u.i);
@ -1630,7 +1630,7 @@ fp_math:
}
pOut->u.r = rB;
MemSetTypeFlag(pOut, MEM_Real);
if( ((type1|type2)&MEM_Real)==0 && !bIntint ){
if( ((type1|type2)&(MEM_Real|MEM_IntReal))==0 && !bIntint ){
sqlite3VdbeIntegerAffinity(pOut);
}
#endif
@ -1801,7 +1801,7 @@ case OP_MustBeInt: { /* jump, in1 */
*/
case OP_RealAffinity: { /* in1 */
pIn1 = &aMem[pOp->p1];
if( pIn1->flags & MEM_Int ){
if( pIn1->flags & (MEM_Int|MEM_IntReal) ){
sqlite3VdbeMemRealify(pIn1);
}
break;
@ -1993,7 +1993,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
affinity = pOp->p5 & SQLITE_AFF_MASK;
if( affinity>=SQLITE_AFF_NUMERIC ){
if( (flags1 | flags3)&MEM_Str ){
if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
applyNumericAffinity(pIn1,0);
assert( flags3==pIn3->flags );
/* testcase( flags3!=pIn3->flags );
@ -2003,7 +2003,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** in case our analysis is incorrect, so it is left in. */
flags3 = pIn3->flags;
}
if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
applyNumericAffinity(pIn3,0);
}
}
@ -2016,17 +2016,19 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
goto compare_op;
}
}else if( affinity==SQLITE_AFF_TEXT ){
if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){
if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn1->flags & MEM_Int );
testcase( pIn1->flags & MEM_Real );
testcase( pIn1->flags & MEM_IntReal );
sqlite3VdbeMemStringify(pIn1, encoding, 1);
testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
assert( pIn1!=pIn3 );
}
if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){
if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn3->flags & MEM_Int );
testcase( pIn3->flags & MEM_Real );
testcase( pIn3->flags & MEM_IntReal );
sqlite3VdbeMemStringify(pIn3, encoding, 1);
testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) );
flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
@ -2790,6 +2792,7 @@ case OP_Affinity: {
/* When applying REAL affinity, if the result is still MEM_Int,
** indicate that REAL is actually desired */
pIn1->flags |= MEM_IntReal;
pIn1->flags &= ~MEM_Int;
}
REGISTER_TRACE((int)(pIn1-aMem), pIn1);
zAffinity++;
@ -3987,14 +3990,14 @@ case OP_SeekGT: { /* jump, in3, group */
** blob, or NULL. But it needs to be an integer before we can do
** the seek, so convert it. */
pIn3 = &aMem[pOp->p3];
if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Str))==MEM_Str ){
applyNumericAffinity(pIn3, 0);
}
iKey = sqlite3VdbeIntValue(pIn3);
/* If the P3 value could not be converted into an integer without
** loss of information, then special processing is required... */
if( (pIn3->flags & MEM_Int)==0 ){
if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){
if( (pIn3->flags & MEM_Real)==0 ){
/* If the P3 value cannot be converted into any kind of a number,
** then the seek is not possible, so jump to P2 */
@ -4379,7 +4382,7 @@ case OP_SeekRowid: { /* jump, in3 */
u64 iKey;
pIn3 = &aMem[pOp->p3];
if( (pIn3->flags & MEM_Int)==0 ){
if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){
/* Make sure pIn3->u.i contains a valid integer representation of
** the key value, but do not change the datatype of the register, as
** other parts of the perpared statement might be depending on the

View File

@ -266,7 +266,7 @@ int sqlite3_value_type(sqlite3_value* pVal){
SQLITE_NULL, /* 0x1d */
SQLITE_INTEGER, /* 0x1e */
SQLITE_NULL, /* 0x1f */
SQLITE_BLOB, /* 0x20 */
SQLITE_FLOAT, /* 0x20 */
SQLITE_NULL, /* 0x21 */
SQLITE_TEXT, /* 0x22 */
SQLITE_NULL, /* 0x23 */
@ -304,10 +304,10 @@ int sqlite3_value_type(sqlite3_value* pVal){
int eType = SQLITE_BLOB;
if( pVal->flags & MEM_Null ){
eType = SQLITE_NULL;
}else if( pVal->flags & MEM_Int ){
eType = (pVal->flags & MEM_IntReal) ? SQLITE_FLOAT : SQLITE_INTEGER;
}else if( pVal->flags & MEM_Real ){
}else if( pVal->flags & (MEM_Real|MEM_IntReal) ){
eType = SQLITE_FLOAT;
}else if( pVal->flags & MEM_Int ){
eType = SQLITE_INTEGER;
}else if( pVal->flags & MEM_Str ){
eType = SQLITE_TEXT;
}
@ -1849,7 +1849,7 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
}else if( iIdx>=p->pUnpacked->nField ){
*ppValue = (sqlite3_value *)columnNullValue();
}else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
if( pMem->flags & MEM_Int ){
if( pMem->flags & (MEM_Int|MEM_IntReal) ){
sqlite3VdbeMemRealify(pMem);
}
}

View File

@ -1534,7 +1534,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
Mem *pMem = pOp->p4.pMem;
if( pMem->flags & MEM_Str ){
zP4 = pMem->z;
}else if( pMem->flags & MEM_Int ){
}else if( pMem->flags & (MEM_Int|MEM_IntReal) ){
sqlite3_str_appendf(&x, "%lld", pMem->u.i);
}else if( pMem->flags & MEM_Real ){
sqlite3_str_appendf(&x, "%.16g", pMem->u.r);
@ -3432,7 +3432,7 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
*pLen = 0;
return 0;
}
if( flags&MEM_Int ){
if( flags&(MEM_Int|MEM_IntReal) ){
/* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
# define MAX_6BYTE ((((i64)0x00008000)<<32)-1)
i64 i = pMem->u.i;
@ -4111,8 +4111,8 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
/* At least one of the two values is a number
*/
if( combined_flags&(MEM_Int|MEM_Real) ){
if( (f1 & f2 & MEM_Int)!=0 ){
if( combined_flags&(MEM_Int|MEM_Real|MEM_IntReal) ){
if( (f1 & f2 & (MEM_Int|MEM_IntReal))!=0 ){
if( pMem1->u.i < pMem2->u.i ) return -1;
if( pMem1->u.i > pMem2->u.i ) return +1;
return 0;
@ -4122,15 +4122,19 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
if( pMem1->u.r > pMem2->u.r ) return +1;
return 0;
}
if( (f1&MEM_Int)!=0 ){
if( (f1&(MEM_Int|MEM_IntReal))!=0 ){
if( (f2&MEM_Real)!=0 ){
return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r);
}else if( (f2&(MEM_Int|MEM_IntReal))!=0 ){
if( pMem1->u.i < pMem2->u.i ) return -1;
if( pMem1->u.i > pMem2->u.i ) return +1;
return 0;
}else{
return -1;
}
}
if( (f1&MEM_Real)!=0 ){
if( (f2&MEM_Int)!=0 ){
if( (f2&(MEM_Int|MEM_IntReal))!=0 ){
return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r);
}else{
return -1;
@ -4279,7 +4283,7 @@ int sqlite3VdbeRecordCompareWithSkip(
u32 serial_type;
/* RHS is an integer */
if( pRhs->flags & MEM_Int ){
if( pRhs->flags & (MEM_Int|MEM_IntReal) ){
serial_type = aKey1[idx1];
testcase( serial_type==12 );
if( serial_type>=10 ){
@ -4624,7 +4628,9 @@ RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
testcase( flags & MEM_Real );
testcase( flags & MEM_Null );
testcase( flags & MEM_Blob );
if( (flags & (MEM_Real|MEM_Null|MEM_Blob))==0 && p->pKeyInfo->aColl[0]==0 ){
if( (flags & (MEM_Real|MEM_IntReal|MEM_Null|MEM_Blob))==0
&& p->pKeyInfo->aColl[0]==0
){
assert( flags & MEM_Str );
return vdbeRecordCompareString;
}

View File

@ -18,6 +18,11 @@
#include "sqliteInt.h"
#include "vdbeInt.h"
/* True if X is a power of two. 0 is considered a power of two here.
** In other words, return true if X has at most one bit set.
*/
#define ISPOWEROF2(X) (((X)&((X)-1))==0)
#ifdef SQLITE_DEBUG
/*
** Check invariants on a Mem object.
@ -37,8 +42,8 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
** That saves a few cycles in inner loops. */
assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 );
/* Cannot be both MEM_Int and MEM_Real at the same time */
assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );
/* Cannot have more than one of MEM_Int, MEM_Real, or MEM_IntReal */
assert( ISPOWEROF2(p->flags & (MEM_Int|MEM_Real|MEM_IntReal)) );
if( p->flags & MEM_Null ){
/* Cannot be both MEM_Null and some other type */
@ -93,17 +98,17 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
#endif
/*
** Render a Mem object which is either MEM_Int or MEM_Real into a
** buffer.
** Render a Mem object which is one of MEM_Int, MEM_Real, or MEM_IntReal
** into a buffer.
*/
static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
StrAccum acc;
assert( p->flags & (MEM_Int|MEM_Real) );
assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) );
sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
if( p->flags & MEM_IntReal ){
sqlite3_str_appendf(&acc, "%!.15g", (double)p->u.i);
}else if( p->flags & MEM_Int ){
if( p->flags & MEM_Int ){
sqlite3_str_appendf(&acc, "%lld", p->u.i);
}else if( p->flags & MEM_IntReal ){
sqlite3_str_appendf(&acc, "%!.15g", (double)p->u.i);
}else{
sqlite3_str_appendf(&acc, "%!.15g", p->u.r);
}
@ -136,7 +141,7 @@ int sqlite3VdbeMemConsistentDualRep(Mem *p){
char *z;
int i, j, incr;
if( (p->flags & MEM_Str)==0 ) return 1;
if( (p->flags & (MEM_Int|MEM_Real))==0 ) return 1;
if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1;
vdbeMemRenderNum(sizeof(zBuf), zBuf, p);
z = p->z;
i = j = 0;
@ -249,8 +254,8 @@ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
**
** Any prior string or blob content in the pMem object may be discarded.
** The pMem->xDel destructor is called, if it exists. Though MEM_Str
** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null
** values are preserved.
** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, MEM_IntReal,
** and MEM_Null values are preserved.
**
** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM)
** if unable to complete the resizing.
@ -354,8 +359,8 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){
** are converted using sqlite3_snprintf(). Converting a BLOB to a string
** is a no-op.
**
** Existing representations MEM_Int and MEM_Real are invalidated if
** bForce is true but are retained if bForce is false.
** Existing representations MEM_Int, MEM_Real, or MEM_IntReal are invalidated
** if bForce is true but are retained if bForce is false.
**
** A MEM_Null value will never be passed to this function. This function is
** used for converting values to text for returning to the user (i.e. via
@ -369,7 +374,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( !(pMem->flags&MEM_Zero) );
assert( !(pMem->flags&(MEM_Str|MEM_Blob)) );
assert( pMem->flags&(MEM_Int|MEM_Real) );
assert( pMem->flags&(MEM_Int|MEM_Real|MEM_IntReal) );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
@ -558,7 +563,7 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
flags = pMem->flags;
if( flags & MEM_Int ){
if( flags & (MEM_Int|MEM_IntReal) ){
return pMem->u.i;
}else if( flags & MEM_Real ){
return doubleToInt64(pMem->u.r);
@ -587,7 +592,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
if( pMem->flags & MEM_Real ){
return pMem->u.r;
}else if( pMem->flags & MEM_Int ){
}else if( pMem->flags & (MEM_Int|MEM_IntReal) ){
return (double)pMem->u.i;
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
return memRealValue(pMem);
@ -602,7 +607,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
** Return the value ifNull if pMem is NULL.
*/
int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){
if( pMem->flags & MEM_Int ) return pMem->u.i!=0;
if( pMem->flags & (MEM_Int|MEM_IntReal) ) return pMem->u.i!=0;
if( pMem->flags & MEM_Null ) return ifNull;
return sqlite3VdbeRealValue(pMem)!=0.0;
}
@ -675,7 +680,7 @@ static int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){
}
/*
** Convert pMem so that it has types MEM_Real or MEM_Int or both.
** Convert pMem so that it has type MEM_Real or MEM_Int.
** Invalidate any prior representations.
**
** Every effort is made to force the conversion, even if the input
@ -683,7 +688,7 @@ static int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){
** as much of the string as we can and ignore the rest.
*/
int sqlite3VdbeMemNumerify(Mem *pMem){
if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
if( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))==0 ){
int rc;
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
@ -701,7 +706,7 @@ int sqlite3VdbeMemNumerify(Mem *pMem){
}
}
}
assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))!=0 );
pMem->flags &= ~(MEM_Str|MEM_Blob|MEM_Zero);
return SQLITE_OK;
}
@ -928,7 +933,7 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
** dual type, are allowed, as long as the underlying value is the
** same. */
u16 mFlags = pMem->flags & pX->flags & pX->mScopyFlags;
assert( (mFlags&MEM_Int)==0 || pMem->u.i==pX->u.i );
assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i );
assert( (mFlags&MEM_Real)==0 || pMem->u.r==pX->u.r );
assert( (mFlags&MEM_Str)==0 || (pMem->n==pX->n && pMem->z==pX->z) );
assert( (mFlags&MEM_Blob)==0 || sqlite3BlobCompare(pMem,pX)==0 );
@ -1491,7 +1496,7 @@ static int valueFromExpr(
}else{
sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8);
}
if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str;
if( pVal->flags & (MEM_Int|MEM_IntReal|MEM_Real) ) pVal->flags &= ~MEM_Str;
if( enc!=SQLITE_UTF8 ){
rc = sqlite3VdbeChangeEncoding(pVal, enc);
}

View File

@ -130,7 +130,7 @@ char *sqlite3VdbeExpandSql(
pVar = &p->aVar[idx-1];
if( pVar->flags & MEM_Null ){
sqlite3_str_append(&out, "NULL", 4);
}else if( pVar->flags & MEM_Int ){
}else if( pVar->flags & (MEM_Int|MEM_IntReal) ){
sqlite3_str_appendf(&out, "%lld", pVar->u.i);
}else if( pVar->flags & MEM_Real ){
sqlite3_str_appendf(&out, "%!.15g", pVar->u.r);