Skip to content

Commit d4ed3d0

Browse files
[BugFix] Fix cast from LARGEINT to DECIMAL128 (backport #63559) (#63868)
Signed-off-by: zihe.liu <[email protected]> Co-authored-by: zihe.liu <[email protected]>
1 parent 6cbc74a commit d4ed3d0

File tree

4 files changed

+292
-3
lines changed

4 files changed

+292
-3
lines changed

be/src/exprs/decimal_cast_expr.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,15 @@ struct DecimalNonDecimalCast<overflow_mode, DecimalType, NonDecimalType, Decimal
140140
using NonDecimalColumnType = RunTimeColumnType<NonDecimalType>;
141141

142142
static inline ColumnPtr decimal_from(const ColumnPtr& column, int precision, int scale) {
143+
if (scale == 0) {
144+
return _decimal_from<true>(column, precision, scale);
145+
} else {
146+
return _decimal_from<false>(column, precision, scale);
147+
}
148+
}
149+
150+
template <bool ZeroScale>
151+
static inline ColumnPtr _decimal_from(const ColumnPtr& column, int precision, int scale) {
143152
const auto num_rows = column->size();
144153
auto result = DecimalColumnType::create(precision, scale, num_rows);
145154
const auto data = &ColumnHelper::cast_to_raw<NonDecimalType>(column)->get_data().front();
@@ -163,9 +172,16 @@ struct DecimalNonDecimalCast<overflow_mode, DecimalType, NonDecimalType, Decimal
163172
DecimalV3Cast::from_integer<SignedBooleanType, DecimalCppType, check_overflow<overflow_mode>>(
164173
(SignedBooleanType)(data[i]), scale_factor, &result_data[i]);
165174
} else if constexpr (lt_is_integer<NonDecimalType>) {
166-
overflow =
167-
DecimalV3Cast::from_integer<NonDecimalCppType, DecimalCppType, check_overflow<overflow_mode>>(
168-
data[i], scale_factor, &result_data[i]);
175+
if constexpr (ZeroScale) {
176+
// Fast path for integer-to-decimal conversion with scale 0.
177+
overflow =
178+
DecimalV3Cast::to_decimal_trivial<NonDecimalCppType, DecimalCppType,
179+
check_overflow<overflow_mode>>(data[i], &result_data[i]);
180+
} else {
181+
overflow = DecimalV3Cast::from_integer<NonDecimalCppType, DecimalCppType,
182+
check_overflow<overflow_mode>>(data[i], scale_factor,
183+
&result_data[i]);
184+
}
169185
} else if constexpr (lt_is_float<NonDecimalType>) {
170186
overflow = DecimalV3Cast::from_float<NonDecimalCppType, DecimalCppType>(data[i], scale_factor,
171187
&result_data[i]);
@@ -218,6 +234,7 @@ struct DecimalNonDecimalCast<overflow_mode, DecimalType, NonDecimalType, Decimal
218234
}
219235
}
220236
}
237+
221238
if constexpr (check_overflow<overflow_mode>) {
222239
ColumnBuilder<DecimalType> builder(result, null_column, has_null);
223240
return builder.build(column->is_constant());

be/src/runtime/int128_arithmetics_x86_64.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,14 @@ static inline int64_t i32_x_i32_produce_i64(int32_t a, int32_t b) {
210210
}
211211

212212
static inline int multi3(const int128_t& x, const int128_t& y, int128_t& res) {
213+
// This algorithm mistakenly treats `INT128_MIN * 1` as an overflow, because `abs(INT128_MIN)` remains `INT128_MIN`,
214+
// which causes `asm_add` to detect `SF=1`. Therefore, we add a special case here to bypass this issue.
215+
if (UNLIKELY((x == std::numeric_limits<int128_t>::min() && y == 1) ||
216+
(y == std::numeric_limits<int128_t>::min() && x == 1))) {
217+
res = std::numeric_limits<int128_t>::min();
218+
return 0;
219+
}
220+
213221
// sgn(x)
214222
auto sx = x >> 127;
215223
// sgn(y)
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
-- name: test_decimal_cast
2+
CREATE TABLE t1 (
3+
k1 bigint NULL,
4+
5+
c_tinyint tinyint null,
6+
c_int int null,
7+
c_bigint bigint null,
8+
c_largeint largeint null
9+
) ENGINE=OLAP
10+
DUPLICATE KEY(`k1`)
11+
DISTRIBUTED BY HASH(`k1`) BUCKETS 96
12+
PROPERTIES (
13+
"replication_num" = "1"
14+
);
15+
-- result:
16+
-- !result
17+
insert into t1 values
18+
(1, 127, 2147483647, 9223372036854775807, 170141183460469231731687303715884105727),
19+
(2, -128, -2147483648, -9223372036854775808, -170141183460469231731687303715884105728),
20+
(3, null, null, null, null),
21+
(4, 0, 0, 0, 0),
22+
(5, 1, 1, 1, 1),
23+
(6, -1, -1, -1, -1),
24+
(7, 12, 214748364, 922337203685477580, 17014118346046923173168730371588410572),
25+
(8, -12, -214748364, -922337203685477580, -17014118346046923173168730371588410572);
26+
-- result:
27+
-- !result
28+
select
29+
k1,
30+
cast(c_tinyint as DECIMAL(9,0)),
31+
cast(c_int as DECIMAL(9,0)),
32+
cast(c_bigint as DECIMAL(9,0)),
33+
cast(c_largeint as DECIMAL(9,0))
34+
from t1
35+
order by k1;
36+
-- result:
37+
1 127 2147483647 9223372036854775807 None
38+
2 -128 -2147483648 -9223372036854775808 None
39+
3 None None None None
40+
4 0 0 0 0
41+
5 1 1 1 1
42+
6 -1 -1 -1 -1
43+
7 12 214748364 922337203685477580 None
44+
8 -12 -214748364 -922337203685477580 None
45+
-- !result
46+
select
47+
k1,
48+
cast(c_tinyint as DECIMAL(9,1)),
49+
cast(c_int as DECIMAL(9,1)),
50+
cast(c_bigint as DECIMAL(9,1)),
51+
cast(c_largeint as DECIMAL(9,1))
52+
from t1
53+
order by k1;
54+
-- result:
55+
1 127.0 2147483647.0 None None
56+
2 -128.0 -2147483648.0 None None
57+
3 None None None None
58+
4 0.0 0.0 0.0 0.0
59+
5 1.0 1.0 1.0 1.0
60+
6 -1.0 -1.0 -1.0 -1.0
61+
7 12.0 214748364.0 922337203685477580.0 None
62+
8 -12.0 -214748364.0 -922337203685477580.0 None
63+
-- !result
64+
select
65+
k1,
66+
cast(c_tinyint as DECIMAL(27,0)),
67+
cast(c_int as DECIMAL(27,0)),
68+
cast(c_bigint as DECIMAL(27,0)),
69+
cast(c_largeint as DECIMAL(27,0))
70+
from t1
71+
order by k1;
72+
-- result:
73+
1 127 2147483647 9223372036854775807 170141183460469231731687303715884105727
74+
2 -128 -2147483648 -9223372036854775808 -170141183460469231731687303715884105728
75+
3 None None None None
76+
4 0 0 0 0
77+
5 1 1 1 1
78+
6 -1 -1 -1 -1
79+
7 12 214748364 922337203685477580 17014118346046923173168730371588410572
80+
8 -12 -214748364 -922337203685477580 -17014118346046923173168730371588410572
81+
-- !result
82+
select
83+
k1,
84+
cast(c_tinyint as DECIMAL(27,1)),
85+
cast(c_int as DECIMAL(27,1)),
86+
cast(c_bigint as DECIMAL(27,1)),
87+
cast(c_largeint as DECIMAL(27,1))
88+
from t1
89+
order by k1;
90+
-- result:
91+
1 127.0 2147483647.0 9223372036854775807.0 None
92+
2 -128.0 -2147483648.0 -9223372036854775808.0 None
93+
3 None None None None
94+
4 0.0 0.0 0.0 0.0
95+
5 1.0 1.0 1.0 1.0
96+
6 -1.0 -1.0 -1.0 -1.0
97+
7 12.0 214748364.0 922337203685477580.0 17014118346046923173168730371588410572.0
98+
8 -12.0 -214748364.0 -922337203685477580.0 -17014118346046923173168730371588410572.0
99+
-- !result
100+
select
101+
k1,
102+
cast(c_tinyint as DECIMAL(38,0)),
103+
cast(c_int as DECIMAL(38,0)),
104+
cast(c_bigint as DECIMAL(38,0)),
105+
cast(c_largeint as DECIMAL(38,0))
106+
from t1
107+
order by k1;
108+
-- result:
109+
1 127 2147483647 9223372036854775807 170141183460469231731687303715884105727
110+
2 -128 -2147483648 -9223372036854775808 -170141183460469231731687303715884105728
111+
3 None None None None
112+
4 0 0 0 0
113+
5 1 1 1 1
114+
6 -1 -1 -1 -1
115+
7 12 214748364 922337203685477580 17014118346046923173168730371588410572
116+
8 -12 -214748364 -922337203685477580 -17014118346046923173168730371588410572
117+
-- !result
118+
select
119+
k1,
120+
cast(c_tinyint as DECIMAL(38,1)),
121+
cast(c_int as DECIMAL(38,1)),
122+
cast(c_bigint as DECIMAL(38,1)),
123+
cast(c_largeint as DECIMAL(38,1))
124+
from t1
125+
order by k1;
126+
-- result:
127+
1 127.0 2147483647.0 9223372036854775807.0 None
128+
2 -128.0 -2147483648.0 -9223372036854775808.0 None
129+
3 None None None None
130+
4 0.0 0.0 0.0 0.0
131+
5 1.0 1.0 1.0 1.0
132+
6 -1.0 -1.0 -1.0 -1.0
133+
7 12.0 214748364.0 922337203685477580.0 17014118346046923173168730371588410572.0
134+
8 -12.0 -214748364.0 -922337203685477580.0 -17014118346046923173168730371588410572.0
135+
-- !result
136+
select k1, c_tinyint * 0, c_int * 0, c_bigint * 0, c_largeint * 0 from t1 order by k1;
137+
-- result:
138+
1 0 0 0 0
139+
2 0 0 0 0
140+
3 None None None None
141+
4 0 0 0 0
142+
5 0 0 0 0
143+
6 0 0 0 0
144+
7 0 0 0 0
145+
8 0 0 0 0
146+
-- !result
147+
select k1, c_tinyint * 1, c_int * 1, c_bigint * 1, c_largeint * 1 from t1 order by k1;
148+
-- result:
149+
1 127 2147483647 9223372036854775807 170141183460469231731687303715884105727
150+
2 -128 -2147483648 -9223372036854775808 -170141183460469231731687303715884105728
151+
3 None None None None
152+
4 0 0 0 0
153+
5 1 1 1 1
154+
6 -1 -1 -1 -1
155+
7 12 214748364 922337203685477580 17014118346046923173168730371588410572
156+
8 -12 -214748364 -922337203685477580 -17014118346046923173168730371588410572
157+
-- !result
158+
select k1, cast(c_tinyint * 0 as decimal(38, 0)), cast(c_int * 0 as decimal(38, 0)), cast(c_bigint * 0 as decimal(38, 0)), cast(c_largeint * 0 as decimal(38, 0)) from t1 order by k1;
159+
-- result:
160+
1 0 0 0 0
161+
2 0 0 0 0
162+
3 None None None None
163+
4 0 0 0 0
164+
5 0 0 0 0
165+
6 0 0 0 0
166+
7 0 0 0 0
167+
8 0 0 0 0
168+
-- !result
169+
select k1, cast(c_tinyint * 1 as decimal(38, 0)), cast(c_int * 1 as decimal(38, 0)), cast(c_bigint * 1 as decimal(38, 0)), cast(c_largeint * 1 as decimal(38, 0)) from t1 order by k1;
170+
-- result:
171+
1 127 2147483647 9223372036854775807 170141183460469231731687303715884105727
172+
2 -128 -2147483648 -9223372036854775808 -170141183460469231731687303715884105728
173+
3 None None None None
174+
4 0 0 0 0
175+
5 1 1 1 1
176+
6 -1 -1 -1 -1
177+
7 12 214748364 922337203685477580 17014118346046923173168730371588410572
178+
8 -12 -214748364 -922337203685477580 -17014118346046923173168730371588410572
179+
-- !result
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
-- name: test_decimal_cast
2+
3+
CREATE TABLE t1 (
4+
k1 bigint NULL,
5+
6+
c_tinyint tinyint null,
7+
c_int int null,
8+
c_bigint bigint null,
9+
c_largeint largeint null
10+
) ENGINE=OLAP
11+
DUPLICATE KEY(`k1`)
12+
DISTRIBUTED BY HASH(`k1`) BUCKETS 96
13+
PROPERTIES (
14+
"replication_num" = "1"
15+
);
16+
17+
insert into t1 values
18+
(1, 127, 2147483647, 9223372036854775807, 170141183460469231731687303715884105727),
19+
(2, -128, -2147483648, -9223372036854775808, -170141183460469231731687303715884105728),
20+
(3, null, null, null, null),
21+
(4, 0, 0, 0, 0),
22+
(5, 1, 1, 1, 1),
23+
(6, -1, -1, -1, -1),
24+
(7, 12, 214748364, 922337203685477580, 17014118346046923173168730371588410572),
25+
(8, -12, -214748364, -922337203685477580, -17014118346046923173168730371588410572);
26+
27+
select
28+
k1,
29+
cast(c_tinyint as DECIMAL(9,0)),
30+
cast(c_int as DECIMAL(9,0)),
31+
cast(c_bigint as DECIMAL(9,0)),
32+
cast(c_largeint as DECIMAL(9,0))
33+
from t1
34+
order by k1;
35+
36+
select
37+
k1,
38+
cast(c_tinyint as DECIMAL(9,1)),
39+
cast(c_int as DECIMAL(9,1)),
40+
cast(c_bigint as DECIMAL(9,1)),
41+
cast(c_largeint as DECIMAL(9,1))
42+
from t1
43+
order by k1;
44+
45+
select
46+
k1,
47+
cast(c_tinyint as DECIMAL(27,0)),
48+
cast(c_int as DECIMAL(27,0)),
49+
cast(c_bigint as DECIMAL(27,0)),
50+
cast(c_largeint as DECIMAL(27,0))
51+
from t1
52+
order by k1;
53+
54+
select
55+
k1,
56+
cast(c_tinyint as DECIMAL(27,1)),
57+
cast(c_int as DECIMAL(27,1)),
58+
cast(c_bigint as DECIMAL(27,1)),
59+
cast(c_largeint as DECIMAL(27,1))
60+
from t1
61+
order by k1;
62+
63+
select
64+
k1,
65+
cast(c_tinyint as DECIMAL(38,0)),
66+
cast(c_int as DECIMAL(38,0)),
67+
cast(c_bigint as DECIMAL(38,0)),
68+
cast(c_largeint as DECIMAL(38,0))
69+
from t1
70+
order by k1;
71+
72+
select
73+
k1,
74+
cast(c_tinyint as DECIMAL(38,1)),
75+
cast(c_int as DECIMAL(38,1)),
76+
cast(c_bigint as DECIMAL(38,1)),
77+
cast(c_largeint as DECIMAL(38,1))
78+
from t1
79+
order by k1;
80+
81+
select k1, c_tinyint * 0, c_int * 0, c_bigint * 0, c_largeint * 0 from t1 order by k1;
82+
select k1, c_tinyint * 1, c_int * 1, c_bigint * 1, c_largeint * 1 from t1 order by k1;
83+
84+
select k1, cast(c_tinyint * 0 as decimal(38, 0)), cast(c_int * 0 as decimal(38, 0)), cast(c_bigint * 0 as decimal(38, 0)), cast(c_largeint * 0 as decimal(38, 0)) from t1 order by k1;
85+
select k1, cast(c_tinyint * 1 as decimal(38, 0)), cast(c_int * 1 as decimal(38, 0)), cast(c_bigint * 1 as decimal(38, 0)), cast(c_largeint * 1 as decimal(38, 0)) from t1 order by k1;

0 commit comments

Comments
 (0)