Skip to content

Commit c500683

Browse files
committed
add support for Decimal128(S)
1 parent f224fed commit c500683

File tree

8 files changed

+94
-33
lines changed

8 files changed

+94
-33
lines changed

src/types/block/builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,6 @@ mod test {
206206
block.columns[14].sql_type(),
207207
SqlType::DateTime(DateTimeType::Chrono)
208208
);
209-
assert_eq!(block.columns[15].sql_type(), SqlType::Decimal(18, 4));
209+
assert_eq!(block.columns[15].sql_type(), SqlType::Decimal(38, 4));
210210
}
211211
}

src/types/column/decimal.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ impl DecimalColumnData {
5252
let type_name = match nobits {
5353
NoBits::N32 => "Int32",
5454
NoBits::N64 => "Int64",
55+
NoBits::N128 => "Int128",
5556
};
5657
let inner =
5758
<dyn ColumnData>::load_data::<BoxColumnWrapper, _>(reader, type_name, size, tz)?;
@@ -161,16 +162,21 @@ impl ColumnData for DecimalColumnData {
161162
let internal: i64 = decimal.internal();
162163
self.inner.push(internal.into())
163164
}
165+
NoBits::N128 => {
166+
let internal: i128 = decimal.internal();
167+
self.inner.push(internal.into())
168+
}
164169
}
165170
} else {
166171
panic!("value should be decimal ({value:?})");
167172
}
168173
}
169174

170175
fn at(&self, index: usize) -> ValueRef {
171-
let underlying: i64 = match self.nobits {
172-
NoBits::N32 => i64::from(i32::from(self.inner.at(index))),
173-
NoBits::N64 => i64::from(self.inner.at(index)),
176+
let underlying: i128 = match self.nobits {
177+
NoBits::N32 => i128::from(i32::from(self.inner.at(index))),
178+
NoBits::N64 => i128::from(i64::from(self.inner.at(index))),
179+
NoBits::N128 => i128::from(self.inner.at(index)),
174180
};
175181

176182
ValueRef::Decimal(Decimal {
@@ -224,6 +230,10 @@ impl<K: ColumnType> ColumnData for DecimalAdapter<K> {
224230
let internal: i64 = decimal.internal();
225231
encoder.write(internal);
226232
}
233+
NoBits::N128 => {
234+
let internal: i128 = decimal.internal();
235+
encoder.write(internal);
236+
}
227237
}
228238
} else {
229239
panic!("should be decimal");
@@ -276,6 +286,9 @@ impl<K: ColumnType> ColumnData for NullableDecimalAdapter<K> {
276286
encoder.write(underlying as i32);
277287
}
278288
NoBits::N64 => {
289+
encoder.write(underlying as i64);
290+
}
291+
NoBits::N128 => {
279292
encoder.write(underlying);
280293
}
281294
}

src/types/column/factory.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ impl dyn ColumnData {
182182
let inner_type = match nobits {
183183
NoBits::N32 => SqlType::Int32,
184184
NoBits::N64 => SqlType::Int64,
185+
NoBits::N128 => SqlType::Int128,
185186
};
186187

187188
W::wrap(DecimalColumnData {
@@ -382,6 +383,7 @@ fn parse_decimal(source: &str) -> Option<(u8, u8, NoBits)> {
382383
let precision = match bits {
383384
NoBits::N32 => 9,
384385
NoBits::N64 => 18,
386+
NoBits::N128 => 38,
385387
};
386388
Some((precision, scale, bits))
387389
}
@@ -554,7 +556,7 @@ mod test {
554556
fn test_parse_decimal() {
555557
assert_eq!(parse_decimal("Decimal(9, 4)"), Some((9, 4, NoBits::N32)));
556558
assert_eq!(parse_decimal("Decimal(10, 4)"), Some((10, 4, NoBits::N64)));
557-
assert_eq!(parse_decimal("Decimal(20, 4)"), None);
559+
assert_eq!(parse_decimal("Decimal(20, 4)"), Some((20, 4, NoBits::N128)));
558560
assert_eq!(parse_decimal("Decimal(2000, 4)"), None);
559561
assert_eq!(parse_decimal("Decimal(3, 4)"), None);
560562
assert_eq!(parse_decimal("Decimal(20, -4)"), None);

src/types/column/iter/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ impl<'a> DecimalIterator<'a> {
309309
unsafe fn next_unchecked_<T>(&mut self) -> Decimal
310310
where
311311
T: Copy + Sized,
312-
i64: From<T>,
312+
i128: From<T>,
313313
{
314314
let current_value = *(self.ptr as *const T);
315315
self.ptr = (self.ptr as *const T).offset(1) as *const u8;
@@ -327,6 +327,7 @@ impl<'a> DecimalIterator<'a> {
327327
match self.nobits {
328328
NoBits::N32 => self.next_unchecked_::<i32>(),
329329
NoBits::N64 => self.next_unchecked_::<i64>(),
330+
NoBits::N128 => self.next_unchecked_::<i128>(),
330331
}
331332
}
332333

@@ -336,6 +337,7 @@ impl<'a> DecimalIterator<'a> {
336337
match self.nobits {
337338
NoBits::N32 => self.ptr = (self.ptr as *const i32).add(n) as *const u8,
338339
NoBits::N64 => self.ptr = (self.ptr as *const i64).add(n) as *const u8,
340+
NoBits::N128 => self.ptr = (self.ptr as *const i128).add(n) as *const u8,
339341
}
340342
}
341343
}
@@ -347,6 +349,7 @@ impl<'a> ExactSizeIterator for DecimalIterator<'a> {
347349
let size = match self.nobits {
348350
NoBits::N32 => mem::size_of::<i32>(),
349351
NoBits::N64 => mem::size_of::<i64>(),
352+
NoBits::N128 => mem::size_of::<i128>(),
350353
};
351354
(self.end as usize - self.ptr as usize) / size
352355
}
@@ -983,6 +986,7 @@ impl<'a> Iterable<'a, Simple> for Decimal {
983986
match nobits {
984987
NoBits::N32 => (ptr as *const u32).add(size) as *const u8,
985988
NoBits::N64 => (ptr as *const u64).add(size) as *const u8,
989+
NoBits::N128 => (ptr as *const u128).add(size) as *const u8,
986990
}
987991
};
988992

src/types/decimal.rs

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{
44
hash::{Hash, Hasher},
55
};
66

7-
static FACTORS10: &[i64] = &[
7+
static FACTORS10: &[i128] = &[
88
1,
99
10,
1010
100,
@@ -24,27 +24,48 @@ static FACTORS10: &[i64] = &[
2424
10_000_000_000_000_000,
2525
100_000_000_000_000_000,
2626
1_000_000_000_000_000_000,
27+
10_000_000_000_000_000_000,
28+
100_000_000_000_000_000_000,
29+
1_000_000_000_000_000_000_000,
30+
10_000_000_000_000_000_000_000,
31+
100_000_000_000_000_000_000_000,
32+
1_000_000_000_000_000_000_000_000,
33+
10_000_000_000_000_000_000_000_000,
34+
100_000_000_000_000_000_000_000_000,
35+
1_000_000_000_000_000_000_000_000_000,
36+
10_000_000_000_000_000_000_000_000_000,
37+
100_000_000_000_000_000_000_000_000_000,
38+
1_000_000_000_000_000_000_000_000_000_000,
39+
10_000_000_000_000_000_000_000_000_000_000,
40+
100_000_000_000_000_000_000_000_000_000_000,
41+
1_000_000_000_000_000_000_000_000_000_000_000,
42+
10_000_000_000_000_000_000_000_000_000_000_000,
43+
100_000_000_000_000_000_000_000_000_000_000_000,
44+
1_000_000_000_000_000_000_000_000_000_000_000_000,
45+
10_000_000_000_000_000_000_000_000_000_000_000_000,
46+
100_000_000_000_000_000_000_000_000_000_000_000_000,
2747
];
2848

2949
pub trait Base {
30-
fn scale(self, scale: i64) -> i64;
50+
fn scale(self, scale: i128) -> i128;
3151
}
3252

3353
pub trait InternalResult {
34-
fn get(underlying: i64) -> Self;
54+
fn get(underlying: i128) -> Self;
3555
}
3656

3757
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
3858
pub(crate) enum NoBits {
3959
N32,
4060
N64,
61+
N128,
4162
}
4263

4364
/// Provides arbitrary-precision floating point decimal.
4465
#[derive(Clone)]
4566
pub struct Decimal {
46-
pub(crate) underlying: i64,
47-
pub(crate) nobits: NoBits, // its domain is {32, 64}
67+
pub(crate) underlying: i128,
68+
pub(crate) nobits: NoBits, // its domain is {32, 64, 128}
4869
pub(crate) precision: u8,
4970
pub(crate) scale: u8,
5071
}
@@ -73,8 +94,8 @@ macro_rules! base_for {
7394
( $( $t:ty: $cast:expr ),* ) => {
7495
$(
7596
impl Base for $t {
76-
fn scale(self, scale: i64) -> i64 {
77-
$cast(self * (scale as $t)) as i64
97+
fn scale(self, scale: i128) -> i128 {
98+
$cast(self * (scale as $t)) as i128
7899
}
79100
}
80101
)*
@@ -84,26 +105,35 @@ macro_rules! base_for {
84105
base_for! {
85106
f32: std::convert::identity,
86107
f64: std::convert::identity,
87-
i8: i64::from,
88-
i16: i64::from,
89-
i32: i64::from,
90-
i64: std::convert::identity,
91-
u8: i64::from,
92-
u16: i64::from,
93-
u32: i64::from,
94-
u64 : std::convert::identity
108+
i8: i128::from,
109+
i16: i128::from,
110+
i32: i128::from,
111+
i64: i128::from,
112+
i128: std::convert::identity,
113+
u8: i128::from,
114+
u16: i128::from,
115+
u32: i128::from,
116+
u64: i128::from,
117+
u128: std::convert::identity
95118
}
96119

97120
impl InternalResult for i32 {
98121
#[inline(always)]
99-
fn get(underlying: i64) -> Self {
122+
fn get(underlying: i128) -> Self {
100123
underlying as Self
101124
}
102125
}
103126

104127
impl InternalResult for i64 {
105128
#[inline(always)]
106-
fn get(underlying: i64) -> Self {
129+
fn get(underlying: i128) -> Self {
130+
underlying as Self
131+
}
132+
}
133+
134+
impl InternalResult for i128 {
135+
#[inline(always)]
136+
fn get(underlying: i128) -> Self {
107137
underlying
108138
}
109139
}
@@ -114,6 +144,8 @@ impl NoBits {
114144
Some(NoBits::N32)
115145
} else if precision <= 18 {
116146
Some(NoBits::N64)
147+
} else if precision <= 38 {
148+
Some(NoBits::N128)
117149
} else {
118150
None
119151
}
@@ -177,8 +209,8 @@ impl From<Decimal> for f64 {
177209

178210
impl Decimal {
179211
/// Method of creating a Decimal.
180-
pub fn new(underlying: i64, scale: u8) -> Decimal {
181-
let precision = 18;
212+
pub fn new(underlying: i128, scale: u8) -> Decimal {
213+
let precision = 38;
182214
if scale > precision {
183215
panic!("scale can't be greater than 18");
184216
}
@@ -192,7 +224,7 @@ impl Decimal {
192224
}
193225

194226
pub fn of<B: Base>(source: B, scale: u8) -> Decimal {
195-
let precision = 18;
227+
let precision = 38;
196228
if scale > precision {
197229
panic!("scale can't be greater than 18");
198230
}
@@ -210,7 +242,7 @@ impl Decimal {
210242
}
211243
}
212244

213-
/// Get the internal representation of decimal as [`i32`] or [`i64`].
245+
/// Get the internal representation of decimal as [`i32`] or [`i64`] or [`i128`].
214246
///
215247
/// example:
216248
/// ```rust
@@ -305,6 +337,12 @@ mod test {
305337
assert_eq!(internal, 20000_i64);
306338
}
307339

340+
#[test]
341+
fn test_internal128() {
342+
let internal: i128 = Decimal::of(2, 4).internal();
343+
assert_eq!(internal, 20000_i128);
344+
}
345+
308346
#[test]
309347
fn test_scale() {
310348
assert_eq!(Decimal::of(2, 4).scale(), 4);

src/types/value.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ mod test {
806806
#[test]
807807
fn test_size_of() {
808808
use std::mem;
809-
assert_eq!(56, mem::size_of::<[Value; 1]>());
809+
assert_eq!(64, mem::size_of::<[Value; 1]>());
810810
}
811811

812812
#[test]

src/types/value_ref.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ mod test {
591591
#[test]
592592
fn test_size_of() {
593593
use std::mem;
594-
assert_eq!(32, mem::size_of::<[ValueRef<'_>; 1]>());
594+
assert_eq!(48, mem::size_of::<[ValueRef<'_>; 1]>());
595595
}
596596

597597
#[test]
@@ -675,7 +675,7 @@ mod test {
675675

676676
assert_eq!(
677677
SqlType::from(ValueRef::Decimal(Decimal::of(2.0_f64, 4))),
678-
SqlType::Decimal(18, 4)
678+
SqlType::Decimal(38, 4)
679679
);
680680

681681
assert_eq!(

tests/clickhouse.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,14 +1712,16 @@ async fn test_decimal() -> Result<(), Error> {
17121712
let ddl = "
17131713
CREATE TABLE clickhouse_decimal (
17141714
x Decimal(8, 3),
1715-
ox Nullable(Decimal(10, 2))
1715+
ox Nullable(Decimal(10, 2)),
1716+
xx Decimal(30, 4)
17161717
) Engine=Memory";
17171718

1718-
let query = "SELECT x, ox FROM clickhouse_decimal";
1719+
let query = "SELECT x, ox, xx FROM clickhouse_decimal";
17191720

17201721
let block = Block::new()
17211722
.column("x", vec![Decimal::of(1.234, 3), Decimal::of(5, 3)])
1722-
.column("ox", vec![None, Some(Decimal::of(1.23, 2))]);
1723+
.column("ox", vec![None, Some(Decimal::of(1.23, 2))])
1724+
.column("xx", vec![Decimal::of(1.23456, 4), Decimal::of(5, 4)]);
17231725

17241726
let pool = Pool::new(database_url());
17251727

@@ -1732,11 +1734,13 @@ async fn test_decimal() -> Result<(), Error> {
17321734
let x: Decimal = block.get(0, "x")?;
17331735
let ox: Option<Decimal> = block.get(1, "ox")?;
17341736
let ox0: Option<Decimal> = block.get(0, "ox")?;
1737+
let xx: Decimal = block.get(0, "xx")?;
17351738

17361739
assert_eq!(2, block.row_count());
17371740
assert_eq!(1.234, x.into());
17381741
assert_eq!(Some(1.23), ox.map(|v| v.into()));
17391742
assert_eq!(None, ox0);
1743+
assert_eq!(1.2345, xx.into());
17401744

17411745
Ok(())
17421746
}

0 commit comments

Comments
 (0)