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 |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
3ff2f1cdc9c57bca56de6cdc0ad5edc9 |
User & Date: | drh 2008-05-11 11:07:07.000 |
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: 88e12caca9 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: 3ff2f1cdc9 user: drh tags: trunk) | |
2008-05-09
| ||
19:38 | Fix leaked filename in case DosOpen() fails. (CVS 5115) (check-in: ecc6c73906 user: pweilbacher tags: trunk) | |
Changes
Changes to src/sqlite.h.in.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** on how SQLite interfaces are suppose to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** on how SQLite interfaces are suppose to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** ** @(#) $Id: sqlite.h.in,v 1.311 2008/05/11 11:07:07 drh Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ #include <stdarg.h> /* Needed for the definition of va_list */ /* ** Make sure we can call this stuff from C++. |
︙ | ︙ | |||
151 152 153 154 155 156 157 | ** SQLite was compiled with its mutexes enabled or zero ** if SQLite was compiled with mutexes disabled. */ int sqlite3_threadsafe(void); /* ** CAPI3REF: Database Connection Handle {F12000} | | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | ** SQLite was compiled with its mutexes enabled or zero ** if SQLite was compiled with mutexes disabled. */ int sqlite3_threadsafe(void); /* ** CAPI3REF: Database Connection Handle {F12000} ** 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 ** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and ** [sqlite3_open_v2()] interfaces are its constructors ** and [sqlite3_close()] is its destructor. There are many other interfaces ** (such as [sqlite3_prepare_v2()], [sqlite3_create_function()], and |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test1.c,v 1.302 2008/05/11 11:07:07 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> /* |
︙ | ︙ | |||
2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 | int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; double value; int rc; if( objc!=4 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; /* Intercept the string "NaN" and generate a NaN value for it. ** All other strings are passed through to Tcl_GetDoubleFromObj(). ** Tcl_GetDoubleFromObj() should understand "NaN" but some versions ** contain a bug. */ | > > > > > > > > > > > > > > > > > > | > > | | | > | > > > > | | 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 | int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; 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 \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; /* Intercept the string "NaN" and generate a NaN value for it. ** All other strings are passed through to Tcl_GetDoubleFromObj(). ** Tcl_GetDoubleFromObj() should understand "NaN" but some versions ** contain a bug. */ zVal = Tcl_GetString(objv[3]); for(i=0; i<sizeof(aSpecialFp)/sizeof(aSpecialFp[0]); i++){ if( strcmp(aSpecialFp[i].zName, zVal)==0 ){ sqlite3_uint64 x; x = aSpecialFp[i].iUpper; x <<= 32; x |= aSpecialFp[i].iLower; value = *(double*)(char*)&x; break; } } if( i>=sizeof(aSpecialFp)/sizeof(aSpecialFp[0]) && Tcl_GetDoubleFromObj(interp, objv[3], &value) ){ return TCL_ERROR; } rc = sqlite3_bind_double(pStmt, idx, value); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ return TCL_ERROR; } |
︙ | ︙ |
Changes to src/util.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** ** $Id: util.c,v 1.228 2008/05/11 11:07:07 drh Exp $ */ #include "sqliteInt.h" #include <stdarg.h> #include <ctype.h> /* |
︙ | ︙ | |||
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | ** for SQL. So this routine always uses "." regardless of locale. */ int sqlite3AtoF(const char *z, double *pResult){ #ifndef SQLITE_OMIT_FLOATING_POINT int sign = 1; const char *zBegin = z; LONGDOUBLE_TYPE v1 = 0.0; while( isspace(*(u8*)z) ) z++; if( *z=='-' ){ sign = -1; z++; }else if( *z=='+' ){ z++; } while( isdigit(*(u8*)z) ){ v1 = v1*10.0 + (*z - '0'); z++; } if( *z=='.' ){ LONGDOUBLE_TYPE divisor = 1.0; z++; while( isdigit(*(u8*)z) ){ | > > > > > > > > > > > > | | > > | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | ** for SQL. So this routine always uses "." regardless of locale. */ int sqlite3AtoF(const char *z, double *pResult){ #ifndef SQLITE_OMIT_FLOATING_POINT int sign = 1; const char *zBegin = z; LONGDOUBLE_TYPE v1 = 0.0; int nSignificant = 0; while( isspace(*(u8*)z) ) z++; if( *z=='-' ){ sign = -1; z++; }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) ){ if( nSignificant<18 ){ v1 = v1*10.0 + (*z - '0'); divisor *= 10.0; nSignificant++; } z++; } v1 /= divisor; } if( *z=='e' || *z=='E' ){ int esign = 1; int eval = 0; |
︙ | ︙ |
Changes to test/nan.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # # Ticket #3060 # # Make sure IEEE floating point NaN values are handled properly. # SQLite should always convert NaN into NULL. # | > > > > | < < < < < < < < < < < | > > > | > > | > > > > > > > > > > > > > > > > > > > > | | > > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | #*********************************************************************** # # Ticket #3060 # # Make sure IEEE floating point NaN values are handled properly. # SQLite should always convert NaN into NULL. # # 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 do_test nan-1.1 { db eval { PRAGMA auto_vacuum=OFF; PRAGMA page_size=1024; CREATE TABLE t1(x FLOAT); } 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 { 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 { 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} do_test nan-2.1 { db eval { DELETE FROM T1; } 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 # of tests writes a normal floating point value (0.5) into the database, # then writes directly into the database file to change the 0.5 into NaN. # Then it reads the value of the database to verify it is converted into # NULL. |
︙ | ︙ | |||
88 89 90 91 92 93 94 95 96 | } {0.5 real} do_test nan-3.3 { db close hexio_write test.db 2040 FFF8000000000000 sqlite3 db test.db db eval {SELECT x, typeof(x) FROM t1} } {{} null} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | } {0.5 real} do_test nan-3.3 { db close hexio_write test.db 2040 FFF8000000000000 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 |