mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Fixed overflow in intDiv functions
This commit is contained in:
parent
8949ef6dd3
commit
52650ce2f7
@ -13,6 +13,7 @@ namespace DB
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int ILLEGAL_DIVISION;
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
@ -55,7 +56,18 @@ struct DivideIntegralImpl
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
throwIfDivisionLeadsToFPE(a, b);
|
||||
return a / b;
|
||||
|
||||
if constexpr (!std::is_same_v<ResultType, NumberTraits::Error>)
|
||||
{
|
||||
/// Otherwise overflow may occur due to integer promotion. Example: int8_t(-1) / uint64_t(2).
|
||||
/// NOTE: overflow is still possible when dividing large signed number to large unsigned number or vice-versa. But it's less harmful.
|
||||
if constexpr (std::is_integral_v<A> && std::is_integral_v<B> && (std::is_signed_v<A> || std::is_signed_v<B>))
|
||||
return std::make_signed_t<A>(a) / std::make_signed_t<B>(b);
|
||||
else
|
||||
return a / b;
|
||||
}
|
||||
else
|
||||
throw Exception("Logical error: the types are not divisable", ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
|
@ -1,9 +1,17 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
#include "intDiv.h"
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
struct DivideIntegralOrZeroImpl
|
||||
{
|
||||
@ -12,7 +20,13 @@ struct DivideIntegralOrZeroImpl
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return unlikely(divisionLeadsToFPE(a, b)) ? 0 : a / b;
|
||||
if (unlikely(divisionLeadsToFPE(a, b)))
|
||||
return 0;
|
||||
|
||||
if constexpr (!std::is_same_v<ResultType, NumberTraits::Error>)
|
||||
return DivideIntegralImpl<A, B>::apply(a, b);
|
||||
else
|
||||
throw Exception("Logical error: the types are not divisable", ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
|
23
dbms/tests/queries/0_stateless/00977_int_div.reference
Normal file
23
dbms/tests/queries/0_stateless/00977_int_div.reference
Normal file
@ -0,0 +1,23 @@
|
||||
-2000 -1 1
|
||||
-1
|
||||
-1
|
||||
-1
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
-1
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
19
dbms/tests/queries/0_stateless/00977_int_div.sql
Normal file
19
dbms/tests/queries/0_stateless/00977_int_div.sql
Normal file
@ -0,0 +1,19 @@
|
||||
SELECT
|
||||
sum(ASD) AS asd,
|
||||
intDiv(toInt64(asd), abs(toInt64(asd))) AS int_div_with_abs,
|
||||
intDiv(toInt64(asd), toInt64(asd)) AS int_div_without_abs
|
||||
FROM
|
||||
(
|
||||
SELECT ASD
|
||||
FROM
|
||||
(
|
||||
SELECT [-1000, -1000] AS asds
|
||||
)
|
||||
ARRAY JOIN asds AS ASD
|
||||
);
|
||||
|
||||
SELECT intDivOrZero( CAST(-1000, 'Int64') , CAST(1000, 'UInt64') );
|
||||
SELECT intDivOrZero( CAST(-1000, 'Int64') , CAST(1000, 'Int64') );
|
||||
|
||||
SELECT intDiv(-1, number) FROM numbers(1, 10);
|
||||
SELECT intDivOrZero(-1, number) FROM numbers(1, 10);
|
Loading…
Reference in New Issue
Block a user