From 169f077e07f312172cb0e5d6cb291b91b61d9164 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 2 May 2019 21:36:26 +0000 Subject: [PATCH 1/4] 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 --- manifest | 23 +++++++++++++---------- manifest.uuid | 2 +- src/vdbe.c | 35 +++++++++++++++++++---------------- src/vdbeapi.c | 10 +++++----- src/vdbeaux.c | 22 ++++++++++++++-------- src/vdbemem.c | 49 +++++++++++++++++++++++++++---------------------- src/vdbetrace.c | 2 +- 7 files changed, 80 insertions(+), 63 deletions(-) diff --git a/manifest b/manifest index 381e157660..57dbaf3973 100644 --- a/manifest +++ b/manifest @@ -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 diff --git a/manifest.uuid b/manifest.uuid index 6808f0b46a..10a2b8a3af 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -48889530a9de22fee536edfd1627be62396ed18d842d5fd6d91e010b4337be95 \ No newline at end of file +dba836e31cb29d339b4520acb06188a892a52e45c50aba9742966b01108e251a \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 9bc5e4ee56..fa18db38d3 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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 diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 65d4f9ae16..58dbdb5d51 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -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); } } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 822c6fe60c..e2657ad40d 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -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; } diff --git a/src/vdbemem.c b/src/vdbemem.c index 82f7f3e102..85d37513e5 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -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); } diff --git a/src/vdbetrace.c b/src/vdbetrace.c index b6d9381336..32c66af228 100644 --- a/src/vdbetrace.c +++ b/src/vdbetrace.c @@ -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); From f2566c4132bc85ec7a11bd2ce0bf012e24817cee Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 3 May 2019 17:08:16 +0000 Subject: [PATCH 2/4] Improved comments on the elements of the array constant used to implement the sqlite3_value_type() interface. FossilOrigin-Name: f73a7de7a53f6aa6517221550a9c9882893206edfd7433e80e5fc0f441db9fc4 --- manifest | 15 +++--- manifest.uuid | 2 +- src/vdbeapi.c | 128 +++++++++++++++++++++++++------------------------- 3 files changed, 71 insertions(+), 74 deletions(-) diff --git a/manifest b/manifest index 57dbaf3973..1348ae5aa5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -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 +C Improved\scomments\son\sthe\selements\sof\sthe\sarray\sconstant\sused\sto\simplement\nthe\ssqlite3_value_type()\sinterface. +D 2019-05-03T17:08:16.321 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -594,7 +594,7 @@ F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf F src/vdbe.c ddb6bb7289e017870636a60914bca64a545f70413e71c0e791513211b22f307c F src/vdbe.h 712bca562eaed1c25506b9faf9680bdc75fc42e2f4a1cd518d883fa79c7a4237 F src/vdbeInt.h 3ba14553508d66f58753952d6dd287dce4ec735de02c6440858b4891aed51c17 -F src/vdbeapi.c 76b8fcedce6d6299599580d98ce71f6d806e297c6e584d27d0356de44df3b307 +F src/vdbeapi.c e9469b4097cd9fd0fc2045e4a219a3aeda141bf074abb49b5678554e3aad744b F src/vdbeaux.c 326e049995ca75ba158bbc09ef59347fd600c8e7bb3958db9e66d575fdcc243d F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 F src/vdbemem.c e102c625dae2d5657a086b97f46ea7645cce23379fcae74737fbe00454399a81 @@ -1822,10 +1822,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 48889530a9de22fee536edfd1627be62396ed18d842d5fd6d91e010b4337be95 -R 5d33250f3b2797d2fce07efa1f0f1900 -T *branch * int-real -T *sym-int-real * -T -sym-trunk * +P dba836e31cb29d339b4520acb06188a892a52e45c50aba9742966b01108e251a +R c4499152d6b5244a86bbe08fb4d56b35 U drh -Z 3590ba61495883d222cfb9f777b00293 +Z d1772b9a78cbf53bbe71ebce94e1a991 diff --git a/manifest.uuid b/manifest.uuid index 10a2b8a3af..d4493a3776 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dba836e31cb29d339b4520acb06188a892a52e45c50aba9742966b01108e251a \ No newline at end of file +f73a7de7a53f6aa6517221550a9c9882893206edfd7433e80e5fc0f441db9fc4 \ No newline at end of file diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 58dbdb5d51..df0bf65ebb 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -234,70 +234,70 @@ const void *sqlite3_value_text16le(sqlite3_value *pVal){ */ int sqlite3_value_type(sqlite3_value* pVal){ static const u8 aType[] = { - SQLITE_BLOB, /* 0x00 */ - SQLITE_NULL, /* 0x01 */ - SQLITE_TEXT, /* 0x02 */ - SQLITE_NULL, /* 0x03 */ - SQLITE_INTEGER, /* 0x04 */ - SQLITE_NULL, /* 0x05 */ - SQLITE_INTEGER, /* 0x06 */ - SQLITE_NULL, /* 0x07 */ - SQLITE_FLOAT, /* 0x08 */ - SQLITE_NULL, /* 0x09 */ - SQLITE_FLOAT, /* 0x0a */ - SQLITE_NULL, /* 0x0b */ - SQLITE_INTEGER, /* 0x0c */ - SQLITE_NULL, /* 0x0d */ - SQLITE_INTEGER, /* 0x0e */ - SQLITE_NULL, /* 0x0f */ - SQLITE_BLOB, /* 0x10 */ - SQLITE_NULL, /* 0x11 */ - SQLITE_TEXT, /* 0x12 */ - SQLITE_NULL, /* 0x13 */ - SQLITE_INTEGER, /* 0x14 */ - SQLITE_NULL, /* 0x15 */ - SQLITE_INTEGER, /* 0x16 */ - SQLITE_NULL, /* 0x17 */ - SQLITE_FLOAT, /* 0x18 */ - SQLITE_NULL, /* 0x19 */ - SQLITE_FLOAT, /* 0x1a */ - SQLITE_NULL, /* 0x1b */ - SQLITE_INTEGER, /* 0x1c */ - SQLITE_NULL, /* 0x1d */ - SQLITE_INTEGER, /* 0x1e */ - SQLITE_NULL, /* 0x1f */ - SQLITE_FLOAT, /* 0x20 */ - SQLITE_NULL, /* 0x21 */ - SQLITE_TEXT, /* 0x22 */ - SQLITE_NULL, /* 0x23 */ - SQLITE_FLOAT, /* 0x24 */ - SQLITE_NULL, /* 0x25 */ - SQLITE_FLOAT, /* 0x26 */ - SQLITE_NULL, /* 0x27 */ - SQLITE_FLOAT, /* 0x28 */ - SQLITE_NULL, /* 0x29 */ - SQLITE_FLOAT, /* 0x2a */ - SQLITE_NULL, /* 0x2b */ - SQLITE_FLOAT, /* 0x2c */ - SQLITE_NULL, /* 0x2d */ - SQLITE_FLOAT, /* 0x2e */ - SQLITE_NULL, /* 0x2f */ - SQLITE_BLOB, /* 0x30 */ - SQLITE_NULL, /* 0x31 */ - SQLITE_TEXT, /* 0x32 */ - SQLITE_NULL, /* 0x33 */ - SQLITE_FLOAT, /* 0x34 */ - SQLITE_NULL, /* 0x35 */ - SQLITE_FLOAT, /* 0x36 */ - SQLITE_NULL, /* 0x37 */ - SQLITE_FLOAT, /* 0x38 */ - SQLITE_NULL, /* 0x39 */ - SQLITE_FLOAT, /* 0x3a */ - SQLITE_NULL, /* 0x3b */ - SQLITE_FLOAT, /* 0x3c */ - SQLITE_NULL, /* 0x3d */ - SQLITE_FLOAT, /* 0x3e */ - SQLITE_NULL, /* 0x3f */ + SQLITE_BLOB, /* 0x00 (not possible) */ + SQLITE_NULL, /* 0x01 NULL */ + SQLITE_TEXT, /* 0x02 TEXT */ + SQLITE_NULL, /* 0x03 (not possible) */ + SQLITE_INTEGER, /* 0x04 INTEGER */ + SQLITE_NULL, /* 0x05 (not possible) */ + SQLITE_INTEGER, /* 0x06 INTEGER + TEXT */ + SQLITE_NULL, /* 0x07 (not possible) */ + SQLITE_FLOAT, /* 0x08 FLOAT */ + SQLITE_NULL, /* 0x09 (not possible) */ + SQLITE_FLOAT, /* 0x0a FLOAT + TEXT */ + SQLITE_NULL, /* 0x0b (not possible) */ + SQLITE_INTEGER, /* 0x0c (not possible) */ + SQLITE_NULL, /* 0x0d (not possible) */ + SQLITE_INTEGER, /* 0x0e (not possible) */ + SQLITE_NULL, /* 0x0f (not possible) */ + SQLITE_BLOB, /* 0x10 BLOB */ + SQLITE_NULL, /* 0x11 (not possible) */ + SQLITE_TEXT, /* 0x12 (not possible) */ + SQLITE_NULL, /* 0x13 (not possible) */ + SQLITE_INTEGER, /* 0x14 INTEGER + BLOB */ + SQLITE_NULL, /* 0x15 (not possible) */ + SQLITE_INTEGER, /* 0x16 (not possible) */ + SQLITE_NULL, /* 0x17 (not possible) */ + SQLITE_FLOAT, /* 0x18 FLOAT + BLOB */ + SQLITE_NULL, /* 0x19 (not possible) */ + SQLITE_FLOAT, /* 0x1a (not possible) */ + SQLITE_NULL, /* 0x1b (not possible) */ + SQLITE_INTEGER, /* 0x1c (not possible) */ + SQLITE_NULL, /* 0x1d (not possible) */ + SQLITE_INTEGER, /* 0x1e (not possible) */ + SQLITE_NULL, /* 0x1f (not possible) */ + SQLITE_FLOAT, /* 0x20 INTREAL */ + SQLITE_NULL, /* 0x21 (not possible) */ + SQLITE_TEXT, /* 0x22 INTREAL + TEXT */ + SQLITE_NULL, /* 0x23 (not possible) */ + SQLITE_FLOAT, /* 0x24 (not possible) */ + SQLITE_NULL, /* 0x25 (not possible) */ + SQLITE_FLOAT, /* 0x26 (not possible) */ + SQLITE_NULL, /* 0x27 (not possible) */ + SQLITE_FLOAT, /* 0x28 (not possible) */ + SQLITE_NULL, /* 0x29 (not possible) */ + SQLITE_FLOAT, /* 0x2a (not possible) */ + SQLITE_NULL, /* 0x2b (not possible) */ + SQLITE_FLOAT, /* 0x2c (not possible) */ + SQLITE_NULL, /* 0x2d (not possible) */ + SQLITE_FLOAT, /* 0x2e (not possible) */ + SQLITE_NULL, /* 0x2f (not possible) */ + SQLITE_BLOB, /* 0x30 (not possible) */ + SQLITE_NULL, /* 0x31 (not possible) */ + SQLITE_TEXT, /* 0x32 (not possible) */ + SQLITE_NULL, /* 0x33 (not possible) */ + SQLITE_FLOAT, /* 0x34 (not possible) */ + SQLITE_NULL, /* 0x35 (not possible) */ + SQLITE_FLOAT, /* 0x36 (not possible) */ + SQLITE_NULL, /* 0x37 (not possible) */ + SQLITE_FLOAT, /* 0x38 (not possible) */ + SQLITE_NULL, /* 0x39 (not possible) */ + SQLITE_FLOAT, /* 0x3a (not possible) */ + SQLITE_NULL, /* 0x3b (not possible) */ + SQLITE_FLOAT, /* 0x3c (not possible) */ + SQLITE_NULL, /* 0x3d (not possible) */ + SQLITE_FLOAT, /* 0x3e (not possible) */ + SQLITE_NULL, /* 0x3f (not possible) */ }; #ifdef SQLITE_DEBUG { From 0c8f40389ea950077ec8e265b4d9cb7a15e2bc58 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 3 May 2019 21:17:28 +0000 Subject: [PATCH 3/4] Add the SQLITE_TESTCTRL_RESULT_INTREAL test-control and use it to create the intreal() SQL function in testfixture. Write a few simple tests to prove this all works. TH3 will hold most of the INTREAL tests, probably. FossilOrigin-Name: c9838731325e0ca73bd8784c10c74ae043fed7861e6de269fd90e29fa4a19955 --- manifest | 21 ++++++++++--------- manifest.uuid | 2 +- src/main.c | 16 +++++++++++++++ src/sqlite.h.in | 3 ++- src/sqliteInt.h | 3 +++ src/test1.c | 22 ++++++++++++++++++++ src/vdbeapi.c | 15 ++++++++++++++ test/intreal.test | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 test/intreal.test diff --git a/manifest b/manifest index 1348ae5aa5..315fac96c6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\scomments\son\sthe\selements\sof\sthe\sarray\sconstant\sused\sto\simplement\nthe\ssqlite3_value_type()\sinterface. -D 2019-05-03T17:08:16.321 +C Add\sthe\sSQLITE_TESTCTRL_RESULT_INTREAL\stest-control\sand\suse\sit\sto\screate\nthe\sintreal()\sSQL\sfunction\sin\stestfixture.\s\sWrite\sa\sfew\ssimple\stests\sto\nprove\sthis\sall\sworks.\s\sTH3\swill\shold\smost\sof\sthe\sINTREAL\stests,\sprobably. +D 2019-05-03T21:17:28.623 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -483,7 +483,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c fc3cf5c371f9a400144e8c2f148ab29cd3f67f7da7eaf47e6a6959f8255fd92c F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 22afc33c3a61b4fd80a60a54f1882688371e6bc64685df2696b008fce65a999c -F src/main.c 16eea1ab004331312da0538dafb497cc0ed82fd9bb2e67f7684b40bf2797b666 +F src/main.c 3c3925b0bcb4c45687fd52f54c79e98e379252e1d3393f8b7dcccfa26181b661 F src/malloc.c 0f9da2a66b230a5785af94b9672126845099b57b70a32c987d04ac28c69da990 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de @@ -521,15 +521,15 @@ F src/resolve.c 408632d9531ca8f1df8591f00530797daaa7bde3fe0d3211de4d431cbb99347e F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c b7304d2f491c11a03a7fbdf34bc218282ac54052377809d4dc3b4b1e7f4bfc93 F src/shell.c.in 567236da9ee68b1dfa363426858ee5e310976ffe422a7b7ae220c0315d7e8c53 -F src/sqlite.h.in 38390767acc1914d58930e03149595ee4710afa4e3c43ab6c3a8aea3f1a6b8cd +F src/sqlite.h.in 0605c88d98c85fbcba8bbd9716e7cc10b361e7b21cf2375171130f577388c943 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 9ecc93b8493bd20c0c07d52e2ac0ed8bab9b549c7f7955b59869597b650dd8b5 -F src/sqliteInt.h 866311ac436c0c2039fccc7ea976fbc79d40c1c2ea687161fa4ba64379b53ae6 +F src/sqliteInt.h 443270b81c96101914eadd4e649d2f8210f4bbed569a6ff5ca8facfc74e20f26 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 F src/tclsqlite.c cfe7f93daf9d8787f65e099efb67d7cdfc2c35236dec5d3f6758520bd3519424 -F src/test1.c c02d8bc27bb61d987b6f696ef62ce583272dbdd03042a241bc5ac767d3558709 +F src/test1.c f4e0be5c344587b2beac474a58018a3833208fb6bbec35d37d58b1270a7a5917 F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5 F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644 F src/test4.c 405834f6a93ec395cc4c9bb8ecebf7c3d8079e7ca16ae65e82d01afd229694bb @@ -594,7 +594,7 @@ F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf F src/vdbe.c ddb6bb7289e017870636a60914bca64a545f70413e71c0e791513211b22f307c F src/vdbe.h 712bca562eaed1c25506b9faf9680bdc75fc42e2f4a1cd518d883fa79c7a4237 F src/vdbeInt.h 3ba14553508d66f58753952d6dd287dce4ec735de02c6440858b4891aed51c17 -F src/vdbeapi.c e9469b4097cd9fd0fc2045e4a219a3aeda141bf074abb49b5678554e3aad744b +F src/vdbeapi.c 3e8a5dacbce3375a967343d2aa4816121c9b1cd32ff6fc715e2d62afa5f6c456 F src/vdbeaux.c 326e049995ca75ba158bbc09ef59347fd600c8e7bb3958db9e66d575fdcc243d F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 F src/vdbemem.c e102c625dae2d5657a086b97f46ea7645cce23379fcae74737fbe00454399a81 @@ -1057,6 +1057,7 @@ F test/intarray.test 8319986182af37c8eb4879c6bfe9cf0074e9d43b193a4c728a0efa3417c F test/interrupt.test 16ea879ec728cb76414c148c5f24afd5d1f91054 F test/interrupt2.test e4408ca770a6feafbadb0801e54a0dcd1a8d108d F test/intpkey.test ac71107a49a06492b69b82aafaf225400598d3c8 +F test/intreal.test 1d03e48c53224b69efc8cb7349f009e388c116790bfdb4d320b233d603aaba9a F test/io.test f95bca1783b01ea7761671560d023360d2dfa4cc F test/ioerr.test 470fcc78e9cd352d162baf782fe301ea807d764241f58a48fc58109c2dfcdb6b F test/ioerr2.test 2593563599e2cc6b6b4fcf5878b177bdd5d8df26 @@ -1822,7 +1823,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P dba836e31cb29d339b4520acb06188a892a52e45c50aba9742966b01108e251a -R c4499152d6b5244a86bbe08fb4d56b35 +P f73a7de7a53f6aa6517221550a9c9882893206edfd7433e80e5fc0f441db9fc4 +R 8eb9fb04cc1483ad2c0c96b5f3e94e7c U drh -Z d1772b9a78cbf53bbe71ebce94e1a991 +Z f5b7804d98a17ecda4dff9fb2344fde1 diff --git a/manifest.uuid b/manifest.uuid index d4493a3776..26b7aea845 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f73a7de7a53f6aa6517221550a9c9882893206edfd7433e80e5fc0f441db9fc4 \ No newline at end of file +c9838731325e0ca73bd8784c10c74ae043fed7861e6de269fd90e29fa4a19955 \ No newline at end of file diff --git a/src/main.c b/src/main.c index 24f7f20f39..6358457c85 100644 --- a/src/main.c +++ b/src/main.c @@ -4104,6 +4104,22 @@ int sqlite3_test_control(int op, ...){ break; } #endif /* defined(YYCOVERAGE) */ + + /* sqlite3_test_control(SQLITE_TESTCTRL_RESULT_INTREAL, sqlite3_context*); + ** + ** This test-control causes the most recent sqlite3_result_int64() value + ** to be interpreted as a MEM_IntReal instead of as an MEM_Int. Normally, + ** MEM_IntReal values only arise during an INSERT operation of integer + ** values into a REAL column, so they can be challenging to test. This + ** test-control enables us to write an intreal() SQL function that can + ** inject an intreal() value at arbitrary places in an SQL statement, + ** for testing purposes. + */ + case SQLITE_TESTCTRL_RESULT_INTREAL: { + sqlite3_context *pCtx = va_arg(ap, sqlite3_context*); + sqlite3ResultIntReal(pCtx); + break; + } } va_end(ap); #endif /* SQLITE_UNTESTABLE */ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index cf390ac372..b9c2330d46 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -7319,7 +7319,8 @@ int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_SORTER_MMAP 24 #define SQLITE_TESTCTRL_IMPOSTER 25 #define SQLITE_TESTCTRL_PARSER_COVERAGE 26 -#define SQLITE_TESTCTRL_LAST 26 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_RESULT_INTREAL 27 +#define SQLITE_TESTCTRL_LAST 27 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 00ac00274f..e6b3aeca18 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4272,6 +4272,9 @@ void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); void sqlite3ValueSetNull(sqlite3_value*); void sqlite3ValueFree(sqlite3_value*); +#ifndef SQLITE_UNTESTABLE +void sqlite3ResultIntReal(sqlite3_context*); +#endif sqlite3_value *sqlite3ValueNew(sqlite3 *); #ifndef SQLITE_OMIT_UTF16 char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); diff --git a/src/test1.c b/src/test1.c index dcbc9e613a..be31ee110b 100644 --- a/src/test1.c +++ b/src/test1.c @@ -998,6 +998,20 @@ static void nondeterministicFunction( sqlite3_result_int(context, cnt++); } +/* +** This SQL function returns the integer value of its argument as a MEM_IntReal +** value. +*/ +static void intrealFunction( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + sqlite3_int64 v = sqlite3_value_int64(argv[0]); + sqlite3_result_int64(context, v); + sqlite3_test_control(SQLITE_TESTCTRL_RESULT_INTREAL, context); +} + /* ** Usage: sqlite3_create_function DB ** @@ -1062,6 +1076,14 @@ static int SQLITE_TCLAPI test_create_function( 0, nondeterministicFunction, 0, 0); } + /* The intreal() function converts its argument to an integer and returns + ** it as a MEM_IntReal. + */ + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "intreal", 1, SQLITE_UTF8, + 0, intrealFunction, 0, 0); + } + #ifndef SQLITE_OMIT_UTF16 /* Use the sqlite3_create_function16() API here. Mainly for fun, but also ** because it is not tested anywhere else. */ diff --git a/src/vdbeapi.c b/src/vdbeapi.c index df0bf65ebb..f145d035cf 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -563,6 +563,21 @@ void sqlite3_result_error_nomem(sqlite3_context *pCtx){ sqlite3OomFault(pCtx->pOut->db); } +#ifndef SQLITE_UNTESTABLE +/* Force the INT64 value currently stored as the result to be +** a MEM_IntReal value. See the SQLITE_TESTCTRL_RESULT_INTREAL +** test-control. +*/ +void sqlite3ResultIntReal(sqlite3_context *pCtx){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + if( pCtx->pOut->flags & MEM_Int ){ + pCtx->pOut->flags &= ~MEM_Int; + pCtx->pOut->flags |= MEM_IntReal; + } +} +#endif + + /* ** This function is called after a transaction has been committed. It ** invokes callbacks registered with sqlite3_wal_hook() as required. diff --git a/test/intreal.test b/test/intreal.test new file mode 100644 index 0000000000..a99e23d430 --- /dev/null +++ b/test/intreal.test @@ -0,0 +1,52 @@ +# 2019-05-03 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# Tests to exercise the MEM_IntReal representation of Mem objects. +# +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix intreal + +sqlite3_create_function db +do_execsql_test 100 { + SELECT intreal(5); +} {5.0} +do_execsql_test 110 { + SELECT intreal(5)=5, 6=intreal(6); +} {1 1} +do_execsql_test 120 { + SELECT intreal(7)=7.0, 8.0=intreal(8); +} {1 1} +do_execsql_test 130 { + SELECT typeof(intreal(9)); +} {real} +do_execsql_test 140 { + SELECT 'a'||intreal(11)||'z'; +} {a11.0z} + +do_execsql_test 150 { + SELECT max(1.0,intreal(2),3.0), max(1,intreal(2),3); +} {3.0 3} +do_execsql_test 160 { + SELECT max(1.0,intreal(4),3.0), max(1,intreal(4),3); +} {4.0 4.0} +do_execsql_test 170 { + SELECT max(1.0,intreal(2),intreal(3),4.0), + max(1,intreal(2),intreal(3),4); +} {4.0 4} +do_execsql_test 180 { + SELECT max(1.0,intreal(5),intreal(3),4.0), + max(1,intreal(5),intreal(3),4); +} {5.0 5.0} + + + + +finish_test From 3242c69c9140d54d98b110b72055e17fd6ede5e0 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 4 May 2019 01:29:13 +0000 Subject: [PATCH 4/4] New testcase macros to ensure that MEM_IntReal is fully tested. FossilOrigin-Name: 8b8ef445ccccc148af2cda5975986af0d134352fe16283f65d0f8a91c9ffa932 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/vdbe.c | 12 ++++++++++++ src/vdbeapi.c | 2 ++ src/vdbeaux.c | 13 +++++++++++++ src/vdbemem.c | 14 +++++++++++++- 6 files changed, 50 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 315fac96c6..4e83d71d95 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sSQLITE_TESTCTRL_RESULT_INTREAL\stest-control\sand\suse\sit\sto\screate\nthe\sintreal()\sSQL\sfunction\sin\stestfixture.\s\sWrite\sa\sfew\ssimple\stests\sto\nprove\sthis\sall\sworks.\s\sTH3\swill\shold\smost\sof\sthe\sINTREAL\stests,\sprobably. -D 2019-05-03T21:17:28.623 +C New\stestcase\smacros\sto\sensure\sthat\sMEM_IntReal\sis\sfully\stested. +D 2019-05-04T01:29:13.397 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -591,13 +591,13 @@ F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507 F src/util.c 5061987401c2e8003177fa30d73196aa036727c8f04bf36a2df0c82b1904a236 F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf -F src/vdbe.c ddb6bb7289e017870636a60914bca64a545f70413e71c0e791513211b22f307c +F src/vdbe.c b0c87760d0e2460a48aa7ff70d9e96fb845cd9af02cf7d7a66de4e2ac39a72bc F src/vdbe.h 712bca562eaed1c25506b9faf9680bdc75fc42e2f4a1cd518d883fa79c7a4237 F src/vdbeInt.h 3ba14553508d66f58753952d6dd287dce4ec735de02c6440858b4891aed51c17 -F src/vdbeapi.c 3e8a5dacbce3375a967343d2aa4816121c9b1cd32ff6fc715e2d62afa5f6c456 -F src/vdbeaux.c 326e049995ca75ba158bbc09ef59347fd600c8e7bb3958db9e66d575fdcc243d +F src/vdbeapi.c f9161e5c77f512fbb80091ce8af621d19c9556bda5e734cffaac1198407400da +F src/vdbeaux.c 94f5bea5db40f6c26a2db320788745a3852202a2ab4472928247955619027906 F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 -F src/vdbemem.c e102c625dae2d5657a086b97f46ea7645cce23379fcae74737fbe00454399a81 +F src/vdbemem.c 81dc93a8b6a02b874920bc20be7d529cfce84229ecbd53a7cd3170a0fa115440 F src/vdbesort.c 66592d478dbb46f19aed0b42222325eadb84deb40a90eebe25c6e7c1d8468f47 F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0 F src/vtab.c 1fa256c6ddad7a81e2a4dc080d015d4b0a7135767717d311298e47f6fca64bb3 @@ -1823,7 +1823,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f73a7de7a53f6aa6517221550a9c9882893206edfd7433e80e5fc0f441db9fc4 -R 8eb9fb04cc1483ad2c0c96b5f3e94e7c +P c9838731325e0ca73bd8784c10c74ae043fed7861e6de269fd90e29fa4a19955 +R 90de5cd79636b0a1b576e1c339f26a72 U drh -Z f5b7804d98a17ecda4dff9fb2344fde1 +Z bb3da40e826b6604a073d2d31bc7ecda diff --git a/manifest.uuid b/manifest.uuid index 26b7aea845..389d168cc0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c9838731325e0ca73bd8784c10c74ae043fed7861e6de269fd90e29fa4a19955 \ No newline at end of file +8b8ef445ccccc148af2cda5975986af0d134352fe16283f65d0f8a91c9ffa932 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index fa18db38d3..7242b3b1bc 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -353,6 +353,9 @@ static void applyAffinity( ** CPU cycles. */ if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/ if( (pRec->flags&(MEM_Real|MEM_Int|MEM_IntReal)) ){ + testcase( pRec->flags & MEM_Int ); + testcase( pRec->flags & MEM_Real ); + testcase( pRec->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pRec, enc, 1); } } @@ -416,9 +419,14 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ */ static u16 numericType(Mem *pMem){ if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal) ){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_Real ); + testcase( pMem->flags & MEM_IntReal ); return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal); } if( pMem->flags & (MEM_Str|MEM_Blob) ){ + testcase( pMem->flags & MEM_Str ); + testcase( pMem->flags & MEM_Blob ); return computeNumericType(pMem); } return 0; @@ -1802,6 +1810,8 @@ case OP_MustBeInt: { /* jump, in1 */ case OP_RealAffinity: { /* in1 */ pIn1 = &aMem[pOp->p1]; if( pIn1->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pIn1->flags & MEM_Int ); + testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemRealify(pIn1); } break; @@ -4382,6 +4392,8 @@ case OP_SeekRowid: { /* jump, in3 */ u64 iKey; pIn3 = &aMem[pOp->p3]; + testcase( pIn3->flags & MEM_Int ); + testcase( pIn3->flags & MEM_IntReal ); 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 diff --git a/src/vdbeapi.c b/src/vdbeapi.c index f145d035cf..83221d9724 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1865,6 +1865,8 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ *ppValue = (sqlite3_value *)columnNullValue(); }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ if( pMem->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_IntReal ); sqlite3VdbeMemRealify(pMem); } } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index e2657ad40d..ddeeeecf20 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3437,6 +3437,8 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ # define MAX_6BYTE ((((i64)0x00008000)<<32)-1) i64 i = pMem->u.i; u64 u; + testcase( flags & MEM_Int ); + testcase( flags & MEM_IntReal ); if( i<0 ){ u = ~i; }else{ @@ -4112,7 +4114,12 @@ 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|MEM_IntReal) ){ + testcase( combined_flags & MEM_Int ); + testcase( combined_flags & MEM_Real ); + testcase( combined_flags & MEM_IntReal ); if( (f1 & f2 & (MEM_Int|MEM_IntReal))!=0 ){ + testcase( f1 & f2 & MEM_Int ); + testcase( f1 & f2 & MEM_IntReal ); if( pMem1->u.i < pMem2->u.i ) return -1; if( pMem1->u.i > pMem2->u.i ) return +1; return 0; @@ -4123,6 +4130,8 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ return 0; } if( (f1&(MEM_Int|MEM_IntReal))!=0 ){ + testcase( f1 & MEM_Int ); + testcase( f1 & MEM_IntReal ); if( (f2&MEM_Real)!=0 ){ return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r); }else if( (f2&(MEM_Int|MEM_IntReal))!=0 ){ @@ -4135,6 +4144,8 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ } if( (f1&MEM_Real)!=0 ){ if( (f2&(MEM_Int|MEM_IntReal))!=0 ){ + testcase( f2 & MEM_Int ); + testcase( f2 & MEM_IntReal ); return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r); }else{ return -1; @@ -4284,6 +4295,8 @@ int sqlite3VdbeRecordCompareWithSkip( /* RHS is an integer */ if( pRhs->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pRhs->flags & MEM_Int ); + testcase( pRhs->flags & MEM_IntReal ); serial_type = aKey1[idx1]; testcase( serial_type==12 ); if( serial_type>=10 ){ diff --git a/src/vdbemem.c b/src/vdbemem.c index 85d37513e5..d1e6ac4d77 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -564,6 +564,7 @@ i64 sqlite3VdbeIntValue(Mem *pMem){ assert( EIGHT_BYTE_ALIGNMENT(pMem) ); flags = pMem->flags; if( flags & (MEM_Int|MEM_IntReal) ){ + testcase( flags & MEM_IntReal ); return pMem->u.i; }else if( flags & MEM_Real ){ return doubleToInt64(pMem->u.r); @@ -593,6 +594,7 @@ double sqlite3VdbeRealValue(Mem *pMem){ if( pMem->flags & MEM_Real ){ return pMem->u.r; }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pMem->flags & MEM_IntReal ); return (double)pMem->u.i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ return memRealValue(pMem); @@ -607,6 +609,7 @@ double sqlite3VdbeRealValue(Mem *pMem){ ** Return the value ifNull if pMem is NULL. */ int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){ + testcase( pMem->flags & MEM_IntReal ); if( pMem->flags & (MEM_Int|MEM_IntReal) ) return pMem->u.i!=0; if( pMem->flags & MEM_Null ) return ifNull; return sqlite3VdbeRealValue(pMem)!=0.0; @@ -688,6 +691,10 @@ static int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){ ** as much of the string as we can and ignore the rest. */ int sqlite3VdbeMemNumerify(Mem *pMem){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_Real ); + testcase( pMem->flags & MEM_IntReal ); + testcase( pMem->flags & MEM_Null ); if( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))==0 ){ int rc; assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); @@ -1496,7 +1503,12 @@ static int valueFromExpr( }else{ sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); } - if( pVal->flags & (MEM_Int|MEM_IntReal|MEM_Real) ) pVal->flags &= ~MEM_Str; + assert( (pVal->flags & MEM_IntReal)==0 ); + if( pVal->flags & (MEM_Int|MEM_IntReal|MEM_Real) ){ + testcase( pVal->flags & MEM_Int ); + testcase( pVal->flags & MEM_Real ); + pVal->flags &= ~MEM_Str; + } if( enc!=SQLITE_UTF8 ){ rc = sqlite3VdbeChangeEncoding(pVal, enc); }