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

Enforce consistent comparison results between integer and floating point

values.  Fix for ticket [38a97a87a6e4e83].

FossilOrigin-Name: 849e686da2d20fd7f938427475fc792384d2aa7c
This commit is contained in:
drh
2015-11-06 19:53:09 +00:00
6 changed files with 150 additions and 45 deletions

View File

@@ -1,5 +1,5 @@
C Test\scases\sfor\sthe\sieee754\sextension.
D 2015-11-06T17:01:20.579
C Enforce\sconsistent\scomparison\sresults\sbetween\sinteger\sand\sfloating\spoint\nvalues.\s\sFix\sfor\sticket\s[38a97a87a6e4e83].
D 2015-11-06T19:53:09.863
F Makefile.in 3a705bb4bd12e194212ddbdbf068310d17153cdb
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 702d3e98f3afc6587a78481257f3c4c900efc3a4
@@ -350,7 +350,7 @@ F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
F src/tclsqlite.c d9439b6a910985b7fff43ba6756bcef00de22649
F src/test1.c 9ac5cbfe3c859ab7518edc5109a2959d6bf7b059
F src/test1.c a719afff3144f7f01c6dc3f7d118ac31d15e7527
F src/test2.c 5586f43fcd9a1be0830793cf9d354082c261b25b
F src/test3.c a8887dabbbee3059af338f20d290084a63ed1b0f
F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e
@@ -407,7 +407,7 @@ F src/vdbe.c dfbaae2570172c523bce14299021d352b8508f7f
F src/vdbe.h efb7a8c1459e31f3ea4377824c6a7e4cb5068637
F src/vdbeInt.h 33403622c6a8feaaac5f0f3f17f5d1bf6df42286
F src/vdbeapi.c 020681b943e77766b32ae1cddf86d7831b7374ca
F src/vdbeaux.c 717bc2ae9cc0b58ef398fff44bd9164bfd96772a
F src/vdbeaux.c 869c95b0fc73026da1ca179e053807f563793e8f
F src/vdbeblob.c 565fabd302f5fca3bdf3d56cac330483616a39b6
F src/vdbemem.c fdd1578e47bea61390d472de53c565781d81e045
F src/vdbesort.c 8b23930a1289526f6d2a3a9f2e965bcc963e4a68
@@ -453,7 +453,7 @@ F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a
F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0
F test/atof1.test 08a61df9365c341f334a65f4348897312d8f3db7
F test/atof1.test ff0b0156fd705b67c506e1f2bfe9e26102bea9bd
F test/attach.test 437107943f14d131cf5efc2ae5305a94d7cb1d58
F test/attach2.test 0ec5defa340363de6cd50fd595046465e9aaba2d
F test/attach3.test 359eb65d00102cdfcef6fa4e81dc1648f8f80b27
@@ -903,6 +903,7 @@ F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934
F test/notnull.test f8fcf58669ddba79274daa2770d61dfad8274f62
F test/null.test 0dcce4f04284ec66108c503327ad6d224c0752b3
F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1
F test/numindex1.test 20a5450d4b056e48cd5db30e659f13347a099823
F test/offset1.test f06b83657bcf26f9ce805e67450e189e282143b2
F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394
F test/orderby1.test 870e150450437d3980badbde3d0166b81d9e33f6
@@ -1399,7 +1400,8 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 33e6606f5e497e81119ec491cf2370f60bddafc0
R 6a48cd86f6e2c59a9972f4901e737c7d
P 840cbda88675b6012dae2423252bf42d0d563874 7a9988d38cd7ab3df79eed97631ff23d5928b4ad
R 281cdf2e28b38f35a9e781fe4ef44557
T +closed 7a9988d38cd7ab3df79eed97631ff23d5928b4ad
U drh
Z 4f550f3fed6ca631b416aee9408c87ae
Z 043f003e4fd28221190bc705626ad8a1

View File

@@ -1 +1 @@
840cbda88675b6012dae2423252bf42d0d563874
849e686da2d20fd7f938427475fc792384d2aa7c

View File

@@ -7039,6 +7039,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
};
static int bitmask_size = sizeof(Bitmask)*8;
static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
int i;
extern int sqlite3_sync_count, sqlite3_fullsync_count;
extern int sqlite3_opentemp_count;
@@ -7139,6 +7140,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_data_directory, TCL_LINK_STRING);
Tcl_LinkVar(interp, "bitmask_size",
(char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY);
Tcl_LinkVar(interp, "longdouble_size",
(char*)&longdouble_size, TCL_LINK_INT|TCL_LINK_READ_ONLY);
Tcl_LinkVar(interp, "sqlite_sync_count",
(char*)&sqlite3_sync_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_fullsync_count",

View File

@@ -3634,6 +3634,34 @@ static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){
return pB1->n - pB2->n;
}
/*
** Do a comparison between a 64-bit signed integer and a 64-bit floating-point
** number. Return negative, zero, or positive if the first (i64) is less than,
** equal to, or greater than the second (double).
*/
static int sqlite3IntFloatCompare(i64 i, double r){
if( sizeof(LONGDOUBLE_TYPE)>8 ){
LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
if( x<r ) return -1;
if( x>r ) return +1;
return 0;
}else{
i64 y;
double s;
if( r<-9223372036854775808.0 ) return +1;
if( r>9223372036854775807.0 ) return -1;
y = (i64)r;
if( i<y ) return -1;
if( i>y ){
if( y==SMALLEST_INT64 && r>0.0 ) return -1;
return +1;
}
s = (double)i;
if( s<r ) return -1;
if( s>r ) return +1;
return 0;
}
}
/*
** Compare the values contained by the two memory cells, returning
@@ -3660,34 +3688,34 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
return (f2&MEM_Null) - (f1&MEM_Null);
}
/* If one value is a number and the other is not, the number is less.
** If both are numbers, compare as reals if one is a real, or as integers
** if both values are integers.
/* At least one of the two values is a number
*/
if( combined_flags&(MEM_Int|MEM_Real) ){
double r1, r2;
if( (f1 & f2 & MEM_Int)!=0 ){
if( pMem1->u.i < pMem2->u.i ) return -1;
if( pMem1->u.i > pMem2->u.i ) return 1;
if( pMem1->u.i > pMem2->u.i ) return +1;
return 0;
}
if( (f1 & f2 & MEM_Real)!=0 ){
if( pMem1->u.r < pMem2->u.r ) return -1;
if( pMem1->u.r > pMem2->u.r ) return +1;
return 0;
}
if( (f1&MEM_Int)!=0 ){
if( (f2&MEM_Real)!=0 ){
return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r);
}else{
return -1;
}
}
if( (f1&MEM_Real)!=0 ){
r1 = pMem1->u.r;
}else if( (f1&MEM_Int)!=0 ){
r1 = (double)pMem1->u.i;
}else{
return 1;
if( (f2&MEM_Int)!=0 ){
return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r);
}else{
return -1;
}
}
if( (f2&MEM_Real)!=0 ){
r2 = pMem2->u.r;
}else if( (f2&MEM_Int)!=0 ){
r2 = (double)pMem2->u.i;
}else{
return -1;
}
if( r1<r2 ) return -1;
if( r1>r2 ) return 1;
return 0;
return +1;
}
/* If one value is a string and the other is a blob, the string is less.
@@ -3838,13 +3866,8 @@ int sqlite3VdbeRecordCompareWithSkip(
}else if( serial_type==0 ){
rc = -1;
}else if( serial_type==7 ){
double rhs = (double)pRhs->u.i;
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
if( mem1.u.r<rhs ){
rc = -1;
}else if( mem1.u.r>rhs ){
rc = +1;
}
rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
}else{
i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
i64 rhs = pRhs->u.i;
@@ -3868,18 +3891,15 @@ int sqlite3VdbeRecordCompareWithSkip(
}else if( serial_type==0 ){
rc = -1;
}else{
double rhs = pRhs->u.r;
double lhs;
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
if( serial_type==7 ){
lhs = mem1.u.r;
if( mem1.u.r<pRhs->u.r ){
rc = -1;
}else if( mem1.u.r>pRhs->u.r ){
rc = +1;
}
}else{
lhs = (double)mem1.u.i;
}
if( lhs<rhs ){
rc = -1;
}else if( lhs>rhs ){
rc = +1;
rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
}
}
}
@@ -4088,6 +4108,7 @@ static int vdbeRecordCompareString(
int serial_type;
int res;
assert( pPKey2->aMem[0].flags & MEM_Str );
vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
getVarint32(&aKey1[1], serial_type);
if( serial_type<12 ){

View File

@@ -15,7 +15,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
if {![info exists __GNUC__] || [regexp arm $tcl_platform(machine)]} {
if {$::longdouble_size<=8} {
finish_test
return
}

79
test/numindex1.test Normal file
View File

@@ -0,0 +1,79 @@
# 2015-11-05
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements tests for indexes on large numeric values.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Test cases from Zsbán Ambrus:
#
do_execsql_test numindex1-1.1 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
CREATE INDEX t1b ON t1(b);
INSERT INTO t1(a,b) VALUES(100, 356282677878746339);
INSERT INTO t1(a,b) VALUES(50, 356282677878746339.0);
INSERT INTO t1(a,b) VALUES(0, 356282677878746340);
DELETE FROM t1 WHERE a=50;
PRAGMA integrity_check;
} {ok}
do_execsql_test numindex1-1.2 {
CREATE TABLE t2(a,b);
INSERT INTO t2(a,b) VALUES('b', 1<<58),
('c', (1<<58)+1e-7), ('d', (1<<58)+1);
SELECT a, b, typeof(b), '|' FROM t2 ORDER BY +a;
} {b 288230376151711744 integer | c 2.88230376151712e+17 real | d 288230376151711745 integer |}
do_execsql_test numindex1-1.3 {
SELECT x.a || CASE WHEN x.b==y.b THEN '==' ELSE '<>' END || y.a
FROM t2 AS x, t2 AS y
ORDER BY +x.a, +x.b;
} {b==b b==c b<>d c==b c==c c<>d d<>b d<>c d==d}
# New test cases
#
do_execsql_test numindex1-2.1 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY,b);
CREATE INDEX t1b ON t1(b);
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
INSERT INTO t1(a,b) SELECT x, 10000000000000004.0 FROM c
WHERE x NOT IN (23,37);
INSERT INTO t1(a,b) VALUES(23,10000000000000005);
INSERT INTO t1(a,b) VALUES(37,10000000000000003);
DELETE FROM t1 WHERE a NOT IN (23,37);
PRAGMA integrity_check;
} {ok}
do_execsql_test numindex1-3.1 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY,b);
CREATE INDEX t1b ON t1(b);
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<20)
INSERT INTO t1(a,b) SELECT x, 100000000000000005.0
FROM c WHERE x NOT IN (3,5,7,11,13,17,19);
INSERT INTO t1(a,b) VALUES(3,100000000000000005);
INSERT INTO t1(a,b) VALUES(5,100000000000000000);
INSERT INTO t1(a,b) VALUES(7,100000000000000008);
INSERT INTO t1(a,b) VALUES(11,100000000000000006);
INSERT INTO t1(a,b) VALUES(13,100000000000000001);
INSERT INTO t1(a,b) VALUES(17,100000000000000004);
INSERT INTO t1(a,b) VALUES(19,100000000000000003);
PRAGMA integrity_check;
} {ok}
do_execsql_test numindex1-3.2 {
SELECT a FROM t1 ORDER BY b;
} {1 2 4 5 6 8 9 10 12 14 15 16 18 20 13 19 17 3 11 7}
finish_test