blob: aaea2e4a0b364f5e1980370f351e9f83841d3c10 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use num::BigInt;
use std::any::Any;
use std::sync::Arc;
use crate::array::array_decimal::Decimal256Array;
use crate::array::ArrayRef;
use crate::array::Decimal128Array;
use crate::array::{ArrayBuilder, FixedSizeBinaryBuilder};
use crate::error::{ArrowError, Result};
use crate::datatypes::{validate_decimal256_precision, validate_decimal_precision};
use crate::util::decimal::Decimal256;
/// Array Builder for [`Decimal128Array`]
///
/// See [`Decimal128Array`] for example.
///
#[derive(Debug)]
pub struct Decimal128Builder {
builder: FixedSizeBinaryBuilder,
precision: usize,
scale: usize,
/// Should i128 values be validated for compatibility with scale and precision?
/// defaults to true
value_validation: bool,
}
/// Array Builder for [`Decimal256Array`]
///
/// See [`Decimal256Array`] for example.
#[derive(Debug)]
pub struct Decimal256Builder {
builder: FixedSizeBinaryBuilder,
precision: usize,
scale: usize,
/// Should decimal values be validated for compatibility with scale and precision?
/// defaults to true
value_validation: bool,
}
impl Decimal128Builder {
const BYTE_LENGTH: i32 = 16;
/// Creates a new [`Decimal128Builder`], `capacity` is the number of bytes in the values
/// array
pub fn new(capacity: usize, precision: usize, scale: usize) -> Self {
Self {
builder: FixedSizeBinaryBuilder::new(capacity, Self::BYTE_LENGTH),
precision,
scale,
value_validation: true,
}
}
/// Disable validation
///
/// # Safety
///
/// After disabling validation, caller must ensure that appended values are compatible
/// for the specified precision and scale.
pub unsafe fn disable_value_validation(&mut self) {
self.value_validation = false;
}
/// Appends a decimal value into the builder.
#[inline]
pub fn append_value(&mut self, value: impl Into<i128>) -> Result<()> {
let value = if self.value_validation {
validate_decimal_precision(value.into(), self.precision)?
} else {
value.into()
};
let value_as_bytes =
Self::from_i128_to_fixed_size_bytes(value, Self::BYTE_LENGTH as usize)?;
if Self::BYTE_LENGTH != value_as_bytes.len() as i32 {
return Err(ArrowError::InvalidArgumentError(
"Byte slice does not have the same length as Decimal128Builder value lengths".to_string()
));
}
self.builder.append_value(value_as_bytes.as_slice())
}
pub(crate) fn from_i128_to_fixed_size_bytes(v: i128, size: usize) -> Result<Vec<u8>> {
if size > 16 {
return Err(ArrowError::InvalidArgumentError(
"Decimal128Builder only supports values up to 16 bytes.".to_string(),
));
}
let res = v.to_le_bytes();
let start_byte = 16 - size;
Ok(res[start_byte..16].to_vec())
}
/// Append a null value to the array.
#[inline]
pub fn append_null(&mut self) {
self.builder.append_null()
}
/// Appends an `Option<impl Into<i128>>` into the builder.
#[inline]
pub fn append_option(&mut self, value: Option<impl Into<i128>>) -> Result<()> {
match value {
None => {
self.append_null();
Ok(())
}
Some(value) => self.append_value(value),
}
}
/// Builds the `Decimal128Array` and reset this builder.
pub fn finish(&mut self) -> Decimal128Array {
Decimal128Array::from_fixed_size_binary_array(
self.builder.finish(),
self.precision,
self.scale,
)
}
}
impl ArrayBuilder for Decimal128Builder {
/// Returns the builder as a non-mutable `Any` reference.
fn as_any(&self) -> &dyn Any {
self
}
/// Returns the builder as a mutable `Any` reference.
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
/// Returns the boxed builder as a box of `Any`.
fn into_box_any(self: Box<Self>) -> Box<dyn Any> {
self
}
/// Returns the number of array slots in the builder
fn len(&self) -> usize {
self.builder.len()
}
/// Returns whether the number of array slots is zero
fn is_empty(&self) -> bool {
self.builder.is_empty()
}
/// Builds the array and reset this builder.
fn finish(&mut self) -> ArrayRef {
Arc::new(self.finish())
}
}
impl Decimal256Builder {
const BYTE_LENGTH: i32 = 32;
/// Creates a new [`Decimal256Builder`], `capacity` is the number of bytes in the values
/// array
pub fn new(capacity: usize, precision: usize, scale: usize) -> Self {
Self {
builder: FixedSizeBinaryBuilder::new(capacity, Self::BYTE_LENGTH),
precision,
scale,
value_validation: true,
}
}
/// Disable validation
///
/// # Safety
///
/// After disabling validation, caller must ensure that appended values are compatible
/// for the specified precision and scale.
pub unsafe fn disable_value_validation(&mut self) {
self.value_validation = false;
}
/// Appends a [`Decimal256`] number into the builder.
///
/// Returns an error if `value` has different precision, scale or length in bytes than this builder
#[inline]
pub fn append_value(&mut self, value: &Decimal256) -> Result<()> {
let value = if self.value_validation {
let raw_bytes = value.raw_value();
let integer = BigInt::from_signed_bytes_le(raw_bytes);
validate_decimal256_precision(&integer, self.precision)?;
value
} else {
value
};
if self.precision != value.precision() || self.scale != value.scale() {
return Err(ArrowError::InvalidArgumentError(
"Decimal value does not have the same precision or scale as Decimal256Builder".to_string()
));
}
let value_as_bytes = value.raw_value();
if Self::BYTE_LENGTH != value_as_bytes.len() as i32 {
return Err(ArrowError::InvalidArgumentError(
"Byte slice does not have the same length as Decimal256Builder value lengths".to_string()
));
}
self.builder.append_value(value_as_bytes)
}
/// Append a null value to the array.
#[inline]
pub fn append_null(&mut self) {
self.builder.append_null()
}
/// Appends an `Option<&Decimal256>` into the builder.
#[inline]
pub fn append_option(&mut self, value: Option<&Decimal256>) -> Result<()> {
match value {
None => {
self.append_null();
Ok(())
}
Some(value) => self.append_value(value),
}
}
/// Builds the [`Decimal256Array`] and reset this builder.
pub fn finish(&mut self) -> Decimal256Array {
Decimal256Array::from_fixed_size_binary_array(
self.builder.finish(),
self.precision,
self.scale,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use num::Num;
use crate::array::array_decimal::Decimal128Array;
use crate::array::{array_decimal, Array};
use crate::datatypes::DataType;
use crate::util::decimal::{Decimal128, Decimal256};
#[test]
fn test_decimal_builder() {
let mut builder = Decimal128Builder::new(30, 38, 6);
builder.append_value(8_887_000_000_i128).unwrap();
builder.append_null();
builder.append_value(-8_887_000_000_i128).unwrap();
builder.append_option(None::<i128>).unwrap();
builder.append_option(Some(8_887_000_000_i128)).unwrap();
let decimal_array: Decimal128Array = builder.finish();
assert_eq!(&DataType::Decimal128(38, 6), decimal_array.data_type());
assert_eq!(5, decimal_array.len());
assert_eq!(2, decimal_array.null_count());
assert_eq!(32, decimal_array.value_offset(2));
assert_eq!(16, decimal_array.value_length());
}
#[test]
fn test_decimal_builder_with_decimal128() {
let mut builder = Decimal128Builder::new(30, 38, 6);
builder
.append_value(Decimal128::new_from_i128(30, 38, 8_887_000_000_i128))
.unwrap();
builder.append_null();
builder
.append_value(Decimal128::new_from_i128(30, 38, -8_887_000_000_i128))
.unwrap();
let decimal_array: Decimal128Array = builder.finish();
assert_eq!(&DataType::Decimal128(38, 6), decimal_array.data_type());
assert_eq!(3, decimal_array.len());
assert_eq!(1, decimal_array.null_count());
assert_eq!(32, decimal_array.value_offset(2));
assert_eq!(16, decimal_array.value_length());
}
#[test]
fn test_decimal256_builder() {
let mut builder = Decimal256Builder::new(30, 40, 6);
let mut bytes = [0_u8; 32];
bytes[0..16].clone_from_slice(&8_887_000_000_i128.to_le_bytes());
let value = Decimal256::try_new_from_bytes(40, 6, &bytes).unwrap();
builder.append_value(&value).unwrap();
builder.append_null();
bytes = [255; 32];
let value = Decimal256::try_new_from_bytes(40, 6, &bytes).unwrap();
builder.append_value(&value).unwrap();
bytes = [0; 32];
bytes[0..16].clone_from_slice(&0_i128.to_le_bytes());
bytes[15] = 128;
let value = Decimal256::try_new_from_bytes(40, 6, &bytes).unwrap();
builder.append_value(&value).unwrap();
builder.append_option(None::<&Decimal256>).unwrap();
builder.append_option(Some(&value)).unwrap();
let decimal_array: Decimal256Array = builder.finish();
assert_eq!(&DataType::Decimal256(40, 6), decimal_array.data_type());
assert_eq!(6, decimal_array.len());
assert_eq!(2, decimal_array.null_count());
assert_eq!(64, decimal_array.value_offset(2));
assert_eq!(32, decimal_array.value_length());
assert_eq!(decimal_array.value(0).to_string(), "8887.000000");
assert!(decimal_array.is_null(1));
assert_eq!(decimal_array.value(2).to_string(), "-0.000001");
assert_eq!(
decimal_array.value(3).to_string(),
"170141183460469231731687303715884.105728"
);
}
#[test]
#[should_panic(
expected = "Decimal value does not have the same precision or scale as Decimal256Builder"
)]
fn test_decimal256_builder_unmatched_precision_scale() {
let mut builder = Decimal256Builder::new(30, 10, 6);
let mut bytes = [0_u8; 32];
bytes[0..16].clone_from_slice(&8_887_000_000_i128.to_le_bytes());
let value = Decimal256::try_new_from_bytes(40, 6, &bytes).unwrap();
builder.append_value(&value).unwrap();
}
#[test]
#[should_panic(
expected = "9999999999999999999999999999999999999999999999999999999999999999999999999999 is too large to store in a Decimal256 of precision 75. Max is 999999999999999999999999999999999999999999999999999999999999999999999999999"
)]
fn test_decimal256_builder_out_of_range_precision_scale() {
let mut builder = Decimal256Builder::new(30, 75, 6);
let big_value = BigInt::from_str_radix("9999999999999999999999999999999999999999999999999999999999999999999999999999", 10).unwrap();
let value = Decimal256::from_big_int(&big_value, 75, 6).unwrap();
builder.append_value(&value).unwrap();
}
#[test]
#[should_panic(
expected = "9999999999999999999999999999999999999999999999999999999999999999999999999999 is too large to store in a Decimal256 of precision 75. Max is 999999999999999999999999999999999999999999999999999999999999999999999999999"
)]
fn test_decimal256_data_validation() {
let mut builder = Decimal256Builder::new(30, 75, 6);
// Disable validation at builder
unsafe {
builder.disable_value_validation();
}
let big_value = BigInt::from_str_radix("9999999999999999999999999999999999999999999999999999999999999999999999999999", 10).unwrap();
let value = Decimal256::from_big_int(&big_value, 75, 6).unwrap();
builder
.append_value(&value)
.expect("should not validate invalid value at builder");
let array = builder.finish();
let array_data = array_decimal::BasicDecimalArray::data(&array);
array_data.validate_values().unwrap();
}
}