vortex_array/arrays/decimal/
mod.rs1mod compute;
5mod narrow;
6mod ops;
7mod patch;
8mod serde;
9
10use arrow_buffer::BooleanBufferBuilder;
11use vortex_buffer::{Buffer, BufferMut, ByteBuffer};
12use vortex_dtype::{DType, DecimalDType};
13use vortex_error::{VortexExpect, VortexResult, vortex_ensure, vortex_panic};
14use vortex_scalar::{DecimalValueType, NativeDecimalType};
15
16pub use crate::arrays::decimal::narrow::narrowed_decimal;
17use crate::builders::ArrayBuilder;
18use crate::stats::{ArrayStats, StatsSetRef};
19use crate::validity::Validity;
20use crate::vtable::{
21 ArrayVTable, CanonicalVTable, NotSupported, VTable, ValidityHelper,
22 ValidityVTableFromValidityHelper, VisitorVTable,
23};
24use crate::{ArrayBufferVisitor, ArrayChildVisitor, Canonical, EncodingId, EncodingRef, vtable};
25
26vtable!(Decimal);
27
28impl VTable for DecimalVTable {
29 type Array = DecimalArray;
30 type Encoding = DecimalEncoding;
31
32 type ArrayVTable = Self;
33 type CanonicalVTable = Self;
34 type OperationsVTable = Self;
35 type ValidityVTable = ValidityVTableFromValidityHelper;
36 type VisitorVTable = Self;
37 type ComputeVTable = NotSupported;
38 type EncodeVTable = NotSupported;
39 type PipelineVTable = NotSupported;
40 type SerdeVTable = Self;
41
42 fn id(_encoding: &Self::Encoding) -> EncodingId {
43 EncodingId::new_ref("vortex.decimal")
44 }
45
46 fn encoding(_array: &Self::Array) -> EncodingRef {
47 EncodingRef::new_ref(DecimalEncoding.as_ref())
48 }
49}
50
51#[derive(Clone, Debug)]
52pub struct DecimalEncoding;
53
54pub fn smallest_storage_type(decimal_dtype: &DecimalDType) -> DecimalValueType {
56 match decimal_dtype.precision() {
57 1..=2 => DecimalValueType::I8,
58 3..=4 => DecimalValueType::I16,
59 5..=9 => DecimalValueType::I32,
60 10..=18 => DecimalValueType::I64,
61 19..=38 => DecimalValueType::I128,
62 39..=76 => DecimalValueType::I256,
63 0 => unreachable!("precision must be greater than 0"),
64 p => unreachable!("precision larger than 76 is invalid found precision {p}"),
65 }
66}
67
68pub fn compatible_storage_type(value_type: DecimalValueType, dtype: DecimalDType) -> bool {
70 value_type >= smallest_storage_type(&dtype)
71}
72
73#[derive(Clone, Debug)]
131pub struct DecimalArray {
132 dtype: DType,
133 values: ByteBuffer,
134 values_type: DecimalValueType,
135 validity: Validity,
136 stats_set: ArrayStats,
137}
138
139impl DecimalArray {
140 pub fn new<T: NativeDecimalType>(
147 buffer: Buffer<T>,
148 decimal_dtype: DecimalDType,
149 validity: Validity,
150 ) -> Self {
151 Self::try_new(buffer, decimal_dtype, validity)
152 .vortex_expect("DecimalArray construction failed")
153 }
154
155 pub fn try_new<T: NativeDecimalType>(
164 buffer: Buffer<T>,
165 decimal_dtype: DecimalDType,
166 validity: Validity,
167 ) -> VortexResult<Self> {
168 Self::validate(&buffer, &validity)?;
169
170 Ok(unsafe { Self::new_unchecked(buffer, decimal_dtype, validity) })
172 }
173
174 pub unsafe fn new_unchecked<T: NativeDecimalType>(
188 buffer: Buffer<T>,
189 decimal_dtype: DecimalDType,
190 validity: Validity,
191 ) -> Self {
192 Self {
193 values: buffer.into_byte_buffer(),
194 values_type: T::VALUES_TYPE,
195 dtype: DType::Decimal(decimal_dtype, validity.nullability()),
196 validity,
197 stats_set: Default::default(),
198 }
199 }
200
201 pub(crate) fn validate<T: NativeDecimalType>(
205 buffer: &Buffer<T>,
206 validity: &Validity,
207 ) -> VortexResult<()> {
208 if let Some(len) = validity.maybe_len() {
209 vortex_ensure!(
210 buffer.len() == len,
211 "Buffer and validity length mismatch: buffer={}, validity={}",
212 buffer.len(),
213 len,
214 );
215 }
216
217 Ok(())
218 }
219
220 pub fn byte_buffer(&self) -> ByteBuffer {
222 self.values.clone()
223 }
224
225 pub fn buffer<T: NativeDecimalType>(&self) -> Buffer<T> {
226 if self.values_type != T::VALUES_TYPE {
227 vortex_panic!(
228 "Cannot extract Buffer<{:?}> for DecimalArray with values_type {:?}",
229 T::VALUES_TYPE,
230 self.values_type,
231 );
232 }
233 Buffer::<T>::from_byte_buffer(self.values.clone())
234 }
235
236 pub fn decimal_dtype(&self) -> DecimalDType {
238 if let DType::Decimal(decimal_dtype, _) = self.dtype {
239 decimal_dtype
240 } else {
241 vortex_panic!("Expected Decimal dtype, got {:?}", self.dtype)
242 }
243 }
244
245 pub fn values_type(&self) -> DecimalValueType {
246 self.values_type
247 }
248
249 pub fn precision(&self) -> u8 {
250 self.decimal_dtype().precision()
251 }
252
253 pub fn scale(&self) -> i8 {
254 self.decimal_dtype().scale()
255 }
256
257 pub fn from_option_iter<T: NativeDecimalType, I: IntoIterator<Item = Option<T>>>(
258 iter: I,
259 decimal_dtype: DecimalDType,
260 ) -> Self {
261 let iter = iter.into_iter();
262 let mut values = BufferMut::with_capacity(iter.size_hint().0);
263 let mut validity = BooleanBufferBuilder::new(values.capacity());
264
265 for i in iter {
266 match i {
267 None => {
268 validity.append(false);
269 values.push(T::default());
270 }
271 Some(e) => {
272 validity.append(true);
273 values.push(e);
274 }
275 }
276 }
277 Self::new(
278 values.freeze(),
279 decimal_dtype,
280 Validity::from(validity.finish()),
281 )
282 }
283}
284
285impl ArrayVTable<DecimalVTable> for DecimalVTable {
286 fn len(array: &DecimalArray) -> usize {
287 let divisor = match array.values_type {
288 DecimalValueType::I8 => 1,
289 DecimalValueType::I16 => 2,
290 DecimalValueType::I32 => 4,
291 DecimalValueType::I64 => 8,
292 DecimalValueType::I128 => 16,
293 DecimalValueType::I256 => 32,
294 ty => vortex_panic!("unknown decimal value type {:?}", ty),
295 };
296 array.values.len() / divisor
297 }
298
299 fn dtype(array: &DecimalArray) -> &DType {
300 &array.dtype
301 }
302
303 fn stats(array: &DecimalArray) -> StatsSetRef<'_> {
304 array.stats_set.to_ref(array.as_ref())
305 }
306}
307
308impl VisitorVTable<DecimalVTable> for DecimalVTable {
309 fn visit_buffers(array: &DecimalArray, visitor: &mut dyn ArrayBufferVisitor) {
310 visitor.visit_buffer(&array.values);
311 }
312
313 fn visit_children(array: &DecimalArray, visitor: &mut dyn ArrayChildVisitor) {
314 visitor.visit_validity(array.validity(), array.len())
315 }
316}
317
318impl CanonicalVTable<DecimalVTable> for DecimalVTable {
319 fn canonicalize(array: &DecimalArray) -> Canonical {
320 Canonical::Decimal(array.clone())
321 }
322
323 fn append_to_builder(array: &DecimalArray, builder: &mut dyn ArrayBuilder) {
324 builder.extend_from_array(array.as_ref())
325 }
326}
327
328impl ValidityHelper for DecimalArray {
329 fn validity(&self) -> &Validity {
330 &self.validity
331 }
332}
333
334#[cfg(test)]
335mod test {
336 use arrow_array::Decimal128Array;
337
338 #[test]
339 fn test_decimal() {
340 let value = Decimal128Array::new_null(100);
343 let numeric = value.value(10);
344 assert_eq!(numeric, 0i128);
345 }
346}