Safer readInt

This commit is contained in:
Amos Bird 2021-05-25 10:29:47 +08:00
parent 9edfc1641a
commit 6f12781bf1
No known key found for this signature in database
GPG Key ID: 80D430DCBECFEDB4
6 changed files with 58 additions and 3 deletions

View File

@ -270,16 +270,37 @@ ReturnType readIntTextImpl(T & x, ReadBuffer & buf)
}
const size_t initial_pos = buf.count();
bool has_sign = false;
bool has_number = false;
while (!buf.eof())
{
switch (*buf.position())
{
case '+':
{
if (has_sign || has_number)
{
if constexpr (throw_exception)
throw ParsingException(
"Cannot parse number with multiple sign (+/-) characters or intermediate sign character",
ErrorCodes::CANNOT_PARSE_NUMBER);
else
return ReturnType(false);
}
has_sign = true;
break;
}
case '-':
{
if (has_sign || has_number)
{
if constexpr (throw_exception)
throw ParsingException(
"Cannot parse number with multiple sign (+/-) characters or intermediate sign character",
ErrorCodes::CANNOT_PARSE_NUMBER);
else
return ReturnType(false);
}
if constexpr (is_signed_v<T>)
negative = true;
else
@ -289,6 +310,7 @@ ReturnType readIntTextImpl(T & x, ReadBuffer & buf)
else
return ReturnType(false);
}
has_sign = true;
break;
}
case '0': [[fallthrough]];
@ -302,6 +324,7 @@ ReturnType readIntTextImpl(T & x, ReadBuffer & buf)
case '8': [[fallthrough]];
case '9':
{
has_number = true;
if constexpr (check_overflow == ReadIntTextCheckOverflow::CHECK_OVERFLOW && !is_big_int_v<T>)
{
/// Perform relativelly slow overflow check only when
@ -330,6 +353,14 @@ ReturnType readIntTextImpl(T & x, ReadBuffer & buf)
}
end:
if (has_sign && !has_number)
{
if constexpr (throw_exception)
throw ParsingException(
"Cannot parse number with a sign character but without any numeric character", ErrorCodes::CANNOT_PARSE_NUMBER);
else
return ReturnType(false);
}
x = res;
if constexpr (is_signed_v<T>)
{

View File

@ -0,0 +1,12 @@
<test>
<create_query>DROP TABLE IF EXISTS numeric_strings</create_query>
<create_query>CREATE TABLE numeric_strings(num String) ENGINE Memory</create_query>
<fill_query>
INSERT INTO numeric_strings SELECT number FROM numbers(30000000)
</fill_query>
<query short="1">SELECT count(num::Int64) FROM numeric_strings FORMAT Null</query>
<drop_query>DROP TABLE IF EXISTS numeric_strings</drop_query>
</test>

View File

@ -8,8 +8,8 @@ $CLICKHOUSE_CLIENT -q "DROP TABLE IF EXISTS empty_strings_deserialization"
$CLICKHOUSE_CLIENT -q "CREATE TABLE empty_strings_deserialization(s String, i Int32, f Float32) ENGINE Memory"
echo ',,' | $CLICKHOUSE_CLIENT -q "INSERT INTO empty_strings_deserialization FORMAT CSV"
echo 'aaa,-,' | $CLICKHOUSE_CLIENT -q "INSERT INTO empty_strings_deserialization FORMAT CSV"
echo 'bbb,,-' | $CLICKHOUSE_CLIENT -q "INSERT INTO empty_strings_deserialization FORMAT CSV"
echo 'aaa,,' | $CLICKHOUSE_CLIENT -q "INSERT INTO empty_strings_deserialization FORMAT CSV"
echo 'bbb,,-0' | $CLICKHOUSE_CLIENT -q "INSERT INTO empty_strings_deserialization FORMAT CSV"
$CLICKHOUSE_CLIENT -q "SELECT * FROM empty_strings_deserialization ORDER BY s"

View File

@ -1,4 +1,4 @@
SELECT '-1E9-1E9-1E9-1E9' AS x, toDecimal32(x, 0); -- { serverError 6 }
SELECT '-1E9-1E9-1E9-1E9' AS x, toDecimal32(x, 0); -- { serverError 72 }
SELECT '-1E9' AS x, toDecimal32(x, 0); -- { serverError 69 }
SELECT '1E-9' AS x, toDecimal32(x, 0);
SELECT '1E-8' AS x, toDecimal32(x, 0);

View File

@ -0,0 +1,2 @@
1
-1

View File

@ -0,0 +1,10 @@
select toInt64('--1'); -- { serverError 72; }
select toInt64('+-1'); -- { serverError 72; }
select toInt64('++1'); -- { serverError 72; }
select toInt64('++'); -- { serverError 72; }
select toInt64('+'); -- { serverError 72; }
select toInt64('1+1'); -- { serverError 72; }
select toInt64('1-1'); -- { serverError 72; }
select toInt64(''); -- { serverError 32; }
select toInt64('1');
select toInt64('-1');