fresh-borzoni commented on code in PR #175:
URL: https://github.com/apache/fluss-rust/pull/175#discussion_r2702397531
##########
crates/fluss/src/row/column.rs:
##########
@@ -126,6 +126,105 @@ impl InternalRow for ColumnarRow {
.value(self.row_id)
}
+ fn get_decimal(&self, pos: usize, precision: usize, scale: usize) ->
bigdecimal::BigDecimal {
+ use arrow::datatypes::DataType;
+
+ let column = self.record_batch.column(pos);
+ let array = column
+ .as_any()
+ .downcast_ref::<Decimal128Array>()
+ .unwrap_or_else(|| {
+ panic!(
+ "Expected Decimal128Array at column {}, found: {:?}",
+ pos,
+ column.data_type()
+ )
+ });
+
+ // Null check: InternalRow trait doesn't return Result, so this would
be UB
+ debug_assert!(
+ !array.is_null(self.row_id),
+ "get_decimal called on null value at pos {} row {}",
+ pos,
+ self.row_id
+ );
+
+ // Read precision/scale from schema field metadata (version-safe
approach)
+ let schema = self.record_batch.schema();
+ let field = schema.field(pos);
+ let (arrow_precision, arrow_scale) = match field.data_type() {
+ DataType::Decimal128(p, s) => (*p as usize, *s as i64),
+ dt => panic!(
+ "Expected Decimal128 data type at column {}, found: {:?}",
+ pos, dt
+ ),
+ };
+
+ // Validate Arrow precision matches schema (scale may differ due to
schema evolution)
+ debug_assert_eq!(
+ arrow_precision, precision,
+ "Arrow Decimal128 precision ({}) doesn't match schema precision
({})",
+ arrow_precision, precision
+ );
+
+ let i128_val = array.value(self.row_id);
+
+ // Construct BigDecimal with Arrow's scale
+ let bd = bigdecimal::BigDecimal::new(
+ bigdecimal::num_bigint::BigInt::from(i128_val),
+ arrow_scale,
+ );
+
+ // Rescale if needed (matches Java's Decimal.fromBigDecimal behavior)
+ let result = if arrow_scale != scale as i64 {
+ use bigdecimal::rounding::RoundingMode;
+ bd.with_scale_round(scale as i64, RoundingMode::HalfUp)
+ } else {
+ bd
+ };
+
+ // Validate precision after rescale (matches Java: if (bd.precision()
> precision) throw)
+ // Use Java's precision rules: strip trailing zeros, count significant
digits
+ let (unscaled, _) = result.as_bigint_and_exponent();
+ let actual_precision = {
+ use bigdecimal::num_traits::Zero;
+ if unscaled.is_zero() {
+ 1
+ } else {
+ let s = unscaled.magnitude().to_str_radix(10);
+ let trimmed = s.trim_end_matches('0');
+ trimmed.len()
+ }
+ };
+
+ if actual_precision > precision {
+ panic!(
+ "Decimal precision overflow at column {} row {}: value {} has
{} digits but precision is {}",
+ pos, self.row_id, result, actual_precision, precision
+ );
+ }
+
+ result
+ }
+
+ fn get_date(&self, pos: usize) -> i32 {
+ self.get_int(pos)
+ }
+
+ fn get_time(&self, pos: usize) -> i32 {
+ self.get_int(pos)
+ }
+
+ fn get_timestamp_ntz(&self, pos: usize) -> crate::row::datum::Timestamp {
+ let millis = self.get_long(pos);
+ crate::row::datum::Timestamp::new(millis)
Review Comment:
yes, missed that, thank you!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]