mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Merge 539b17c693
into 44b4bd38b9
This commit is contained in:
commit
74d8617628
@ -32,9 +32,48 @@ using FunctionNegate = FunctionUnaryArithmetic<NegateImpl, NameNegate, true>;
|
||||
template <> struct FunctionUnaryArithmeticMonotonicity<NameNegate>
|
||||
{
|
||||
static bool has() { return true; }
|
||||
static IFunction::Monotonicity get(const Field &, const Field &)
|
||||
static IFunction::Monotonicity get(const Field & left, const Field & right)
|
||||
{
|
||||
return { .is_monotonic = true, .is_positive = false, .is_strict = true };
|
||||
/// negate(UInt64) -> Int64:
|
||||
/// * monotonically decreases on [0, 2^63] (no overflow),
|
||||
/// * then jumps up from -2^63 to 2^63-1, then
|
||||
/// * monotonically decreases on [2^63+1, 2^64-1] (with overflow).
|
||||
/// Similarly for UInt128 and UInt256.
|
||||
/// Note: we currently don't handle the corner case -UINT64_MIN == UINT64_MIN, and similar for floats and wide signed ints.
|
||||
/// (This implementation seems overcomplicated and not very correct, maybe there's a better way to do it,
|
||||
/// maybe by using the actual IDataType instead of two field types.)
|
||||
|
||||
/// We don't know the data type, assume nonmonotonic.
|
||||
if (left.isNull() && right.isNull())
|
||||
return { .is_monotonic = false, .is_positive = false, .is_strict = true };
|
||||
|
||||
auto which_half_if_unsigned_or_infinity = [](const Field & f, int half_if_null, bool & is_unsigned) -> int
|
||||
{
|
||||
is_unsigned = true;
|
||||
switch (f.getType())
|
||||
{
|
||||
case Field::Types::UInt64: return (f.safeGet<UInt64>() > 1ul << 63) ? +1 : -1;
|
||||
case Field::Types::UInt128: return (f.safeGet<UInt128>() > UInt128(1) << 127) ? +1 : -1;
|
||||
case Field::Types::UInt256: return (f.safeGet<UInt256>() > UInt256(1) << 255) ? +1 : -1;
|
||||
default: break;
|
||||
}
|
||||
is_unsigned = false;
|
||||
if (f.isPositiveInfinity())
|
||||
return +1;
|
||||
if (f.isNegativeInfinity())
|
||||
return -1;
|
||||
if (f.isNull())
|
||||
return half_if_null;
|
||||
return 0;
|
||||
};
|
||||
bool left_is_unsigned, right_is_unsigned;
|
||||
int left_half = which_half_if_unsigned_or_infinity(left, -1, left_is_unsigned);
|
||||
int right_half = which_half_if_unsigned_or_infinity(right, +1, right_is_unsigned);
|
||||
|
||||
bool is_monotonic = true;
|
||||
if (left_is_unsigned || right_is_unsigned)
|
||||
is_monotonic = left_half * right_half >= 0; /// either both values in the same half or unexpected signed-unsigned mix
|
||||
return { .is_monotonic = is_monotonic, .is_positive = false, .is_strict = true };
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,3 @@
|
||||
42
|
||||
42
|
||||
42
|
14
tests/queries/0_stateless/03259_negate_key_overflow.sql
Normal file
14
tests/queries/0_stateless/03259_negate_key_overflow.sql
Normal file
@ -0,0 +1,14 @@
|
||||
create table a (x UInt64) engine MergeTree order by x;
|
||||
insert into a values (12345678901234567890), (42);
|
||||
select * from a where -x = -42;
|
||||
drop table a;
|
||||
|
||||
create table a (x UInt128) engine MergeTree order by x;
|
||||
insert into a values (170141183460469231731687303715884105828), (42);
|
||||
select * from a where -x = -42;
|
||||
drop table a;
|
||||
|
||||
create table a (x UInt256) engine MergeTree order by x;
|
||||
insert into a values (57896044618658097711785492504343953926634992332820282019728792003956564820068), (42);
|
||||
select * from a where -x = -42;
|
||||
drop table a;
|
Loading…
Reference in New Issue
Block a user