1use std::sync::Arc;
7
8use arrow_array::ArrayRef;
9use arrow_array::builder::Decimal128Builder;
10
11use crate::Result;
12use crate::traits::builder::HanaCompatibleBuilder;
13use crate::traits::sealed::private::Sealed;
14use crate::types::hana::{DecimalPrecision, DecimalScale};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct DecimalConfig {
21 precision: DecimalPrecision,
22 scale: DecimalScale,
23}
24
25impl DecimalConfig {
26 pub fn new(precision: u8, scale: i8) -> Result<Self> {
32 let prec = DecimalPrecision::new(precision)?;
33 let scl = DecimalScale::new(scale, prec)?;
34 Ok(Self {
35 precision: prec,
36 scale: scl,
37 })
38 }
39
40 #[must_use]
42 pub const fn precision(&self) -> u8 {
43 self.precision.value()
44 }
45
46 #[must_use]
48 pub const fn scale(&self) -> i8 {
49 self.scale.value()
50 }
51}
52
53#[derive(Debug)]
57pub struct Decimal128BuilderWrapper {
58 builder: Decimal128Builder,
59 config: DecimalConfig,
60 len: usize,
61}
62
63impl Decimal128BuilderWrapper {
64 #[must_use]
76 pub fn new(capacity: usize, precision: u8, scale: i8) -> Self {
77 let config = DecimalConfig::new(precision, scale)
78 .expect("decimal config should be validated before builder creation");
79
80 let builder = Decimal128Builder::with_capacity(capacity)
81 .with_data_type(arrow_schema::DataType::Decimal128(precision, scale));
82
83 Self {
84 builder,
85 config,
86 len: 0,
87 }
88 }
89
90 #[must_use]
92 pub fn from_config(capacity: usize, config: DecimalConfig) -> Self {
93 let builder = Decimal128Builder::with_capacity(capacity).with_data_type(
94 arrow_schema::DataType::Decimal128(config.precision(), config.scale()),
95 );
96
97 Self {
98 builder,
99 config,
100 len: 0,
101 }
102 }
103
104 fn convert_decimal(&self, value: &hdbconnect::HdbValue) -> Result<i128> {
121 use hdbconnect::HdbValue;
122 use num_bigint::BigInt;
123 use num_traits::ToPrimitive;
124
125 match value {
126 HdbValue::DECIMAL(decimal) => {
127 let (mantissa, exponent) = decimal.as_bigint_and_exponent();
128 let target_scale = i64::from(self.config.scale());
129
130 let scale_diff = target_scale - exponent;
136
137 let scaled_value = if scale_diff >= 0 {
138 let exp = u32::try_from(scale_diff).map_err(|_| {
141 crate::ArrowConversionError::decimal_overflow(
142 self.config.precision(),
143 self.config.scale(),
144 )
145 })?;
146 let multiplier = BigInt::from(10_i128).pow(exp);
147 &mantissa * &multiplier
148 } else {
149 let exp = u32::try_from(-scale_diff).map_err(|_| {
151 crate::ArrowConversionError::decimal_overflow(
152 self.config.precision(),
153 self.config.scale(),
154 )
155 })?;
156 let divisor = BigInt::from(10_i128).pow(exp);
157 &mantissa / &divisor
158 };
159
160 scaled_value.to_i128().ok_or_else(|| {
161 crate::ArrowConversionError::decimal_overflow(
162 self.config.precision(),
163 self.config.scale(),
164 )
165 })
166 }
167 other => Err(crate::ArrowConversionError::value_conversion(
168 "decimal",
169 format!("expected DECIMAL, got {:?}", std::mem::discriminant(other)),
170 )),
171 }
172 }
173}
174
175impl Sealed for Decimal128BuilderWrapper {}
176
177impl HanaCompatibleBuilder for Decimal128BuilderWrapper {
178 fn append_hana_value(&mut self, value: &hdbconnect::HdbValue) -> Result<()> {
179 let i128_val = self.convert_decimal(value)?;
180 self.builder.append_value(i128_val);
181 self.len += 1;
182 Ok(())
183 }
184
185 fn append_null(&mut self) {
186 self.builder.append_null();
187 self.len += 1;
188 }
189
190 fn finish(&mut self) -> ArrayRef {
191 self.len = 0;
192 Arc::new(self.builder.finish())
193 }
194
195 fn len(&self) -> usize {
196 self.len
197 }
198
199 fn capacity(&self) -> Option<usize> {
200 Some(self.builder.capacity())
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use arrow_array::Array;
207
208 use super::*;
209
210 #[test]
215 fn test_decimal_config_valid() {
216 let config = DecimalConfig::new(18, 2).unwrap();
217 assert_eq!(config.precision(), 18);
218 assert_eq!(config.scale(), 2);
219 }
220
221 #[test]
222 fn test_decimal_config_invalid_precision() {
223 assert!(DecimalConfig::new(0, 0).is_err());
224 assert!(DecimalConfig::new(39, 0).is_err());
225 }
226
227 #[test]
228 fn test_decimal_config_invalid_scale() {
229 assert!(DecimalConfig::new(18, -1).is_err());
230 assert!(DecimalConfig::new(18, 20).is_err());
231 }
232
233 #[test]
234 fn test_decimal_config_min_precision() {
235 let config = DecimalConfig::new(1, 0).unwrap();
236 assert_eq!(config.precision(), 1);
237 assert_eq!(config.scale(), 0);
238 }
239
240 #[test]
241 fn test_decimal_config_max_precision() {
242 let config = DecimalConfig::new(38, 10).unwrap();
243 assert_eq!(config.precision(), 38);
244 assert_eq!(config.scale(), 10);
245 }
246
247 #[test]
248 fn test_decimal_config_scale_equals_precision() {
249 let config = DecimalConfig::new(5, 5).unwrap();
250 assert_eq!(config.precision(), 5);
251 assert_eq!(config.scale(), 5);
252 }
253
254 #[test]
255 fn test_decimal_config_zero_scale() {
256 let config = DecimalConfig::new(10, 0).unwrap();
257 assert_eq!(config.precision(), 10);
258 assert_eq!(config.scale(), 0);
259 }
260
261 #[test]
262 fn test_decimal_config_equality() {
263 let config1 = DecimalConfig::new(18, 2).unwrap();
264 let config2 = DecimalConfig::new(18, 2).unwrap();
265 let config3 = DecimalConfig::new(18, 3).unwrap();
266 assert_eq!(config1, config2);
267 assert_ne!(config1, config3);
268 }
269
270 #[test]
271 fn test_decimal_config_copy() {
272 let config1 = DecimalConfig::new(18, 2).unwrap();
273 let config2 = config1;
274 assert_eq!(config1, config2);
275 }
276
277 #[test]
282 fn test_decimal_builder_creation() {
283 let builder = Decimal128BuilderWrapper::new(100, 18, 2);
284 assert_eq!(builder.len(), 0);
285 assert_eq!(builder.config.precision(), 18);
286 assert_eq!(builder.config.scale(), 2);
287 }
288
289 #[test]
290 fn test_decimal_builder_from_config() {
291 let config = DecimalConfig::new(10, 4).unwrap();
292 let builder = Decimal128BuilderWrapper::from_config(50, config);
293 assert_eq!(builder.len(), 0);
294 assert_eq!(builder.config.precision(), 10);
295 assert_eq!(builder.config.scale(), 4);
296 }
297
298 #[test]
299 fn test_decimal_builder_capacity() {
300 let builder = Decimal128BuilderWrapper::new(100, 18, 2);
301 assert!(builder.capacity().is_some());
302 }
303
304 #[test]
305 fn test_decimal_builder_is_empty() {
306 let builder = Decimal128BuilderWrapper::new(10, 18, 2);
307 assert!(builder.is_empty());
308 }
309
310 #[test]
315 fn test_decimal_builder_append_null() {
316 let mut builder = Decimal128BuilderWrapper::new(10, 18, 2);
317 builder.append_null();
318 assert_eq!(builder.len(), 1);
319
320 let array = builder.finish();
321 assert!(array.is_null(0));
322 }
323
324 #[test]
325 fn test_decimal_builder_multiple_nulls() {
326 let mut builder = Decimal128BuilderWrapper::new(10, 18, 2);
327 builder.append_null();
328 builder.append_null();
329 builder.append_null();
330 assert_eq!(builder.len(), 3);
331
332 let array = builder.finish();
333 assert_eq!(array.len(), 3);
334 assert!(array.is_null(0));
335 assert!(array.is_null(1));
336 assert!(array.is_null(2));
337 }
338
339 #[test]
344 fn test_decimal_builder_finish_resets_len() {
345 let mut builder = Decimal128BuilderWrapper::new(10, 18, 2);
346 builder.append_null();
347 builder.append_null();
348 assert_eq!(builder.len(), 2);
349
350 let _ = builder.finish();
351 assert_eq!(builder.len(), 0);
352 }
353
354 #[test]
355 fn test_decimal_builder_finish_empty() {
356 let mut builder = Decimal128BuilderWrapper::new(10, 18, 2);
357 let array = builder.finish();
358 assert_eq!(array.len(), 0);
359 }
360
361 #[test]
362 fn test_decimal_builder_reuse_after_finish() {
363 let mut builder = Decimal128BuilderWrapper::new(10, 18, 2);
364 builder.append_null();
365 let array1 = builder.finish();
366 assert_eq!(array1.len(), 1);
367
368 builder.append_null();
369 builder.append_null();
370 let array2 = builder.finish();
371 assert_eq!(array2.len(), 2);
372 }
373
374 #[test]
379 fn test_decimal_builder_high_precision() {
380 let builder = Decimal128BuilderWrapper::new(10, 38, 10);
381 assert_eq!(builder.config.precision(), 38);
382 assert_eq!(builder.config.scale(), 10);
383 }
384
385 #[test]
386 fn test_decimal_builder_low_precision() {
387 let builder = Decimal128BuilderWrapper::new(10, 1, 0);
388 assert_eq!(builder.config.precision(), 1);
389 assert_eq!(builder.config.scale(), 0);
390 }
391
392 #[test]
393 fn test_decimal_builder_zero_scale() {
394 let builder = Decimal128BuilderWrapper::new(10, 10, 0);
395 assert_eq!(builder.config.precision(), 10);
396 assert_eq!(builder.config.scale(), 0);
397 }
398
399 #[test]
400 fn test_decimal_builder_scale_equals_precision() {
401 let builder = Decimal128BuilderWrapper::new(10, 5, 5);
402 assert_eq!(builder.config.precision(), 5);
403 assert_eq!(builder.config.scale(), 5);
404 }
405
406 #[test]
411 fn test_decimal_builder_len_increments() {
412 let mut builder = Decimal128BuilderWrapper::new(10, 18, 2);
413 assert_eq!(builder.len(), 0);
414 builder.append_null();
415 assert_eq!(builder.len(), 1);
416 builder.append_null();
417 assert_eq!(builder.len(), 2);
418 }
419
420 #[test]
421 fn test_decimal_builder_reset() {
422 let mut builder = Decimal128BuilderWrapper::new(10, 18, 2);
423 builder.append_null();
424 builder.append_null();
425 assert_eq!(builder.len(), 2);
426
427 builder.reset();
428 assert_eq!(builder.len(), 0);
429 assert!(builder.is_empty());
430 }
431
432 #[cfg(feature = "test-utils")]
437 mod convert_decimal_tests {
438 use arrow_array::Decimal128Array;
439
440 use super::*;
441 use crate::traits::row::MockRowBuilder;
442
443 fn convert_and_get_value(precision: u8, scale: i8, decimal_str: &str) -> i128 {
445 let mut builder = Decimal128BuilderWrapper::new(10, precision, scale);
446 let row = MockRowBuilder::new().decimal_str(decimal_str).build();
447 builder.append_hana_value(&row[0]).unwrap();
448 let array = builder.finish();
449 let decimal_array = array.as_any().downcast_ref::<Decimal128Array>().unwrap();
450 decimal_array.value(0)
451 }
452
453 #[test]
458 fn test_convert_decimal_simple_value() {
459 let value = convert_and_get_value(18, 2, "123.45");
461 assert_eq!(value, 12345);
462 }
463
464 #[test]
465 fn test_convert_decimal_integer_value() {
466 let value = convert_and_get_value(10, 0, "100");
468 assert_eq!(value, 100);
469 }
470
471 #[test]
472 fn test_convert_decimal_large_value() {
473 let value = convert_and_get_value(18, 2, "9999999.99");
475 assert_eq!(value, 999999999);
476 }
477
478 #[test]
483 fn test_convert_decimal_scale_up_integer_to_decimal() {
484 let value = convert_and_get_value(10, 2, "100");
486 assert_eq!(value, 10000);
487 }
488
489 #[test]
490 fn test_convert_decimal_scale_up_by_one() {
491 let value = convert_and_get_value(10, 2, "123.4");
493 assert_eq!(value, 12340);
494 }
495
496 #[test]
497 fn test_convert_decimal_scale_up_by_multiple() {
498 let value = convert_and_get_value(10, 4, "5");
500 assert_eq!(value, 50000);
501 }
502
503 #[test]
508 fn test_convert_decimal_scale_down_truncate() {
509 let value = convert_and_get_value(10, 2, "123.456");
511 assert_eq!(value, 12345);
512 }
513
514 #[test]
515 fn test_convert_decimal_scale_down_to_integer() {
516 let value = convert_and_get_value(10, 0, "123.99");
518 assert_eq!(value, 123);
519 }
520
521 #[test]
522 fn test_convert_decimal_scale_down_multiple_places() {
523 let value = convert_and_get_value(18, 2, "1.23456789");
525 assert_eq!(value, 123);
526 }
527
528 #[test]
533 fn test_convert_decimal_scale_match_exact() {
534 let value = convert_and_get_value(18, 2, "123.45");
536 assert_eq!(value, 12345);
537 }
538
539 #[test]
540 fn test_convert_decimal_scale_match_high_scale() {
541 let value = convert_and_get_value(38, 18, "1.234567890123456789");
543 assert_eq!(value, 1_234_567_890_123_456_789_i128);
544 }
545
546 #[test]
551 fn test_convert_decimal_negative_simple() {
552 let value = convert_and_get_value(18, 2, "-123.45");
554 assert_eq!(value, -12345);
555 }
556
557 #[test]
558 fn test_convert_decimal_negative_scale_up() {
559 let value = convert_and_get_value(10, 2, "-100");
561 assert_eq!(value, -10000);
562 }
563
564 #[test]
565 fn test_convert_decimal_negative_scale_down() {
566 let value = convert_and_get_value(10, 2, "-123.456");
568 assert_eq!(value, -12345);
569 }
570
571 #[test]
572 fn test_convert_decimal_negative_large() {
573 let value = convert_and_get_value(18, 2, "-9999999.99");
575 assert_eq!(value, -999999999);
576 }
577
578 #[test]
583 fn test_convert_decimal_zero() {
584 let value = convert_and_get_value(10, 2, "0");
585 assert_eq!(value, 0);
586 }
587
588 #[test]
589 fn test_convert_decimal_zero_with_scale() {
590 let value = convert_and_get_value(10, 2, "0.00");
592 assert_eq!(value, 0);
593 }
594
595 #[test]
596 fn test_convert_decimal_negative_zero() {
597 let value = convert_and_get_value(10, 2, "-0");
599 assert_eq!(value, 0);
600 }
601
602 #[test]
607 fn test_convert_decimal_max_precision_integer() {
608 let value = convert_and_get_value(38, 0, "99999999999999999999999999999999999999");
612 assert_eq!(
613 value,
614 99_999_999_999_999_999_999_999_999_999_999_999_999_i128
615 );
616 }
617
618 #[test]
619 fn test_convert_decimal_max_precision_with_scale() {
620 let value = convert_and_get_value(38, 4, "9999999999999999999999999999999999.9999");
623 assert_eq!(
624 value,
625 99_999_999_999_999_999_999_999_999_999_999_999_999_i128
626 );
627 }
628
629 #[test]
630 fn test_convert_decimal_i128_max_boundary() {
631 let value = convert_and_get_value(38, 0, "170141183460469231731687303715884105727");
634 assert_eq!(value, i128::MAX);
635 }
636
637 #[test]
638 fn test_convert_decimal_i128_min_boundary() {
639 let value = convert_and_get_value(38, 0, "-170141183460469231731687303715884105728");
642 assert_eq!(value, i128::MIN);
643 }
644
645 #[test]
650 fn test_convert_decimal_overflow_scale_up() {
651 let mut builder = Decimal128BuilderWrapper::new(10, 38, 10);
654 let row = MockRowBuilder::new()
656 .decimal_str("17014118346046923173168730371588410573")
657 .build();
658 let result = builder.append_hana_value(&row[0]);
659 assert!(result.is_err());
660 }
661
662 #[test]
663 fn test_convert_decimal_overflow_large_value() {
664 let mut builder = Decimal128BuilderWrapper::new(10, 38, 0);
666 let row = MockRowBuilder::new()
668 .decimal_str("999999999999999999999999999999999999999")
669 .build();
670 let result = builder.append_hana_value(&row[0]);
671 assert!(result.is_err());
672 }
673
674 #[test]
679 fn test_convert_decimal_wrong_type_int() {
680 let mut builder = Decimal128BuilderWrapper::new(10, 18, 2);
681 let row = MockRowBuilder::new().int(42).build();
682 let result = builder.append_hana_value(&row[0]);
683 assert!(result.is_err());
684 }
685
686 #[test]
687 fn test_convert_decimal_wrong_type_string() {
688 let mut builder = Decimal128BuilderWrapper::new(10, 18, 2);
689 let row = MockRowBuilder::new().string("123.45").build();
690 let result = builder.append_hana_value(&row[0]);
691 assert!(result.is_err());
692 }
693
694 #[test]
695 fn test_convert_decimal_wrong_type_null() {
696 let mut builder = Decimal128BuilderWrapper::new(10, 18, 2);
697 let row = MockRowBuilder::new().null().build();
698 let result = builder.append_hana_value(&row[0]);
699 assert!(result.is_err());
702 }
703
704 #[test]
705 fn test_convert_decimal_wrong_type_double() {
706 let mut builder = Decimal128BuilderWrapper::new(10, 18, 2);
707 let row = MockRowBuilder::new().double(123.45).build();
708 let result = builder.append_hana_value(&row[0]);
709 assert!(result.is_err());
710 }
711
712 #[test]
717 fn test_convert_decimal_very_small_value() {
718 let value = convert_and_get_value(18, 8, "0.00000001");
720 assert_eq!(value, 1);
721 }
722
723 #[test]
724 fn test_convert_decimal_leading_zeros() {
725 let value = convert_and_get_value(18, 2, "00123.45");
727 assert_eq!(value, 12345);
728 }
729
730 #[test]
731 fn test_convert_decimal_trailing_zeros() {
732 let value = convert_and_get_value(18, 2, "123.450");
734 assert_eq!(value, 12345);
735 }
736
737 #[test]
738 fn test_convert_decimal_scientific_notation() {
739 let value = convert_and_get_value(10, 0, "1.23e2");
741 assert_eq!(value, 123);
742 }
743
744 #[test]
745 fn test_convert_decimal_scientific_notation_negative_exp() {
746 let value = convert_and_get_value(10, 0, "12300e-2");
748 assert_eq!(value, 123);
749 }
750 }
751}