From: drh Date: Sun, 11 May 2008 11:07:06 +0000 (+0000) Subject: New test cases to verify that SQLite handles bound NaN, +Inf, and -Inf X-Git-Tag: version-3.6.10~1061 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a06f17fe2e432db1c0782055a0febd837880ca88;p=thirdparty%2Fsqlite.git New test cases to verify that SQLite handles bound NaN, +Inf, and -Inf floating point values correctly. Improvements to the text->real conversion routine so that it generates +Inf and -Inf at appropriate times. Tickets #3101 and #3060. (CVS 5116) FossilOrigin-Name: 3ff2f1cdc9c57bca56de6cdc0ad5edc95b0606a0 --- diff --git a/manifest b/manifest index 17ec265670..6bdf0b67df 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sleaked\sfilename\sin\scase\sDosOpen()\sfails.\s(CVS\s5115) -D 2008-05-09T19:38:24 +C New\stest\scases\sto\sverify\sthat\sSQLite\shandles\sbound\sNaN,\s+Inf,\sand\s-Inf\nfloating\spoint\svalues\scorrectly.\s\sImprovements\sto\sthe\stext->real\sconversion\nroutine\sso\sthat\sit\sgenerates\s+Inf\sand\s-Inf\sat\sappropriate\stimes.\nTickets\s#3101\sand\s#3060.\s(CVS\s5116) +D 2008-05-11T11:07:07 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 8b9b8263852f0217157f9042b8e3dae7427ec739 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -130,13 +130,13 @@ F src/printf.c 77c192ccc81117d68b21b449cd33396357aa266d F src/random.c 2b2db2de4ab491f5a14d3480466f8f4b5a5db74a F src/select.c da43ce3080112aa77863e9c570c1df19a892acb8 F src/shell.c 668ad976716982eb658019eda489b6f55131dbe7 -F src/sqlite.h.in abb785d2afcf45bb9344fe6edc1c7b428e1b719f +F src/sqlite.h.in bf986db272eebf11be5c2d49b187a0f9562e2ee4 F src/sqlite3ext.h faacd0e6a81aabee0861c6d7883c9172e74ef5b3 F src/sqliteInt.h c38fad42820bd3a68cdb185edbea9aff8bf5c18b F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/table.c 46ccf9b7892a86f57420ae7bac69ecd5e72d26b5 F src/tclsqlite.c c57e740e30bd6dda678796eed62c7f0e64689834 -F src/test1.c 09062b31b89e3a74dd0a33d2af729b47678976f2 +F src/test1.c 86b31ca06489ed08687e460bf155c6b17958f83a F src/test2.c f0808cc643528b9620e4059ca9bda8346f526121 F src/test3.c f5328839e29631ed9eef8674994ad7341b2de59b F src/test4.c c2c0f5dc907f1346f5d4b65eb5799f11eb9e4071 @@ -165,7 +165,7 @@ F src/tokenize.c 8d77af8584cf027dc21375f0efa5818cb303c995 F src/trigger.c 9bd3b6fa0beff4a02d262c96466f752ec15a7fc3 F src/update.c 2d7143b9014e955509cc4f323f9a9584fb898f34 F src/utf.c 8c94fa10efc78c2568d08d436acc59df4df7191b -F src/util.c 99e0f11500f5a11f4ec7c60b52f34bd0ff622cea +F src/util.c 4f0125fa1ba77be12e30e1b234352fc1b5abfe00 F src/vacuum.c c3b2b70677f874102b8753bf494c232e777f3998 F src/vdbe.c 56c11eb1493296ef6da5bbc049e77b795824bdc7 F src/vdbe.h f4bb70962d9c13e0f65b215c90e8acea1ae6e8ee @@ -398,7 +398,7 @@ F test/misc5.test 0b68dcb630d44af2dbcdca94dd2b17c8d580f6fa F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc7.test 26e0d948a413bca61ed031159907a03d64647409 F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33 -F test/nan.test c2a4562a3cbd5c78eb0592e08495bfdef077a76e +F test/nan.test 14c41572ff52dbc740b1c3303dd313a90dc6084c F test/notnull.test 44d600f916b770def8b095a9962dbe3be5a70d82 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/onefile.test 5af2867a8097cea08f15de5382b8d57d1219d8e3 @@ -634,7 +634,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P bf45a3ab7a295dcc399bdcf27965f1684b0a33b8 -R 57da237ef91fecaf24c595d9efd8c265 -U pweilbacher -Z 0e3f04d9bb50f18e2eb4ea17dbbe751e +P ecc6c739064922937ce66339f74403a0346aeedd +R b636f115ca9e3f31cdc91f25e88091d1 +U drh +Z 25e0008b9bf09460cd85318ac588b5de diff --git a/manifest.uuid b/manifest.uuid index 2c59ffa2c8..b230cd4401 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ecc6c739064922937ce66339f74403a0346aeedd \ No newline at end of file +3ff2f1cdc9c57bca56de6cdc0ad5edc95b0606a0 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 6866c4f960..d5742eac4b 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -30,7 +30,7 @@ ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** -** @(#) $Id: sqlite.h.in,v 1.310 2008/04/27 22:48:05 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.311 2008/05/11 11:07:07 drh Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -155,7 +155,7 @@ int sqlite3_threadsafe(void); /* ** CAPI3REF: Database Connection Handle {F12000} -** KEYWORDS: {database connection} +** KEYWORDS: {database connection} {database connections} ** ** Each open SQLite database is represented by pointer to an instance of the ** opaque structure named "sqlite3". It is useful to think of an sqlite3 diff --git a/src/test1.c b/src/test1.c index cf420f0215..5eaef8a8d2 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.301 2008/05/05 11:33:48 danielk1977 Exp $ +** $Id: test1.c,v 1.302 2008/05/11 11:07:07 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -2614,6 +2614,24 @@ static int test_bind_double( int idx; double value; int rc; + const char *zVal; + int i; + static const struct { + const char *zName; /* Name of the special floating point value */ + unsigned int iUpper; /* Upper 32 bits */ + unsigned int iLower; /* Lower 32 bits */ + } aSpecialFp[] = { + { "NaN", 0x7fffffff, 0xffffffff }, + { "SNaN", 0x7ff7ffff, 0xffffffff }, + { "-NaN", 0xffffffff, 0xffffffff }, + { "-SNaN", 0xfff7ffff, 0xffffffff }, + { "+Inf", 0x7ff00000, 0x00000000 }, + { "-Inf", 0xfff00000, 0x00000000 }, + { "Epsilon", 0x00000000, 0x00000001 }, + { "-Epsilon", 0x80000000, 0x00000001 }, + { "NaN0", 0x7ff80000, 0x00000000 }, + { "-NaN0", 0xfff80000, 0x00000000 }, + }; if( objc!=4 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", @@ -2629,12 +2647,19 @@ static int test_bind_double( ** Tcl_GetDoubleFromObj() should understand "NaN" but some versions ** contain a bug. */ - if( strcmp(Tcl_GetString(objv[3]), "NaN")==0 ){ - sqlite3_int64 i; - i = 0xfff80000; - i <<= 32; - value = *(double*)(char*)&i; - }else if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ){ + zVal = Tcl_GetString(objv[3]); + for(i=0; i=sizeof(aSpecialFp)/sizeof(aSpecialFp[0]) && + Tcl_GetDoubleFromObj(interp, objv[3], &value) ){ return TCL_ERROR; } rc = sqlite3_bind_double(pStmt, idx, value); diff --git a/src/util.c b/src/util.c index 08be306620..0cd214aea2 100644 --- a/src/util.c +++ b/src/util.c @@ -14,7 +14,7 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.227 2008/05/09 13:47:59 drh Exp $ +** $Id: util.c,v 1.228 2008/05/11 11:07:07 drh Exp $ */ #include "sqliteInt.h" #include @@ -262,6 +262,7 @@ int sqlite3AtoF(const char *z, double *pResult){ int sign = 1; const char *zBegin = z; LONGDOUBLE_TYPE v1 = 0.0; + int nSignificant = 0; while( isspace(*(u8*)z) ) z++; if( *z=='-' ){ sign = -1; @@ -269,16 +270,29 @@ int sqlite3AtoF(const char *z, double *pResult){ }else if( *z=='+' ){ z++; } + while( z[0]=='0' ){ + z++; + } while( isdigit(*(u8*)z) ){ v1 = v1*10.0 + (*z - '0'); z++; + nSignificant++; } if( *z=='.' ){ LONGDOUBLE_TYPE divisor = 1.0; z++; + if( nSignificant==0 ){ + while( z[0]=='0' ){ + divisor *= 10.0; + z++; + } + } while( isdigit(*(u8*)z) ){ - v1 = v1*10.0 + (*z - '0'); - divisor *= 10.0; + if( nSignificant<18 ){ + v1 = v1*10.0 + (*z - '0'); + divisor *= 10.0; + nSignificant++; + } z++; } v1 /= divisor; diff --git a/test/nan.test b/test/nan.test index 0344811bda..d5645acbcc 100644 --- a/test/nan.test +++ b/test/nan.test @@ -14,23 +14,16 @@ # Make sure IEEE floating point NaN values are handled properly. # SQLite should always convert NaN into NULL. # -# $Id: nan.test,v 1.2 2008/05/01 18:01:47 drh Exp $ +# Also verify that the decimal to IEEE754 binary conversion routines +# correctly generate 0.0, +Inf, and -Inf as appropriate for numbers +# out of range. +# +# $Id: nan.test,v 1.3 2008/05/11 11:07:07 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl -# The ascii->float conversion routine in SQLite converts all digits -# of a number to a long long double. Then it divids by 10**N where -# N is the number of digits to the right of the decimal point. If -# both the full number and 10**N are +Inf we will get +Inf/+Inf which -# is NaN. -# -unset -nocomplain nan -set nan 9.[string repeat 9 5000] - -unset -nocomplain inf -set inf [string repeat 9 5000].0 do_test nan-1.1 { db eval { @@ -38,31 +31,59 @@ do_test nan-1.1 { PRAGMA page_size=1024; CREATE TABLE t1(x FLOAT); } - db eval "INSERT INTO t1 VALUES($nan)" + set ::STMT [sqlite3_prepare db "INSERT INTO t1 VALUES(?)" -1 TAIL] + sqlite3_bind_double $::STMT 1 NaN + sqlite3_step $::STMT + sqlite3_reset $::STMT db eval {SELECT x, typeof(x) FROM t1} } {{} null} do_test nan-1.2 { - db eval "INSERT INTO t1 VALUES($inf)" + sqlite3_bind_double $::STMT 1 +Inf + sqlite3_step $::STMT + sqlite3_reset $::STMT db eval {SELECT x, typeof(x) FROM t1} } {{} null inf real} do_test nan-1.3 { - db eval "INSERT INTO t1 VALUES(-$inf)" + sqlite3_bind_double $::STMT 1 -Inf + sqlite3_step $::STMT + sqlite3_reset $::STMT db eval {SELECT x, typeof(x) FROM t1} } {{} null inf real -inf real} do_test nan-1.4 { + sqlite3_bind_double $::STMT 1 -NaN + sqlite3_step $::STMT + sqlite3_reset $::STMT + db eval {SELECT x, typeof(x) FROM t1} +} {{} null inf real -inf real {} null} +do_test nan-1.5 { + sqlite3_bind_double $::STMT 1 NaN0 + sqlite3_step $::STMT + sqlite3_reset $::STMT + db eval {SELECT x, typeof(x) FROM t1} +} {{} null inf real -inf real {} null {} null} +do_test nan-1.5 { + sqlite3_bind_double $::STMT 1 -NaN0 + sqlite3_step $::STMT + sqlite3_reset $::STMT + db eval {SELECT x, typeof(x) FROM t1} +} {{} null inf real -inf real {} null {} null {} null} +do_test nan-1.6 { db eval { UPDATE t1 SET x=x-x; SELECT x, typeof(x) FROM t1; } -} {{} null {} null {} null} +} {{} null {} null {} null {} null {} null {} null} do_test nan-2.1 { db eval { DELETE FROM T1; } - db eval "INSERT INTO t1 VALUES('$nan')" + sqlite3_bind_double $::STMT 1 NaN + sqlite3_step $::STMT + sqlite3_reset $::STMT db eval {SELECT x, typeof(x) FROM t1} } {{} null} +sqlite3_finalize $::STMT # SQLite always converts NaN into NULL so it is not possible to write # a NaN value into the database file using SQLite. The following series @@ -92,5 +113,116 @@ do_test nan-3.3 { sqlite3 db test.db db eval {SELECT x, typeof(x) FROM t1} } {{} null} +do_test nan-3.4 { + db close + hexio_write test.db 2040 7FF8000000000000 + sqlite3 db test.db + db eval {SELECT x, typeof(x) FROM t1} +} {{} null} +do_test nan-3.5 { + db close + hexio_write test.db 2040 FFFFFFFFFFFFFFFF + sqlite3 db test.db + db eval {SELECT x, typeof(x) FROM t1} +} {{} null} +do_test nan-3.6 { + db close + hexio_write test.db 2040 7FFFFFFFFFFFFFFF + sqlite3 db test.db + db eval {SELECT x, typeof(x) FROM t1} +} {{} null} + +# Verify that the sqlite3AtoF routine is able to handle extreme +# numbers. +# +do_test nan-4.1 { + db eval {DELETE FROM t1} + db eval "INSERT INTO t1 VALUES([string repeat 9 307].0)" + db eval {SELECT x, typeof(x) FROM t1} +} {1e+307 real} +do_test nan-4.2 { + db eval {DELETE FROM t1} + db eval "INSERT INTO t1 VALUES([string repeat 9 308].0)" + db eval {SELECT x, typeof(x) FROM t1} +} {1e+308 real} +do_test nan-4.3 { + db eval {DELETE FROM t1} + db eval "INSERT INTO t1 VALUES([string repeat 9 309].0)" + db eval {SELECT x, typeof(x) FROM t1} +} {inf real} +do_test nan-4.4 { + db eval {DELETE FROM t1} + db eval "INSERT INTO t1 VALUES(-[string repeat 9 307].0)" + db eval {SELECT x, typeof(x) FROM t1} +} {-1e+307 real} +do_test nan-4.5 { + db eval {DELETE FROM t1} + db eval "INSERT INTO t1 VALUES(-[string repeat 9 308].0)" + db eval {SELECT x, typeof(x) FROM t1} +} {-1e+308 real} +do_test nan-4.6 { + db eval {DELETE FROM t1} + db eval "INSERT INTO t1 VALUES(-[string repeat 9 309].0)" + db eval {SELECT x, typeof(x) FROM t1} +} {-inf real} +do_test nan-4.7 { + db eval {DELETE FROM t1} + set big -[string repeat 0 10000][string repeat 9 308].[string repeat 0 10000] + db eval "INSERT INTO t1 VALUES($big)" + db eval {SELECT x, typeof(x) FROM t1} +} {-1e+308 real} +do_test nan-4.8 { + db eval {DELETE FROM t1} + set big [string repeat 0 10000][string repeat 9 308].[string repeat 0 10000] + db eval "INSERT INTO t1 VALUES($big)" + db eval {SELECT x, typeof(x) FROM t1} +} {1e+308 real} + + +do_test nan-4.10 { + db eval {DELETE FROM t1} + db eval "INSERT INTO t1 VALUES(1234.5[string repeat 0 10000]12345)" + db eval {SELECT x, typeof(x) FROM t1} +} {1234.5 real} +do_test nan-4.11 { + db eval {DELETE FROM t1} + db eval "INSERT INTO t1 VALUES(-1234.5[string repeat 0 10000]12345)" + db eval {SELECT x, typeof(x) FROM t1} +} {-1234.5 real} +do_test nan-4.12 { + db eval {DELETE FROM t1} + set small [string repeat 0 10000].[string repeat 0 323][string repeat 9 10000] + db eval "INSERT INTO t1 VALUES($small)" + db eval {SELECT x, typeof(x) FROM t1} +} {9.88131291682493e-324 real} +do_test nan-4.13 { + db eval {DELETE FROM t1} + set small [string repeat 0 10000].[string repeat 0 324][string repeat 9 10000] + db eval "INSERT INTO t1 VALUES($small)" + db eval {SELECT x, typeof(x) FROM t1} +} {0.0 real} +do_test nan-4.14 { + db eval {DELETE FROM t1} + set small \ + -[string repeat 0 10000].[string repeat 0 323][string repeat 9 10000] + db eval "INSERT INTO t1 VALUES($small)" + db eval {SELECT x, typeof(x) FROM t1} +} {-9.88131291682493e-324 real} +do_test nan-4.15 { + db eval {DELETE FROM t1} + set small \ + -[string repeat 0 10000].[string repeat 0 324][string repeat 9 10000] + db eval "INSERT INTO t1 VALUES($small)" + db eval {SELECT x, typeof(x) FROM t1} +} {0.0 real} + +do_test nan-4.20 { + db eval {DELETE FROM t1} + set big [string repeat 9 10000].0e-9000 + db eval "INSERT INTO t1 VALUES($big)" + db eval {SELECT x, typeof(x) FROM t1} +} {{} null} + + finish_test