1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-09 14:21:03 +03:00

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
This commit is contained in:
drh
2008-05-11 11:07:06 +00:00
parent d2dadc9647
commit a06f17fe2e
6 changed files with 211 additions and 40 deletions

View File

@@ -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

View File

@@ -1 +1 @@
ecc6c739064922937ce66339f74403a0346aeedd
3ff2f1cdc9c57bca56de6cdc0ad5edc95b0606a0

View File

@@ -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

View File

@@ -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]); 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);

View File

@@ -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 <stdarg.h>
@@ -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;

View File

@@ -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