Fix text-to-numeric type casting so that it works correctly on UTF16
strings that contain characters where the LSB is numeric but the MSB is non-zero. Ticket [689137afb6da41] FossilOrigin-Name: 5b22053f918d16f593227a432a5d5b4c195bb0b5
This commit is contained in:
parent
339d6c6d17
commit
0e5fba790a
13
manifest
13
manifest
@ -1,5 +1,5 @@
|
||||
C Bring\smakefiles\sand\sbuild\sscripts\sinto\salignment\swith\sthe\ssessions\sbranch.\nNo\schanges\sto\scode.
|
||||
D 2013-03-19T16:12:40.639
|
||||
C Fix\stext-to-numeric\stype\scasting\sso\sthat\sit\sworks\scorrectly\son\sUTF16\nstrings\sthat\scontain\scharacters\swhere\sthe\sLSB\sis\snumeric\sbut\sthe\sMSB\nis\snon-zero.\s\sTicket\s[689137afb6da41]
|
||||
D 2013-03-20T12:04:29.291
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in df3e48659d80e1b7765785d8d66c86b320f72cc7
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -237,7 +237,7 @@ F src/tokenize.c 1e86210d3976717a19238ea7b047fac481fe8c12
|
||||
F src/trigger.c cd95ac64efa60e39faf9b5597443192ff27a22fa
|
||||
F src/update.c 28d2d098b43a2c70dae399896ea8a02f622410ef
|
||||
F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f
|
||||
F src/util.c 0af2e515dc0dabacec931bca39525f6c3f1c5455
|
||||
F src/util.c 550f2b6a5c0085153a4d00462719fb17ee242792
|
||||
F src/vacuum.c 2727bdd08847fcb6b2d2da6d14f018910e8645d3
|
||||
F src/vdbe.c 292f8f7ced59c29c63fe17830cbe5f5a0230cdf0
|
||||
F src/vdbe.h b52887278cb173e66188da84dfab216bea61119d
|
||||
@ -641,6 +641,7 @@ F test/notify2.test 9503e51b9a272a5405c205ad61b7623d5a9ca489
|
||||
F test/notify3.test a86259abbfb923aa27d30f0fc038c88e5251488a
|
||||
F test/notnull.test 2afad748d18fd66d01f66463de73b3e2501fb226
|
||||
F test/null.test a8b09b8ed87852742343b33441a9240022108993
|
||||
F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1
|
||||
F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394
|
||||
F test/orderby1.test f33968647da5c546528fe4d2bf86c6a6a2e5a7ae
|
||||
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
|
||||
@ -1038,7 +1039,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
||||
P 4fe2db1d866c80fe51f7fddbf9ce6753fb55b5f6
|
||||
R 7758dd15e3a5f0387c3f17443ec025d8
|
||||
P d1f41089aba075eef45fd696599e5d3a74c84d0c
|
||||
R ccf3378e4accef01a0ea31a61ac073d2
|
||||
U drh
|
||||
Z 7c5d1dfbeba3270fc7d5841fae61579f
|
||||
Z 400c45055ef48421e523d8328d092a1b
|
||||
|
@ -1 +1 @@
|
||||
d1f41089aba075eef45fd696599e5d3a74c84d0c
|
||||
5b22053f918d16f593227a432a5d5b4c195bb0b5
|
38
src/util.c
38
src/util.c
@ -261,7 +261,7 @@ int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
|
||||
*/
|
||||
int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
int incr = (enc==SQLITE_UTF8?1:2);
|
||||
int incr;
|
||||
const char *zEnd = z + length;
|
||||
/* sign * significand * (10 ^ (esign * exponent)) */
|
||||
int sign = 1; /* sign of significand */
|
||||
@ -272,10 +272,22 @@ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
|
||||
int eValid = 1; /* True exponent is either not used or is well-formed */
|
||||
double result;
|
||||
int nDigits = 0;
|
||||
int nonNum = 0;
|
||||
|
||||
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
|
||||
*pResult = 0.0; /* Default return value, in case of an error */
|
||||
|
||||
if( enc==SQLITE_UTF16BE ) z++;
|
||||
if( enc==SQLITE_UTF8 ){
|
||||
incr = 1;
|
||||
}else{
|
||||
int i;
|
||||
incr = 2;
|
||||
assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
|
||||
for(i=3-enc; i<length && z[i]==0; i+=2){}
|
||||
nonNum = i<length;
|
||||
zEnd = z+i+enc-3;
|
||||
z += (enc&1);
|
||||
}
|
||||
|
||||
/* skip leading spaces */
|
||||
while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
|
||||
@ -408,7 +420,7 @@ do_atof_calc:
|
||||
*pResult = result;
|
||||
|
||||
/* return true if number and no extra non-whitespace chracters after */
|
||||
return z>=zEnd && nDigits>0 && eValid;
|
||||
return z>=zEnd && nDigits>0 && eValid && nonNum==0;
|
||||
#else
|
||||
return !sqlite3Atoi64(z, pResult, length, enc);
|
||||
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
||||
@ -457,21 +469,33 @@ static int compare2pow63(const char *zNum, int incr){
|
||||
** signed 64-bit integer, its negative -9223372036854665808 can be.
|
||||
**
|
||||
** If zNum is too big for a 64-bit integer and is not
|
||||
** 9223372036854665808 then return 1.
|
||||
** 9223372036854665808 or if zNum contains any non-numeric text,
|
||||
** then return 1.
|
||||
**
|
||||
** length is the number of bytes in the string (bytes, not characters).
|
||||
** The string is not necessarily zero-terminated. The encoding is
|
||||
** given by enc.
|
||||
*/
|
||||
int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
int incr = (enc==SQLITE_UTF8?1:2);
|
||||
int incr;
|
||||
u64 u = 0;
|
||||
int neg = 0; /* assume positive */
|
||||
int i;
|
||||
int c = 0;
|
||||
int nonNum = 0;
|
||||
const char *zStart;
|
||||
const char *zEnd = zNum + length;
|
||||
if( enc==SQLITE_UTF16BE ) zNum++;
|
||||
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
|
||||
if( enc==SQLITE_UTF8 ){
|
||||
incr = 1;
|
||||
}else{
|
||||
incr = 2;
|
||||
assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
|
||||
for(i=3-enc; i<length && zNum[i]==0; i+=2){}
|
||||
nonNum = i<length;
|
||||
zEnd = zNum+i+enc-3;
|
||||
zNum += (enc&1);
|
||||
}
|
||||
while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
|
||||
if( zNum<zEnd ){
|
||||
if( *zNum=='-' ){
|
||||
@ -496,7 +520,7 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
testcase( i==18 );
|
||||
testcase( i==19 );
|
||||
testcase( i==20 );
|
||||
if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr ){
|
||||
if( (c+nonNum!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr ){
|
||||
/* zNum is empty or contains non-numeric text or is longer
|
||||
** than 19 digits (thus guaranteeing that it is too large) */
|
||||
return 1;
|
||||
|
46
test/numcast.test
Normal file
46
test/numcast.test
Normal file
@ -0,0 +1,46 @@
|
||||
# 2013 March 20
|
||||
#
|
||||
# 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 regression tests for SQLite library.
|
||||
# This particular file does testing of casting strings into numeric
|
||||
# values.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
foreach enc {utf8 utf16le utf16be} {
|
||||
do_test numcast-$enc.0 {
|
||||
db close
|
||||
sqlite3 db :memory:
|
||||
db eval "PRAGMA encoding='$enc'"
|
||||
set x [db eval {PRAGMA encoding}]
|
||||
string map {- {}} [string tolower $x]
|
||||
} $enc
|
||||
foreach {idx str rval ival} {
|
||||
1 12345.0 12345.0 12345
|
||||
2 12345.0e0 12345.0 12345
|
||||
3 -12345.0e0 -12345.0 -12345
|
||||
4 -12345.25 -12345.25 -12345
|
||||
5 { -12345.0} -12345.0 -12345
|
||||
6 { 876xyz} 876.0 876
|
||||
7 { 456ķ89} 456.0 456
|
||||
8 { Ġ 321.5} 0.0 0
|
||||
} {
|
||||
do_test numcast-$enc.$idx.1 {
|
||||
db eval {SELECT CAST($str AS real)}
|
||||
} $rval
|
||||
do_test numcast-$enc.$idx.2 {
|
||||
db eval {SELECT CAST($str AS integer)}
|
||||
} $ival
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
Loading…
x
Reference in New Issue
Block a user