Fixed UBSan; added a test

This commit is contained in:
Alexey Milovidov 2020-04-26 17:57:45 +03:00
parent d1464a441f
commit a70637ab4b
3 changed files with 30 additions and 15 deletions

View File

@ -2,15 +2,20 @@
// Moved Decimal-related functions out from Core/Types.h to reduce compilation time.
#include <Core/Types.h>
#include <Common/intExp.h>
#include <Common/Exception.h>
#include <common/arithmeticOverflow.h>
#include <limits>
class DateLUTImpl;
namespace DB
{
namespace ErrorCodes
{
extern const int DECIMAL_OVERFLOW;
}
namespace DecimalUtils
{
@ -37,22 +42,26 @@ struct DecimalComponents
};
/** Make a decimal value from whole and fractional components with given scale multiplier.
* where scale_multiplier = scaleMultiplier<T>(scale)
* this is to reduce number of calls to scaleMultiplier when scale is known.
*
* Sign of `whole` controls sign of result: negative whole => negative result, positive whole => positive result.
* Sign of `fractional` is expected to be positive, otherwise result is undefined.
* If `scale` is to big (scale > maxPrecision<DecimalType::NativeType>), result is undefined.
*/
* where scale_multiplier = scaleMultiplier<T>(scale)
* this is to reduce number of calls to scaleMultiplier when scale is known.
*
* Sign of `whole` controls sign of result: negative whole => negative result, positive whole => positive result.
* Sign of `fractional` is expected to be positive, otherwise result is undefined.
* If `scale` is to big (scale > maxPrecision<DecimalType::NativeType>), result is undefined.
*/
template <typename DecimalType>
DecimalType decimalFromComponentsWithMultiplier(const typename DecimalType::NativeType & whole,
const typename DecimalType::NativeType & fractional,
typename DecimalType::NativeType scale_multiplier)
const typename DecimalType::NativeType & fractional,
typename DecimalType::NativeType scale_multiplier)
{
using T = typename DecimalType::NativeType;
const auto fractional_sign = whole < 0 ? -1 : 1;
const T value = whole * scale_multiplier + fractional_sign * (fractional % scale_multiplier);
T whole_scaled = 0;
if (common::mulOverflow(whole, scale_multiplier, whole_scaled))
throw Exception("Decimal math overflow", ErrorCodes::DECIMAL_OVERFLOW);
const T value = whole_scaled + fractional_sign * (fractional % scale_multiplier);
return DecimalType(value);
}
@ -61,7 +70,8 @@ DecimalType decimalFromComponentsWithMultiplier(const typename DecimalType::Nati
* @see `decimalFromComponentsWithMultiplier` for details.
*/
template <typename DecimalType>
DecimalType decimalFromComponents(const typename DecimalType::NativeType & whole, const typename DecimalType::NativeType & fractional, UInt32 scale)
DecimalType decimalFromComponents(
const typename DecimalType::NativeType & whole, const typename DecimalType::NativeType & fractional, UInt32 scale)
{
using T = typename DecimalType::NativeType;
@ -72,7 +82,8 @@ DecimalType decimalFromComponents(const typename DecimalType::NativeType & whole
* @see `decimalFromComponentsWithMultiplier` for details.
*/
template <typename DecimalType>
DecimalType decimalFromComponents(const DecimalComponents<typename DecimalType::NativeType> & components, UInt32 scale)
DecimalType decimalFromComponents(
const DecimalComponents<typename DecimalType::NativeType> & components, UInt32 scale)
{
return decimalFromComponents<DecimalType>(components.whole, components.fractional, scale);
}
@ -81,7 +92,8 @@ DecimalType decimalFromComponents(const DecimalComponents<typename DecimalType::
* This is an optimization to reduce number of calls to scaleMultiplier on known scale.
*/
template <typename DecimalType>
DecimalComponents<typename DecimalType::NativeType> splitWithScaleMultiplier(const DecimalType & decimal, typename DecimalType::NativeType scale_multiplier)
DecimalComponents<typename DecimalType::NativeType> splitWithScaleMultiplier(
const DecimalType & decimal, typename DecimalType::NativeType scale_multiplier)
{
using T = typename DecimalType::NativeType;
const auto whole = decimal.value / scale_multiplier;

View File

@ -0,0 +1 @@
29

View File

@ -0,0 +1,2 @@
select now64(10); -- { serverError 407 }
select length(toString(now64(9)));