Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | 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) |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
3ff2f1cdc9c57bca56de6cdc0ad5edc9 |
User & Date: | drh 2008-05-11 11:07:07 |
Context
2008-05-11
| ||
17:22 | Use memcpy() instead of casting to copy the content of a long long int into a double. Ticket #3101. (CVS 5117) check-in: 88e12cac user: drh tags: trunk | |
11:07 | 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) check-in: 3ff2f1cd user: drh tags: trunk | |
2008-05-09
| ||
19:38 | Fix leaked filename in case DosOpen() fails. (CVS 5115) check-in: ecc6c739 user: pweilbacher tags: trunk | |
Changes
Changes to src/sqlite.h.in.
26 26 ** on how SQLite interfaces are suppose to operate. 27 27 ** 28 28 ** The name of this file under configuration management is "sqlite.h.in". 29 29 ** The makefile makes some minor changes to this file (such as inserting 30 30 ** the version number) and changes its name to "sqlite3.h" as 31 31 ** part of the build process. 32 32 ** 33 -** @(#) $Id: sqlite.h.in,v 1.310 2008/04/27 22:48:05 drh Exp $ 33 +** @(#) $Id: sqlite.h.in,v 1.311 2008/05/11 11:07:07 drh Exp $ 34 34 */ 35 35 #ifndef _SQLITE3_H_ 36 36 #define _SQLITE3_H_ 37 37 #include <stdarg.h> /* Needed for the definition of va_list */ 38 38 39 39 /* 40 40 ** Make sure we can call this stuff from C++. ................................................................................ 151 151 ** SQLite was compiled with its mutexes enabled or zero 152 152 ** if SQLite was compiled with mutexes disabled. 153 153 */ 154 154 int sqlite3_threadsafe(void); 155 155 156 156 /* 157 157 ** CAPI3REF: Database Connection Handle {F12000} 158 -** KEYWORDS: {database connection} 158 +** KEYWORDS: {database connection} {database connections} 159 159 ** 160 160 ** Each open SQLite database is represented by pointer to an instance of the 161 161 ** opaque structure named "sqlite3". It is useful to think of an sqlite3 162 162 ** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and 163 163 ** [sqlite3_open_v2()] interfaces are its constructors 164 164 ** and [sqlite3_close()] is its destructor. There are many other interfaces 165 165 ** (such as [sqlite3_prepare_v2()], [sqlite3_create_function()], and
Changes to src/test1.c.
9 9 ** May you share freely, never taking more than you give. 10 10 ** 11 11 ************************************************************************* 12 12 ** Code for testing all sorts of SQLite interfaces. This code 13 13 ** is not included in the SQLite library. It is used for automated 14 14 ** testing of the SQLite library. 15 15 ** 16 -** $Id: test1.c,v 1.301 2008/05/05 11:33:48 danielk1977 Exp $ 16 +** $Id: test1.c,v 1.302 2008/05/11 11:07:07 drh Exp $ 17 17 */ 18 18 #include "sqliteInt.h" 19 19 #include "tcl.h" 20 20 #include <stdlib.h> 21 21 #include <string.h> 22 22 23 23 /* ................................................................................ 2610 2610 int objc, 2611 2611 Tcl_Obj *CONST objv[] 2612 2612 ){ 2613 2613 sqlite3_stmt *pStmt; 2614 2614 int idx; 2615 2615 double value; 2616 2616 int rc; 2617 + const char *zVal; 2618 + int i; 2619 + static const struct { 2620 + const char *zName; /* Name of the special floating point value */ 2621 + unsigned int iUpper; /* Upper 32 bits */ 2622 + unsigned int iLower; /* Lower 32 bits */ 2623 + } aSpecialFp[] = { 2624 + { "NaN", 0x7fffffff, 0xffffffff }, 2625 + { "SNaN", 0x7ff7ffff, 0xffffffff }, 2626 + { "-NaN", 0xffffffff, 0xffffffff }, 2627 + { "-SNaN", 0xfff7ffff, 0xffffffff }, 2628 + { "+Inf", 0x7ff00000, 0x00000000 }, 2629 + { "-Inf", 0xfff00000, 0x00000000 }, 2630 + { "Epsilon", 0x00000000, 0x00000001 }, 2631 + { "-Epsilon", 0x80000000, 0x00000001 }, 2632 + { "NaN0", 0x7ff80000, 0x00000000 }, 2633 + { "-NaN0", 0xfff80000, 0x00000000 }, 2634 + }; 2617 2635 2618 2636 if( objc!=4 ){ 2619 2637 Tcl_AppendResult(interp, "wrong # args: should be \"", 2620 2638 Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0); 2621 2639 return TCL_ERROR; 2622 2640 } 2623 2641 ................................................................................ 2625 2643 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 2626 2644 2627 2645 /* Intercept the string "NaN" and generate a NaN value for it. 2628 2646 ** All other strings are passed through to Tcl_GetDoubleFromObj(). 2629 2647 ** Tcl_GetDoubleFromObj() should understand "NaN" but some versions 2630 2648 ** contain a bug. 2631 2649 */ 2632 - if( strcmp(Tcl_GetString(objv[3]), "NaN")==0 ){ 2633 - sqlite3_int64 i; 2634 - i = 0xfff80000; 2635 - i <<= 32; 2636 - value = *(double*)(char*)&i; 2637 - }else if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ){ 2650 + zVal = Tcl_GetString(objv[3]); 2651 + for(i=0; i<sizeof(aSpecialFp)/sizeof(aSpecialFp[0]); i++){ 2652 + if( strcmp(aSpecialFp[i].zName, zVal)==0 ){ 2653 + sqlite3_uint64 x; 2654 + x = aSpecialFp[i].iUpper; 2655 + x <<= 32; 2656 + x |= aSpecialFp[i].iLower; 2657 + value = *(double*)(char*)&x; 2658 + break; 2659 + } 2660 + } 2661 + if( i>=sizeof(aSpecialFp)/sizeof(aSpecialFp[0]) && 2662 + Tcl_GetDoubleFromObj(interp, objv[3], &value) ){ 2638 2663 return TCL_ERROR; 2639 2664 } 2640 2665 rc = sqlite3_bind_double(pStmt, idx, value); 2641 2666 if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; 2642 2667 if( rc!=SQLITE_OK ){ 2643 2668 return TCL_ERROR; 2644 2669 }
Changes to src/util.c.
10 10 ** 11 11 ************************************************************************* 12 12 ** Utility functions used throughout sqlite. 13 13 ** 14 14 ** This file contains functions for allocating memory, comparing 15 15 ** strings, and stuff like that. 16 16 ** 17 -** $Id: util.c,v 1.227 2008/05/09 13:47:59 drh Exp $ 17 +** $Id: util.c,v 1.228 2008/05/11 11:07:07 drh Exp $ 18 18 */ 19 19 #include "sqliteInt.h" 20 20 #include <stdarg.h> 21 21 #include <ctype.h> 22 22 23 23 24 24 /* ................................................................................ 258 258 ** for SQL. So this routine always uses "." regardless of locale. 259 259 */ 260 260 int sqlite3AtoF(const char *z, double *pResult){ 261 261 #ifndef SQLITE_OMIT_FLOATING_POINT 262 262 int sign = 1; 263 263 const char *zBegin = z; 264 264 LONGDOUBLE_TYPE v1 = 0.0; 265 + int nSignificant = 0; 265 266 while( isspace(*(u8*)z) ) z++; 266 267 if( *z=='-' ){ 267 268 sign = -1; 268 269 z++; 269 270 }else if( *z=='+' ){ 270 271 z++; 272 + } 273 + while( z[0]=='0' ){ 274 + z++; 271 275 } 272 276 while( isdigit(*(u8*)z) ){ 273 277 v1 = v1*10.0 + (*z - '0'); 274 278 z++; 279 + nSignificant++; 275 280 } 276 281 if( *z=='.' ){ 277 282 LONGDOUBLE_TYPE divisor = 1.0; 278 283 z++; 284 + if( nSignificant==0 ){ 285 + while( z[0]=='0' ){ 286 + divisor *= 10.0; 287 + z++; 288 + } 289 + } 279 290 while( isdigit(*(u8*)z) ){ 280 - v1 = v1*10.0 + (*z - '0'); 281 - divisor *= 10.0; 291 + if( nSignificant<18 ){ 292 + v1 = v1*10.0 + (*z - '0'); 293 + divisor *= 10.0; 294 + nSignificant++; 295 + } 282 296 z++; 283 297 } 284 298 v1 /= divisor; 285 299 } 286 300 if( *z=='e' || *z=='E' ){ 287 301 int esign = 1; 288 302 int eval = 0;
Changes to test/nan.test.
10 10 #*********************************************************************** 11 11 # 12 12 # Ticket #3060 13 13 # 14 14 # Make sure IEEE floating point NaN values are handled properly. 15 15 # SQLite should always convert NaN into NULL. 16 16 # 17 -# $Id: nan.test,v 1.2 2008/05/01 18:01:47 drh Exp $ 17 +# Also verify that the decimal to IEEE754 binary conversion routines 18 +# correctly generate 0.0, +Inf, and -Inf as appropriate for numbers 19 +# out of range. 20 +# 21 +# $Id: nan.test,v 1.3 2008/05/11 11:07:07 drh Exp $ 18 22 # 19 23 20 24 set testdir [file dirname $argv0] 21 25 source $testdir/tester.tcl 22 26 23 -# The ascii->float conversion routine in SQLite converts all digits 24 -# of a number to a long long double. Then it divids by 10**N where 25 -# N is the number of digits to the right of the decimal point. If 26 -# both the full number and 10**N are +Inf we will get +Inf/+Inf which 27 -# is NaN. 28 -# 29 -unset -nocomplain nan 30 -set nan 9.[string repeat 9 5000] 31 - 32 -unset -nocomplain inf 33 -set inf [string repeat 9 5000].0 34 27 35 28 do_test nan-1.1 { 36 29 db eval { 37 30 PRAGMA auto_vacuum=OFF; 38 31 PRAGMA page_size=1024; 39 32 CREATE TABLE t1(x FLOAT); 40 33 } 41 - db eval "INSERT INTO t1 VALUES($nan)" 34 + set ::STMT [sqlite3_prepare db "INSERT INTO t1 VALUES(?)" -1 TAIL] 35 + sqlite3_bind_double $::STMT 1 NaN 36 + sqlite3_step $::STMT 37 + sqlite3_reset $::STMT 42 38 db eval {SELECT x, typeof(x) FROM t1} 43 39 } {{} null} 44 40 do_test nan-1.2 { 45 - db eval "INSERT INTO t1 VALUES($inf)" 41 + sqlite3_bind_double $::STMT 1 +Inf 42 + sqlite3_step $::STMT 43 + sqlite3_reset $::STMT 46 44 db eval {SELECT x, typeof(x) FROM t1} 47 45 } {{} null inf real} 48 46 do_test nan-1.3 { 49 - db eval "INSERT INTO t1 VALUES(-$inf)" 47 + sqlite3_bind_double $::STMT 1 -Inf 48 + sqlite3_step $::STMT 49 + sqlite3_reset $::STMT 50 50 db eval {SELECT x, typeof(x) FROM t1} 51 51 } {{} null inf real -inf real} 52 52 do_test nan-1.4 { 53 + sqlite3_bind_double $::STMT 1 -NaN 54 + sqlite3_step $::STMT 55 + sqlite3_reset $::STMT 56 + db eval {SELECT x, typeof(x) FROM t1} 57 +} {{} null inf real -inf real {} null} 58 +do_test nan-1.5 { 59 + sqlite3_bind_double $::STMT 1 NaN0 60 + sqlite3_step $::STMT 61 + sqlite3_reset $::STMT 62 + db eval {SELECT x, typeof(x) FROM t1} 63 +} {{} null inf real -inf real {} null {} null} 64 +do_test nan-1.5 { 65 + sqlite3_bind_double $::STMT 1 -NaN0 66 + sqlite3_step $::STMT 67 + sqlite3_reset $::STMT 68 + db eval {SELECT x, typeof(x) FROM t1} 69 +} {{} null inf real -inf real {} null {} null {} null} 70 +do_test nan-1.6 { 53 71 db eval { 54 72 UPDATE t1 SET x=x-x; 55 73 SELECT x, typeof(x) FROM t1; 56 74 } 57 -} {{} null {} null {} null} 75 +} {{} null {} null {} null {} null {} null {} null} 58 76 59 77 do_test nan-2.1 { 60 78 db eval { 61 79 DELETE FROM T1; 62 80 } 63 - db eval "INSERT INTO t1 VALUES('$nan')" 81 + sqlite3_bind_double $::STMT 1 NaN 82 + sqlite3_step $::STMT 83 + sqlite3_reset $::STMT 64 84 db eval {SELECT x, typeof(x) FROM t1} 65 85 } {{} null} 86 +sqlite3_finalize $::STMT 66 87 67 88 # SQLite always converts NaN into NULL so it is not possible to write 68 89 # a NaN value into the database file using SQLite. The following series 69 90 # of tests writes a normal floating point value (0.5) into the database, 70 91 # then writes directly into the database file to change the 0.5 into NaN. 71 92 # Then it reads the value of the database to verify it is converted into 72 93 # NULL. ................................................................................ 88 109 } {0.5 real} 89 110 do_test nan-3.3 { 90 111 db close 91 112 hexio_write test.db 2040 FFF8000000000000 92 113 sqlite3 db test.db 93 114 db eval {SELECT x, typeof(x) FROM t1} 94 115 } {{} null} 116 +do_test nan-3.4 { 117 + db close 118 + hexio_write test.db 2040 7FF8000000000000 119 + sqlite3 db test.db 120 + db eval {SELECT x, typeof(x) FROM t1} 121 +} {{} null} 122 +do_test nan-3.5 { 123 + db close 124 + hexio_write test.db 2040 FFFFFFFFFFFFFFFF 125 + sqlite3 db test.db 126 + db eval {SELECT x, typeof(x) FROM t1} 127 +} {{} null} 128 +do_test nan-3.6 { 129 + db close 130 + hexio_write test.db 2040 7FFFFFFFFFFFFFFF 131 + sqlite3 db test.db 132 + db eval {SELECT x, typeof(x) FROM t1} 133 +} {{} null} 134 + 135 +# Verify that the sqlite3AtoF routine is able to handle extreme 136 +# numbers. 137 +# 138 +do_test nan-4.1 { 139 + db eval {DELETE FROM t1} 140 + db eval "INSERT INTO t1 VALUES([string repeat 9 307].0)" 141 + db eval {SELECT x, typeof(x) FROM t1} 142 +} {1e+307 real} 143 +do_test nan-4.2 { 144 + db eval {DELETE FROM t1} 145 + db eval "INSERT INTO t1 VALUES([string repeat 9 308].0)" 146 + db eval {SELECT x, typeof(x) FROM t1} 147 +} {1e+308 real} 148 +do_test nan-4.3 { 149 + db eval {DELETE FROM t1} 150 + db eval "INSERT INTO t1 VALUES([string repeat 9 309].0)" 151 + db eval {SELECT x, typeof(x) FROM t1} 152 +} {inf real} 153 +do_test nan-4.4 { 154 + db eval {DELETE FROM t1} 155 + db eval "INSERT INTO t1 VALUES(-[string repeat 9 307].0)" 156 + db eval {SELECT x, typeof(x) FROM t1} 157 +} {-1e+307 real} 158 +do_test nan-4.5 { 159 + db eval {DELETE FROM t1} 160 + db eval "INSERT INTO t1 VALUES(-[string repeat 9 308].0)" 161 + db eval {SELECT x, typeof(x) FROM t1} 162 +} {-1e+308 real} 163 +do_test nan-4.6 { 164 + db eval {DELETE FROM t1} 165 + db eval "INSERT INTO t1 VALUES(-[string repeat 9 309].0)" 166 + db eval {SELECT x, typeof(x) FROM t1} 167 +} {-inf real} 168 +do_test nan-4.7 { 169 + db eval {DELETE FROM t1} 170 + set big -[string repeat 0 10000][string repeat 9 308].[string repeat 0 10000] 171 + db eval "INSERT INTO t1 VALUES($big)" 172 + db eval {SELECT x, typeof(x) FROM t1} 173 +} {-1e+308 real} 174 +do_test nan-4.8 { 175 + db eval {DELETE FROM t1} 176 + set big [string repeat 0 10000][string repeat 9 308].[string repeat 0 10000] 177 + db eval "INSERT INTO t1 VALUES($big)" 178 + db eval {SELECT x, typeof(x) FROM t1} 179 +} {1e+308 real} 180 + 181 + 182 +do_test nan-4.10 { 183 + db eval {DELETE FROM t1} 184 + db eval "INSERT INTO t1 VALUES(1234.5[string repeat 0 10000]12345)" 185 + db eval {SELECT x, typeof(x) FROM t1} 186 +} {1234.5 real} 187 +do_test nan-4.11 { 188 + db eval {DELETE FROM t1} 189 + db eval "INSERT INTO t1 VALUES(-1234.5[string repeat 0 10000]12345)" 190 + db eval {SELECT x, typeof(x) FROM t1} 191 +} {-1234.5 real} 192 +do_test nan-4.12 { 193 + db eval {DELETE FROM t1} 194 + set small [string repeat 0 10000].[string repeat 0 323][string repeat 9 10000] 195 + db eval "INSERT INTO t1 VALUES($small)" 196 + db eval {SELECT x, typeof(x) FROM t1} 197 +} {9.88131291682493e-324 real} 198 +do_test nan-4.13 { 199 + db eval {DELETE FROM t1} 200 + set small [string repeat 0 10000].[string repeat 0 324][string repeat 9 10000] 201 + db eval "INSERT INTO t1 VALUES($small)" 202 + db eval {SELECT x, typeof(x) FROM t1} 203 +} {0.0 real} 204 +do_test nan-4.14 { 205 + db eval {DELETE FROM t1} 206 + set small \ 207 + -[string repeat 0 10000].[string repeat 0 323][string repeat 9 10000] 208 + db eval "INSERT INTO t1 VALUES($small)" 209 + db eval {SELECT x, typeof(x) FROM t1} 210 +} {-9.88131291682493e-324 real} 211 +do_test nan-4.15 { 212 + db eval {DELETE FROM t1} 213 + set small \ 214 + -[string repeat 0 10000].[string repeat 0 324][string repeat 9 10000] 215 + db eval "INSERT INTO t1 VALUES($small)" 216 + db eval {SELECT x, typeof(x) FROM t1} 217 +} {0.0 real} 218 + 219 +do_test nan-4.20 { 220 + db eval {DELETE FROM t1} 221 + set big [string repeat 9 10000].0e-9000 222 + db eval "INSERT INTO t1 VALUES($big)" 223 + db eval {SELECT x, typeof(x) FROM t1} 224 +} {{} null} 225 + 226 + 95 227 96 228 finish_test