]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the SQLITE_ENABLE_NAN_INF compile-time option which makes the following
authordrh <>
Wed, 22 Mar 2023 20:21:49 +0000 (20:21 +0000)
committerdrh <>
Wed, 22 Mar 2023 20:21:49 +0000 (20:21 +0000)
behavior changes:  (1)  sqlite3_value_double(NULL) returns NaN,  (2) SQLite
preserves NaN values rather than converting them to NULL.  (3) CAST statements
understand "NaN" and "Inf" and make the right conversions.  (4) Non-standard
JSON is never generated by SQLite JSON routines, but those routines will
accept floating point literals "NaN", "Inf", and "-Inf".

FossilOrigin-Name: 96ec8306457eebf5ce955402d7b8b88aa7d73803e22144cc6a22da0048741016

manifest
manifest.uuid
src/expr.c
src/func.c
src/json.c
src/sqliteInt.h
src/util.c
src/vdbe.c
src/vdbeaux.c
src/vdbemem.c

index 8d94a9b1dac7cd6831f62584d053fdd349cc5a08..e2082d2a3316a02b3e728e3952571fd6951cbfbb 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C The\sfloating-point-to-text\sconversion\swith\sthe\szero-padding\soption\snow\nrenders\sNaN\sas\s"null".
-D 2023-03-22T16:55:35.088
+C Add\sthe\sSQLITE_ENABLE_NAN_INF\scompile-time\soption\swhich\smakes\sthe\sfollowing\nbehavior\schanges:\s\s(1)\s\ssqlite3_value_double(NULL)\sreturns\sNaN,\s\s(2)\sSQLite\npreserves\sNaN\svalues\srather\sthan\sconverting\sthem\sto\sNULL.\s\s(3)\sCAST\sstatements\nunderstand\s"NaN"\sand\s"Inf"\sand\smake\sthe\sright\sconversions.\s\s(4)\sNon-standard\nJSON\sis\snever\sgenerated\sby\sSQLite\sJSON\sroutines,\sbut\sthose\sroutines\swill\naccept\sfloating\spoint\sliterals\s"NaN",\s"Inf",\sand\s"-Inf".
+D 2023-03-22T20:21:49.165
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -575,17 +575,17 @@ F src/date.c f21815ca7172ce073db3163ac54c8d9f2841077165c1a6123b4d1c376a0c7ec7
 F src/dbpage.c d47549716549311f79dc39fe5c8fb19390a6eb2c960f8e37c89a9c4de0c1052e
 F src/dbstat.c ec92074baa61d883de58c945162d9e666c13cd7cf3a23bc38b4d1c4d0b2c2bef
 F src/delete.c 201fe0763c52783d205c8c13cdd9d55c1bd5cb21c1f036753f99103b43284b90
-F src/expr.c e02117f1d698d781dc5990364bec01ef19688f084e14b5ea468a972c3b26903b
+F src/expr.c f4a6c233ce86d359905afd78a1ef436bfe44160b6c71ae74b2239a9cfeca7734
 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
 F src/fkey.c 722f20779f5342a787922deded3628d8c74b5249cab04098cf17ee2f2aaff002
-F src/func.c d187be57a886ddf4e6b7ef584a494361899be3df5eee6d4a747b68ff4aff4122
+F src/func.c 858f7a1ce2ae27f22564e7336b7f06206c262577c22a8720be45690828a4fe4f
 F src/global.c 428d2580a1cdf5dbe1f356d1feab83710ae0cc862ece0fb57bc8259e43838c74
 F src/hash.c c6af5f96a7a76d000f07c5402c48c318c2566beecdee9e78b9d9f60ce7119565
 F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
 F src/hwtime.h b638809e083b601b618df877b2e89cb87c2a47a01f4def10be4c4ebb54664ac7
 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
 F src/insert.c 7940fce7d4aa855606432d82d20694e17c18a03956f5f5776f2404e2df7c18a8
-F src/json.c 9e3a6acf9e4fa8bb6c84a38538ed9c2f9ad09f106910ef0e9cc68e19c8dc4fc8
+F src/json.c 29375e70f76339679dbe03a7d71e32186a789ac33b2a2c7285aa9852279b7e67
 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
 F src/loadext.c b04eb648cedc45efe4298e1ef439ac4f0096ae27b5f01accb0a1f49d57789128
 F src/main.c 09bc5191f75dc48fc4dfddda143cb864c0c3dbc3297eb9a9c8e01fea58ff847d
@@ -630,7 +630,7 @@ F src/shell.c.in e92846a40dae4acd20ae6073846d8a54ba7fc84c8299af3b8d63be19491c5ad
 F src/sqlite.h.in f01033703156615566bb329144d736a37fc35a278049db91127782a9c799b938
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4
-F src/sqliteInt.h ee87a8982f59897ea0594df986bb3ebbe971b16fa0248c9c4940ae18beda7deb
+F src/sqliteInt.h 33d4aff63f8768a8b55456640cc3f24a9cd12907b2496db2f68bd22036744f2e
 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -693,15 +693,15 @@ F src/trigger.c f34367fad4df451b5dfe63fcc1d384fd16e40077e42092b1c3682dedeef5a7e3
 F src/update.c 76664e1beae86e8e961983ebe19a4ee9ebd7e26683ead2b288ba08f81fc7ba4e
 F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
-F src/util.c 3ff7bc2b48dd425b1448304bb86273b05da1621f136d51dbb9789f8803559a1f
+F src/util.c be2f2ba283ecfcd39a92c26a4f27ba39d295da35ad29ef551998c174818545ef
 F src/vacuum.c 84ce7f01f8a7a08748e107a441db83bcec13970190ddcb0c9ff522adbc1c23fd
-F src/vdbe.c 0cf4c72a9e0eb614afc19c9c4ca9c8a919c97c0866934a70dac7c2f689a4edf8
+F src/vdbe.c 1838a91623c34719bf50a161bb73af4b437a2c4293168acaaafa444618de1fc5
 F src/vdbe.h 73b904a6b3bb27f308c6cc287a5751ebc7f1f89456be0ed068a12b92844c6e8c
 F src/vdbeInt.h a4147a4ddf613cb1bcb555ace9e9e74a9c099d65facd88155f191b1fb4d74cfb
 F src/vdbeapi.c 40c47b1528d308a322203de21d2e0d711753257ed9771771b6129214b1d65932
-F src/vdbeaux.c 0f5201346a83a35a08e833c3a03abe626119c07b7361c28bc6a259b98540f1d6
+F src/vdbeaux.c 7c8ea5a1ba0602332a1e335f95779c1a8d69421fdbc55a634c667bfadbb5d2e1
 F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd
-F src/vdbemem.c 0388576b7cf0be13ce14b9e3b8aa90b8a1b923b60321d0242131ae0b5732b43b
+F src/vdbemem.c a021df401b4de72e218c7fbe700c72a3360e24ec8faf7815db5e9d5bc6471ab7
 F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35
 F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
 F src/vdbevtab.c aae4bd769410eb7e1d02c42613eec961d514459b1c3c1c63cfc84e92a137daac
@@ -2051,8 +2051,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P abee339d5eae8b63d9579b7ec3a25f18071e675223e0bb5294c733fb618a3a26
-R cb06c74e184cc2909674761792344766
+P ad59fa17663bda54ec5d4e48ac24e04b87daa70c795d840cd8db382e2dd581b9
+R fb79ed5683a512ac22052bbe024dd798
+T *branch * nan-inf
+T *sym-nan-inf *
+T -sym-trunk *
 U drh
-Z a8c6d294d393530f190c714127c209f2
+Z b4a65856caa12f9fd796f5366ea8bd6b
 # Remove this line to create a well-formed Fossil manifest.
index 2b896cefb04cb18f4fda99c80ad6860523aa9262..87aa6f584158751b62df9b10218e75cd353af73a 100644 (file)
@@ -1 +1 @@
-ad59fa17663bda54ec5d4e48ac24e04b87daa70c795d840cd8db382e2dd581b9
\ No newline at end of file
+96ec8306457eebf5ce955402d7b8b88aa7d73803e22144cc6a22da0048741016
\ No newline at end of file
index 0a52e62309714de2e6407667e10d5ed1b120d3de..9e71d14b7bb0e6049816b57cc910fb3107cd1da0 100644 (file)
@@ -3754,7 +3754,10 @@ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
   if( ALWAYS(z!=0) ){
     double value;
     sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
-    assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */
+#ifndef SQLITE_ENABLE_NAN_INF
+    assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN unless
+                                    ** SQLITE_ENABLE_NAN_INF is on */
+#endif
     if( negateFlag ) value = -value;
     sqlite3VdbeAddOp4Dup8(v, OP_Real, 0, iMem, 0, (u8*)&value, P4_REAL);
   }
index 045c60613bb4238cf7cfe7436a90016e6ec99159..395fc5d222077026b4059e9983a8373a4c90036b 100644 (file)
@@ -16,9 +16,6 @@
 #include "sqliteInt.h"
 #include <stdlib.h>
 #include <assert.h>
-#ifndef SQLITE_OMIT_FLOATING_POINT
-#include <math.h>
-#endif
 #include "vdbeInt.h"
 
 /*
index 9783a3898a317f5ad8cc792979380567cc944688..c9c0166907ec1995ebae3a737e839463a608ec91 100644 (file)
@@ -902,6 +902,19 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
         if( c<'0' || c>'9' ) return -1;
         continue;
       }
+#ifdef SQLITE_ENABLE_NAN_INF
+      /* Non-standard JSON:  Allow "-Inf" (in any case)
+      ** to be understood as floating point literals. */
+      if( (c=='i' || c=='I')
+       && j==i+1
+       && z[i]=='-'
+       && sqlite3StrNICmp(&z[j], "inf",3)==0
+       && !sqlite3Isalnum(z[j+4])
+      ){
+        jsonParseAddNode(pParse, JSON_REAL, 4, &z[i]);
+        return i+4;
+      }
+#endif
       break;
     }
     if( z[j-1]<'0' ) return -1;
@@ -914,6 +927,20 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
     return -3;  /* End of [...] */
   }else if( c==0 ){
     return 0;   /* End of file */
+#ifdef SQLITE_ENABLE_NAN_INF
+  /* Non-standard JSON:  Allow "NaN" and "Inf" (in any case)
+  ** to be understood as floating point literals. */
+  }else if( (c=='n' || c=='N')
+         && sqlite3StrNICmp(z+i,"nan",3)==0
+         && !sqlite3Isalnum(z[i+3]) ){
+    jsonParseAddNode(pParse, JSON_REAL, 3, &z[i]);
+    return i+3;
+  }else if( (c=='i' || c=='I')
+         && sqlite3StrNICmp(z+i,"inf",3)==0
+         && !sqlite3Isalnum(z[i+3]) ){
+    jsonParseAddNode(pParse, JSON_REAL, 3, &z[i]);
+    return i+3;
+#endif /* SQLITE_ENABLE_NAN_INF */
   }else{
     return -1;  /* Syntax error */
   }
index 8cb0198a29cc212c7284a416c8acdfcf7b17e471..f524aac4e8adbe1cd033f903a7ad5f1585367ea4 100644 (file)
 #ifdef HAVE_INTTYPES_H
 #include <inttypes.h>
 #endif
+#ifndef SQLITE_OMIT_FLOATING_POINT
+#include <math.h>
+#endif
 
 /*
 ** The following macros are used to cast pointers to integers and
index 632d317e317cf154577276e408ec2b9147005c7c..045469a7e294281f95f7f4a36b9e4d682a396eae 100644 (file)
@@ -425,6 +425,34 @@ static LONGDOUBLE_TYPE sqlite3Pow10(int E){
 #endif
 }
 
+#ifdef SQLITE_ENABLE_NAN_INF
+/* If the input string z[] is one of the special values
+** "inf" or "NaN" (in any case) then set pResult to that
+** value and return true.  Otherwise return false.
+*/
+static int translateInfNan(
+  const char *z,
+  int incr,
+  double *pResult
+){
+  if( (z[0]=='i'      || z[0]=='I')
+   && (z[incr]=='n'   || z[incr]=='N')
+   && (z[2*incr]=='f' || z[2*incr]=='f')
+  ){
+    *pResult = INFINITY;
+    return 1;
+  }
+  if( (z[0]=='n'      || z[0]=='N')
+   && (z[incr]=='a'   || z[incr]=='A')
+   && (z[2*incr]=='n' || z[2*incr]=='N')
+  ){
+    *pResult = NAN;
+    return 1;
+  }
+  return 0;
+}
+#endif /* SQLITE_ENABLE_NAN_INF */
+
 /*
 ** The string z[] is an text representation of a real number.
 ** Convert this string to a double and write it into *pResult.
@@ -640,6 +668,11 @@ do_atof_calc:
     return eType;
   }else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){
     return -1;
+#ifdef SQLITE_ENABLE_NAN_INF
+  }else if( (zEnd-z)==3*incr && translateInfNan(z,incr,&result) ){
+    *pResult = sign ? +result : -result;
+    return 2;
+#endif
   }else{
     return 0;
   }
index dfe8070de1c66e1821a1764afee7aa9568a18c89..2406a614d8a735c0d9bdf6f69c200a362ce2cf8f 100644 (file)
@@ -1250,7 +1250,9 @@ case OP_Int64: {           /* out2 */
 case OP_Real: {            /* same as TK_FLOAT, out2 */
   pOut = out2Prerelease(p, pOp);
   pOut->flags = MEM_Real;
+#ifndef SQLITE_ENABLE_NAN_INF
   assert( !sqlite3IsNaN(*pOp->p4.pReal) );
+#endif
   pOut->u.r = *pOp->p4.pReal;
   break;
 }
@@ -1811,9 +1813,11 @@ fp_math:
     pOut->u.i = rB;
     MemSetTypeFlag(pOut, MEM_Int);
 #else
+#ifndef SQLITE_ENABLE_NAN_INF
     if( sqlite3IsNaN(rB) ){
       goto arithmetic_result_is_null;
     }
+#endif
     pOut->u.r = rB;
     MemSetTypeFlag(pOut, MEM_Real);
 #endif
index 87fd067322d483a9bd39682c59481bf2cd0224e1..7b87db478b1eced425132bba145246f3be19a05f 100644 (file)
@@ -3990,7 +3990,11 @@ static void serialGet(
     assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 );
     swapMixedEndianFloat(x);
     memcpy(&pMem->u.r, &x, sizeof(x));
+#ifdef SQLITE_ENABLE_NAN_INF
+    pMem->flags = MEM_Real;
+#else
     pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real;
+#endif
   }
 }
 void sqlite3VdbeSerialGet(
index be52062d5511a3b95f481ba131a8628195f7ad72..171dc0dde62840dc240af63994c4fa9fc30475fa 100644 (file)
@@ -662,8 +662,11 @@ double sqlite3VdbeRealValue(Mem *pMem){
   }else if( pMem->flags & (MEM_Str|MEM_Blob) ){
     return memRealValue(pMem);
   }else{
-    /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
+#ifdef SQLITE_NULL_TO_NAN
+    return NAN;
+#else
     return (double)0;
+#endif
   }
 }
 
@@ -964,10 +967,12 @@ void sqlite3VdbeMemSetPointer(
 */
 void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
   sqlite3VdbeMemSetNull(pMem);
-  if( !sqlite3IsNaN(val) ){
-    pMem->u.r = val;
-    pMem->flags = MEM_Real;
-  }
+#ifndef SQLITE_ENABLE_SPECIAL_FP_VALUES
+  /* When SQLITE_ENABLE_SPECIAL_FP_VALUES is omitted, NaN converts to NULL */
+  if( sqlite3IsNaN(val) ) return;
+#endif
+  pMem->u.r = val;
+  pMem->flags = MEM_Real;
 }
 #endif