1use std::{fmt::Debug, marker::PhantomData, sync::Arc};
5
6use arrow_array::{
7 Array, ArrayRef, ArrowPrimitiveType, FixedSizeBinaryArray, GenericByteArray, PrimitiveArray,
8 builder::{
9 ArrayBuilder, BooleanBuilder, FixedSizeBinaryBuilder, GenericByteBuilder, LargeBinaryBuilder,
10 LargeStringBuilder, NullBuilder, PrimitiveBuilder,
11 },
12 types::{
13 ByteArrayType, Date32Type, Decimal128Type, Decimal256Type, Float32Type, Float64Type, Int8Type,
14 Int16Type, Int32Type, Int64Type, IntervalMonthDayNanoType, Time64NanosecondType,
15 TimestampNanosecondType, UInt8Type, UInt16Type, UInt32Type, UInt64Type,
16 },
17};
18use arrow_buffer::{Buffer, NullBuffer, bit_util, i256};
19use arrow_schema::FieldRef;
20use reifydb_value::{
21 Result,
22 value::{
23 column_view::{ColumnView, ViewData},
24 constraint::{bytes::MaxBytes, precision::Precision, scale::Scale},
25 container::{
26 decimal_array::{self, DECIMAL128_MAX_PRECISION, DecimalArray, DecimalView, decimal_at},
27 dictionary_array::DICTIONARY_ENTRY_WIDTH,
28 temporal_array::datetime_timezone,
29 uuid_array::UUID_WIDTH,
30 varlen_array,
31 wide_int_array::WideInt,
32 },
33 decimal::{Decimal, unscaled},
34 dictionary::DictionaryId,
35 value_type::{
36 ValueType,
37 field::{FieldType, named},
38 },
39 },
40};
41
42use crate::{internal_err, internal_error, value::column::push::Push};
43
44#[derive(Debug)]
45pub enum DecimalBuilder {
46 Decimal128 {
47 builder: PrimitiveBuilder<Decimal128Type>,
48 precision: Precision,
49 scale: Scale,
50 },
51 Decimal256 {
52 builder: PrimitiveBuilder<Decimal256Type>,
53 precision: Precision,
54 scale: Scale,
55 },
56}
57
58impl DecimalBuilder {
59 pub fn with_capacity(precision: Precision, scale: Scale, capacity: usize) -> Self {
60 let data_type = decimal_array::data_type(precision, scale);
61 if precision.value() <= DECIMAL128_MAX_PRECISION {
62 DecimalBuilder::Decimal128 {
63 builder: PrimitiveBuilder::with_capacity(capacity).with_data_type(data_type),
64 precision,
65 scale,
66 }
67 } else {
68 DecimalBuilder::Decimal256 {
69 builder: PrimitiveBuilder::with_capacity(capacity).with_data_type(data_type),
70 precision,
71 scale,
72 }
73 }
74 }
75
76 pub(crate) fn from_array(array: DecimalArray) -> Self {
77 let (precision, scale) = (array.precision(), array.scale());
78 match array {
79 DecimalArray::Decimal128(array) => DecimalBuilder::Decimal128 {
80 builder: primitive_builder(array),
81 precision,
82 scale,
83 },
84 DecimalArray::Decimal256(array) => DecimalBuilder::Decimal256 {
85 builder: primitive_builder(array),
86 precision,
87 scale,
88 },
89 }
90 }
91
92 pub fn precision(&self) -> Precision {
93 match self {
94 DecimalBuilder::Decimal128 {
95 precision,
96 ..
97 }
98 | DecimalBuilder::Decimal256 {
99 precision,
100 ..
101 } => *precision,
102 }
103 }
104
105 pub fn scale(&self) -> Scale {
106 match self {
107 DecimalBuilder::Decimal128 {
108 scale,
109 ..
110 }
111 | DecimalBuilder::Decimal256 {
112 scale,
113 ..
114 } => *scale,
115 }
116 }
117
118 pub fn len(&self) -> usize {
119 match self {
120 DecimalBuilder::Decimal128 {
121 builder,
122 ..
123 } => builder.len(),
124 DecimalBuilder::Decimal256 {
125 builder,
126 ..
127 } => builder.len(),
128 }
129 }
130
131 pub fn is_empty(&self) -> bool {
132 self.len() == 0
133 }
134
135 pub fn finish(&mut self) -> DecimalArray {
136 match self {
137 DecimalBuilder::Decimal128 {
138 builder,
139 ..
140 } => DecimalArray::Decimal128(builder.finish()),
141 DecimalBuilder::Decimal256 {
142 builder,
143 ..
144 } => DecimalArray::Decimal256(builder.finish()),
145 }
146 }
147
148 pub(crate) fn append_null(&mut self) {
149 match self {
150 DecimalBuilder::Decimal128 {
151 builder,
152 ..
153 } => builder.append_null(),
154 DecimalBuilder::Decimal256 {
155 builder,
156 ..
157 } => builder.append_null(),
158 }
159 }
160
161 pub fn push(&mut self, value: &Decimal) {
162 if let Some(fitted) = value.fits(self.precision().value(), self.scale().value()) {
163 return self.append_fitting(fitted.unscaled());
164 }
165 let fitted = self.widen_for(value);
166 self.append_fitting(fitted.unscaled());
167 }
168
169 pub(crate) fn append_array(&mut self, array: DecimalView<'_>) {
170 match (self, array) {
171 (
172 DecimalBuilder::Decimal128 {
173 builder,
174 precision,
175 scale,
176 },
177 DecimalView::Decimal128(array),
178 ) if array.precision() == precision.value() && array.scale() as u8 == scale.value() => builder.append_array(array),
179 (
180 DecimalBuilder::Decimal256 {
181 builder,
182 precision,
183 scale,
184 },
185 DecimalView::Decimal256(array),
186 ) if array.precision() == precision.value() && array.scale() as u8 == scale.value() => builder.append_array(array),
187 (this, array) => {
188 let nulls = decimal_nulls(array);
189 for index in 0..array.len() {
190 if nulls.as_ref().is_some_and(|nulls| nulls.is_null(index)) {
191 this.append_null();
192 continue;
193 }
194 let value = decimal_at(array, index).expect("index is below the array length");
195 this.push(&value);
196 }
197 }
198 }
199 }
200
201 fn append_fitting(&mut self, unscaled: i256) {
202 match self {
203 DecimalBuilder::Decimal128 {
204 builder,
205 ..
206 } => builder.append_value(unscaled.to_i128().expect("a value within precision 38 fits i128")),
207 DecimalBuilder::Decimal256 {
208 builder,
209 ..
210 } => builder.append_value(unscaled),
211 }
212 }
213
214 fn widen_for(&mut self, value: &Decimal) -> Decimal {
215 let (precision, scale) = (self.precision().value(), self.scale().value());
216 let finished = self.finish();
217 let nulls = decimal_nulls(&finished);
218 let existing: Vec<Decimal> = finished
219 .unscaled_values()
220 .into_iter()
221 .map(|unscaled| {
222 Decimal::from_parts(unscaled, scale)
223 .expect("a decimal builder holds only valid decimals")
224 })
225 .collect();
226 let integer_digits = |decimal: &Decimal| decimal.digits().saturating_sub(decimal.scale());
227 let needed = existing.iter().chain([value]).map(integer_digits).max().unwrap_or(0);
228 let wide_scale = scale.max(value.scale()).min(unscaled::MAX_DIGITS - needed);
229 let round = |decimal: &Decimal| {
230 decimal.round_to_scale(wide_scale)
231 .expect("rounding never adds a whole digit past the widest value")
232 };
233 let rounded: Vec<Decimal> = existing.iter().map(round).collect();
234 let fitted = round(value);
235 let wide_precision = ((precision - scale).max(needed) + wide_scale).min(unscaled::MAX_DIGITS);
236 let mut widened = DecimalBuilder::with_capacity(
237 Precision::new(wide_precision),
238 Scale::new(wide_scale),
239 rounded.len() + 1,
240 );
241 for (index, decimal) in rounded.into_iter().enumerate() {
242 match nulls.as_ref().is_some_and(|nulls| nulls.is_null(index)) {
243 true => widened.append_null(),
244 false => widened.append_fitting(decimal.unscaled()),
245 }
246 }
247 *self = widened;
248 fitted
249 }
250}
251
252fn decimal_nulls<'a>(array: impl Into<DecimalView<'a>>) -> Option<NullBuffer> {
253 array.into().array().logical_nulls()
254}
255
256#[derive(Debug)]
257pub struct WideBuilder<T: WideInt> {
258 builder: FixedSizeBinaryBuilder,
259 marker: PhantomData<T>,
260}
261
262impl<T: WideInt> WideBuilder<T> {
263 pub(crate) fn with_capacity(capacity: usize) -> Self {
264 Self {
265 builder: FixedSizeBinaryBuilder::with_capacity(capacity, T::WIDTH as i32),
266 marker: PhantomData,
267 }
268 }
269
270 pub(crate) fn from_array(array: &FixedSizeBinaryArray) -> Self {
271 Self {
272 builder: fixed_size_builder(array),
273 marker: PhantomData,
274 }
275 }
276
277 pub(crate) fn append_null(&mut self) {
278 let mut row = [0u8; 16];
279 T::default().to_ordered(&mut row);
280 let null_row = FixedSizeBinaryArray::new(
281 T::WIDTH as i32,
282 Buffer::from(row[..T::WIDTH].to_vec()),
283 Some(NullBuffer::new_null(1)),
284 );
285 append_fixed_array(&mut self.builder, &null_row)
286 .expect("a null row of the builder width always appends");
287 }
288
289 pub(crate) fn append_value(&mut self, value: T) {
290 let mut row = [0u8; 16];
291 value.to_ordered(&mut row);
292 append_fixed(&mut self.builder, &row);
293 }
294
295 pub(crate) fn append_array(&mut self, array: &FixedSizeBinaryArray) -> Result<()> {
296 append_fixed_array(&mut self.builder, array)
297 }
298
299 pub(crate) fn len(&self) -> usize {
300 self.builder.len()
301 }
302
303 pub(crate) fn finish(&mut self) -> FixedSizeBinaryArray {
304 self.builder.finish()
305 }
306}
307
308#[derive(Debug)]
309pub struct ColumnBuilder {
310 pub(crate) inner: TypedBuilder,
311 pub(crate) optional: bool,
312}
313
314#[derive(Debug)]
315pub enum TypedBuilder {
316 Bool(BooleanBuilder),
317 Int1(PrimitiveBuilder<Int8Type>),
318 Int2(PrimitiveBuilder<Int16Type>),
319 Int4(PrimitiveBuilder<Int32Type>),
320 Int8(PrimitiveBuilder<Int64Type>),
321 Int16(WideBuilder<i128>),
322 Uint1(PrimitiveBuilder<UInt8Type>),
323 Uint2(PrimitiveBuilder<UInt16Type>),
324 Uint4(PrimitiveBuilder<UInt32Type>),
325 Uint8(PrimitiveBuilder<UInt64Type>),
326 Uint16(WideBuilder<u128>),
327 Float4(PrimitiveBuilder<Float32Type>),
328 Float8(PrimitiveBuilder<Float64Type>),
329 Date(PrimitiveBuilder<Date32Type>),
330 DateTime(PrimitiveBuilder<TimestampNanosecondType>),
331 Time(PrimitiveBuilder<Time64NanosecondType>),
332 Duration(PrimitiveBuilder<IntervalMonthDayNanoType>),
333 IdentityId(FixedSizeBinaryBuilder),
334 Uuid4(FixedSizeBinaryBuilder),
335 Uuid7(FixedSizeBinaryBuilder),
336 DictionaryId {
337 builder: FixedSizeBinaryBuilder,
338 dictionary_id: Option<DictionaryId>,
339 },
340 Utf8 {
341 builder: LargeStringBuilder,
342 max_bytes: MaxBytes,
343 },
344 Blob {
345 builder: LargeBinaryBuilder,
346 max_bytes: MaxBytes,
347 },
348 Decimal(DecimalBuilder),
349 Any {
350 builder: LargeBinaryBuilder,
351 declared_type: Option<ValueType>,
352 },
353 Digest {
354 builder: LargeBinaryBuilder,
355 inner: ValueType,
356 accuracy: u32,
357 },
358 None(NullBuilder),
359}
360
361impl ColumnBuilder {
362 pub fn with_capacity(target: ValueType, capacity: usize) -> Self {
363 let inner = match target {
364 ValueType::Option(inner) => {
365 return ColumnBuilder {
366 optional: true,
367 ..ColumnBuilder::with_capacity(*inner, capacity)
368 };
369 }
370 ValueType::Boolean => TypedBuilder::Bool(BooleanBuilder::with_capacity(capacity)),
371 ValueType::Int1 => TypedBuilder::Int1(PrimitiveBuilder::with_capacity(capacity)),
372 ValueType::Int2 => TypedBuilder::Int2(PrimitiveBuilder::with_capacity(capacity)),
373 ValueType::Int4 => TypedBuilder::Int4(PrimitiveBuilder::with_capacity(capacity)),
374 ValueType::Int8 => TypedBuilder::Int8(PrimitiveBuilder::with_capacity(capacity)),
375 ValueType::Int16 => TypedBuilder::Int16(WideBuilder::with_capacity(capacity)),
376 ValueType::Uint1 => TypedBuilder::Uint1(PrimitiveBuilder::with_capacity(capacity)),
377 ValueType::Uint2 => TypedBuilder::Uint2(PrimitiveBuilder::with_capacity(capacity)),
378 ValueType::Uint4 => TypedBuilder::Uint4(PrimitiveBuilder::with_capacity(capacity)),
379 ValueType::Uint8 => TypedBuilder::Uint8(PrimitiveBuilder::with_capacity(capacity)),
380 ValueType::Uint16 => TypedBuilder::Uint16(WideBuilder::with_capacity(capacity)),
381 ValueType::Float4 => TypedBuilder::Float4(PrimitiveBuilder::with_capacity(capacity)),
382 ValueType::Float8 => TypedBuilder::Float8(PrimitiveBuilder::with_capacity(capacity)),
383 ValueType::Date => TypedBuilder::Date(PrimitiveBuilder::with_capacity(capacity)),
384 ValueType::DateTime => TypedBuilder::DateTime(
385 PrimitiveBuilder::<TimestampNanosecondType>::with_capacity(capacity)
386 .with_timezone(datetime_timezone()),
387 ),
388 ValueType::Time => TypedBuilder::Time(PrimitiveBuilder::with_capacity(capacity)),
389 ValueType::Duration => TypedBuilder::Duration(PrimitiveBuilder::with_capacity(capacity)),
390 ValueType::IdentityId => TypedBuilder::IdentityId(FixedSizeBinaryBuilder::with_capacity(
391 capacity,
392 UUID_WIDTH as i32,
393 )),
394 ValueType::Uuid4 => {
395 TypedBuilder::Uuid4(FixedSizeBinaryBuilder::with_capacity(capacity, UUID_WIDTH as i32))
396 }
397 ValueType::Uuid7 => {
398 TypedBuilder::Uuid7(FixedSizeBinaryBuilder::with_capacity(capacity, UUID_WIDTH as i32))
399 }
400 ValueType::DictionaryId => TypedBuilder::DictionaryId {
401 builder: FixedSizeBinaryBuilder::with_capacity(capacity, DICTIONARY_ENTRY_WIDTH as i32),
402 dictionary_id: None,
403 },
404 ValueType::Utf8 => TypedBuilder::Utf8 {
405 builder: LargeStringBuilder::with_capacity(capacity, capacity * 16),
406 max_bytes: MaxBytes::MAX,
407 },
408 ValueType::Blob => TypedBuilder::Blob {
409 builder: LargeBinaryBuilder::with_capacity(capacity, capacity * 32),
410 max_bytes: MaxBytes::MAX,
411 },
412 ValueType::Decimal {
413 precision,
414 scale,
415 } => TypedBuilder::Decimal(DecimalBuilder::with_capacity(precision, scale, capacity)),
416 ValueType::Any | ValueType::Tuple(_) => TypedBuilder::Any {
417 builder: LargeBinaryBuilder::with_capacity(capacity, 0),
418 declared_type: None,
419 },
420 declared @ (ValueType::List(_) | ValueType::Record(_)) => TypedBuilder::Any {
421 builder: LargeBinaryBuilder::with_capacity(capacity, 0),
422 declared_type: Some(declared),
423 },
424 ValueType::Digest {
425 inner,
426 accuracy,
427 } => TypedBuilder::Digest {
428 builder: LargeBinaryBuilder::with_capacity(capacity, 0),
429 inner: *inner,
430 accuracy,
431 },
432 };
433 ColumnBuilder {
434 inner,
435 optional: false,
436 }
437 }
438
439 pub fn like(view: &ColumnView, capacity: usize) -> Self {
440 if view.is_none() {
441 return ColumnBuilder::untyped_none();
442 }
443 let mut builder = ColumnBuilder::with_capacity(view.get_type(), capacity);
444 builder.copy_details(&view.data);
445 builder
446 }
447
448 pub fn from_view(view: &ColumnView) -> Self {
449 ColumnBuilder {
450 inner: TypedBuilder::from_view(&view.data),
451 optional: view.is_nullable() || view.none_count() > 0,
452 }
453 }
454
455 pub(crate) fn untyped_none() -> Self {
456 ColumnBuilder {
457 inner: TypedBuilder::None(NullBuilder::new()),
458 optional: true,
459 }
460 }
461
462 pub fn inner(&self) -> &TypedBuilder {
463 &self.inner
464 }
465
466 pub fn push<T>(&mut self, value: T)
467 where
468 ColumnBuilder: Push<T>,
469 T: Debug,
470 {
471 <Self as Push<T>>::push(self, value)
472 }
473
474 pub fn set_dictionary_id(&mut self, id: DictionaryId) {
475 if let TypedBuilder::DictionaryId {
476 dictionary_id,
477 ..
478 } = &mut self.inner
479 {
480 *dictionary_id = Some(id);
481 }
482 }
483
484 pub fn dictionary_id(&self) -> Option<DictionaryId> {
485 match &self.inner {
486 TypedBuilder::DictionaryId {
487 dictionary_id,
488 ..
489 } => *dictionary_id,
490 _ => None,
491 }
492 }
493
494 pub fn extend(&mut self, other: &ColumnView) -> Result<()> {
495 match (self.is_untyped_none(), other.is_untyped_none()) {
496 (true, true) => {
497 let len = self.len() + other.len();
498 *self = ColumnBuilder::untyped_none();
499 self.append_nones(len);
500 return Ok(());
501 }
502 (true, false) => {
503 let len = self.len();
504 *self = ColumnBuilder::like(other, len + other.len());
505 self.append_nones(len);
506 self.optional = true;
507 }
508 (false, true) => {
509 self.append_nones(other.len());
510 return Ok(());
511 }
512 (false, false) => {}
513 }
514 let other_optional = other.is_nullable() || other.none_count() > 0;
515 if self.optional && other_optional && !self.same_type(other) {
516 return internal_err!("column type mismatch in Option extend");
517 }
518 self.append_view(other)?;
519 self.optional |= other_optional;
520 Ok(())
521 }
522
523 pub fn append_values(&mut self, other: &ColumnView) -> Result<()> {
524 let nones = other.none_count();
525 if nones == other.len() {
526 self.append_nones(other.len());
527 return Ok(());
528 }
529 self.append_view(other)?;
530 self.optional |= nones > 0;
531 Ok(())
532 }
533
534 fn append_nones(&mut self, count: usize) {
535 for _ in 0..count {
536 self.push_none();
537 }
538 }
539
540 fn same_type(&self, other: &ColumnView) -> bool {
541 let same_family =
542 matches!((&self.inner, &other.data), (TypedBuilder::Decimal(_), ViewData::Decimal(_)));
543 same_family || self.inner.get_type() == other.base_type()
544 }
545
546 fn is_untyped_none(&self) -> bool {
547 match &self.inner {
548 TypedBuilder::None(_) => true,
549 TypedBuilder::Any {
550 builder,
551 declared_type: None,
552 } if self.optional => match builder.validity_slice() {
553 Some(bits) => (0..builder.len()).all(|index| !bit_util::get_bit(bits, index)),
554 None => builder.is_empty(),
555 },
556 _ => false,
557 }
558 }
559
560 fn copy_details(&mut self, data: &ViewData) {
561 match (data, &mut self.inner) {
562 (
563 ViewData::Utf8 {
564 max_bytes: source,
565 ..
566 },
567 TypedBuilder::Utf8 {
568 max_bytes: target,
569 ..
570 },
571 )
572 | (
573 ViewData::Blob {
574 max_bytes: source,
575 ..
576 },
577 TypedBuilder::Blob {
578 max_bytes: target,
579 ..
580 },
581 ) => *target = *source,
582 (
583 ViewData::DictionaryId {
584 dictionary_id: Some(source),
585 ..
586 },
587 TypedBuilder::DictionaryId {
588 dictionary_id: target,
589 ..
590 },
591 ) => *target = Some(*source),
592 _ => {}
593 }
594 }
595
596 fn append_view(&mut self, other: &ColumnView) -> Result<()> {
597 match (&mut self.inner, &other.data) {
598 (TypedBuilder::Bool(l), ViewData::Bool(r)) => l.append_array(r),
599 (TypedBuilder::Int1(l), ViewData::Int1(r)) => l.append_array(r),
600 (TypedBuilder::Int2(l), ViewData::Int2(r)) => l.append_array(r),
601 (TypedBuilder::Int4(l), ViewData::Int4(r)) => l.append_array(r),
602 (TypedBuilder::Int8(l), ViewData::Int8(r)) => l.append_array(r),
603 (TypedBuilder::Int16(l), ViewData::Int16(r)) => l.append_array(r)?,
604 (TypedBuilder::Uint1(l), ViewData::Uint1(r)) => l.append_array(r),
605 (TypedBuilder::Uint2(l), ViewData::Uint2(r)) => l.append_array(r),
606 (TypedBuilder::Uint4(l), ViewData::Uint4(r)) => l.append_array(r),
607 (TypedBuilder::Uint8(l), ViewData::Uint8(r)) => l.append_array(r),
608 (TypedBuilder::Uint16(l), ViewData::Uint16(r)) => l.append_array(r)?,
609 (TypedBuilder::Float4(l), ViewData::Float4(r)) => l.append_array(r),
610 (TypedBuilder::Float8(l), ViewData::Float8(r)) => l.append_array(r),
611 (TypedBuilder::Date(l), ViewData::Date(r)) => l.append_array(r),
612 (TypedBuilder::DateTime(l), ViewData::DateTime(r)) => l.append_array(r),
613 (TypedBuilder::Time(l), ViewData::Time(r)) => l.append_array(r),
614 (TypedBuilder::Duration(l), ViewData::Duration(r)) => l.append_array(r),
615 (TypedBuilder::IdentityId(l), ViewData::IdentityId(r)) => append_fixed_array(l, r)?,
616 (TypedBuilder::Uuid4(l), ViewData::Uuid4(r)) => append_fixed_array(l, r)?,
617 (TypedBuilder::Uuid7(l), ViewData::Uuid7(r)) => append_fixed_array(l, r)?,
618 (
619 TypedBuilder::DictionaryId {
620 builder,
621 ..
622 },
623 ViewData::DictionaryId {
624 container,
625 ..
626 },
627 ) => append_fixed_array(builder, container)?,
628 (
629 TypedBuilder::Utf8 {
630 builder,
631 ..
632 },
633 ViewData::Utf8 {
634 container,
635 ..
636 },
637 ) => append_varlen(builder, container)?,
638 (
639 TypedBuilder::Blob {
640 builder,
641 ..
642 },
643 ViewData::Blob {
644 container,
645 ..
646 },
647 ) => append_varlen(builder, container)?,
648 (TypedBuilder::Decimal(l), ViewData::Decimal(r)) => l.append_array(*r),
649 (
650 TypedBuilder::Any {
651 builder,
652 ..
653 },
654 ViewData::Any {
655 container,
656 ..
657 },
658 ) => append_varlen(builder, container)?,
659 (
660 TypedBuilder::Digest {
661 builder,
662 inner: l_inner,
663 accuracy: l_accuracy,
664 },
665 ViewData::Digest {
666 container,
667 inner: r_inner,
668 accuracy: r_accuracy,
669 },
670 ) if l_inner == r_inner && l_accuracy == r_accuracy => append_varlen(builder, container)?,
671 _ => return internal_err!("column type mismatch"),
672 }
673 Ok(())
674 }
675
676 pub fn len(&self) -> usize {
677 self.inner.len()
678 }
679
680 pub fn is_empty(&self) -> bool {
681 self.len() == 0
682 }
683
684 pub fn get_type(&self) -> ValueType {
685 match self.optional {
686 true => ValueType::Option(Box::new(self.inner.get_type())),
687 false => self.inner.get_type(),
688 }
689 }
690
691 pub fn finish(self, name: &str) -> (FieldRef, ArrayRef) {
692 let (mut field_type, array) = self.inner.finish();
693 if let Some(value_type) = field_type.value_type.take() {
694 field_type.value_type = Some(match self.optional || array.null_count() > 0 {
695 true => ValueType::Option(Box::new(value_type)),
696 false => value_type,
697 });
698 }
699 named(name, field_type, array)
700 }
701}
702
703impl TypedBuilder {
704 pub(crate) fn append_null(&mut self) {
705 match self {
706 TypedBuilder::Bool(b) => b.append_null(),
707 TypedBuilder::Int1(b) => b.append_null(),
708 TypedBuilder::Int2(b) => b.append_null(),
709 TypedBuilder::Int4(b) => b.append_null(),
710 TypedBuilder::Int8(b) => b.append_null(),
711 TypedBuilder::Int16(b) => b.append_null(),
712 TypedBuilder::Uint1(b) => b.append_null(),
713 TypedBuilder::Uint2(b) => b.append_null(),
714 TypedBuilder::Uint4(b) => b.append_null(),
715 TypedBuilder::Uint8(b) => b.append_null(),
716 TypedBuilder::Uint16(b) => b.append_null(),
717 TypedBuilder::Float4(b) => b.append_null(),
718 TypedBuilder::Float8(b) => b.append_null(),
719 TypedBuilder::Date(b) => b.append_null(),
720 TypedBuilder::DateTime(b) => b.append_null(),
721 TypedBuilder::Time(b) => b.append_null(),
722 TypedBuilder::Duration(b) => b.append_null(),
723 TypedBuilder::IdentityId(b) => b.append_null(),
724 TypedBuilder::Uuid4(b) => b.append_null(),
725 TypedBuilder::Uuid7(b) => b.append_null(),
726 TypedBuilder::DictionaryId {
727 builder,
728 ..
729 } => builder.append_null(),
730 TypedBuilder::Utf8 {
731 builder,
732 ..
733 } => builder.append_null(),
734 TypedBuilder::Blob {
735 builder,
736 ..
737 }
738 | TypedBuilder::Any {
739 builder,
740 ..
741 }
742 | TypedBuilder::Digest {
743 builder,
744 ..
745 } => builder.append_null(),
746 TypedBuilder::Decimal(b) => b.append_null(),
747 TypedBuilder::None(b) => b.append_null(),
748 }
749 }
750
751 pub fn len(&self) -> usize {
752 match self {
753 TypedBuilder::Bool(b) => b.len(),
754 TypedBuilder::Int1(b) => b.len(),
755 TypedBuilder::Int2(b) => b.len(),
756 TypedBuilder::Int4(b) => b.len(),
757 TypedBuilder::Int8(b) => b.len(),
758 TypedBuilder::Int16(b) => b.len(),
759 TypedBuilder::Uint1(b) => b.len(),
760 TypedBuilder::Uint2(b) => b.len(),
761 TypedBuilder::Uint4(b) => b.len(),
762 TypedBuilder::Uint8(b) => b.len(),
763 TypedBuilder::Uint16(b) => b.len(),
764 TypedBuilder::Float4(b) => b.len(),
765 TypedBuilder::Float8(b) => b.len(),
766 TypedBuilder::Date(b) => b.len(),
767 TypedBuilder::DateTime(b) => b.len(),
768 TypedBuilder::Time(b) => b.len(),
769 TypedBuilder::Duration(b) => b.len(),
770 TypedBuilder::IdentityId(b) => b.len(),
771 TypedBuilder::Uuid4(b) => b.len(),
772 TypedBuilder::Uuid7(b) => b.len(),
773 TypedBuilder::DictionaryId {
774 builder,
775 ..
776 } => builder.len(),
777 TypedBuilder::Utf8 {
778 builder,
779 ..
780 } => builder.len(),
781 TypedBuilder::Blob {
782 builder,
783 ..
784 }
785 | TypedBuilder::Any {
786 builder,
787 ..
788 }
789 | TypedBuilder::Digest {
790 builder,
791 ..
792 } => builder.len(),
793 TypedBuilder::Decimal(b) => b.len(),
794 TypedBuilder::None(b) => b.len(),
795 }
796 }
797
798 pub fn is_empty(&self) -> bool {
799 self.len() == 0
800 }
801
802 pub fn get_type(&self) -> ValueType {
803 match self {
804 TypedBuilder::Bool(_) => ValueType::Boolean,
805 TypedBuilder::Int1(_) => ValueType::Int1,
806 TypedBuilder::Int2(_) => ValueType::Int2,
807 TypedBuilder::Int4(_) => ValueType::Int4,
808 TypedBuilder::Int8(_) => ValueType::Int8,
809 TypedBuilder::Int16(_) => ValueType::Int16,
810 TypedBuilder::Uint1(_) => ValueType::Uint1,
811 TypedBuilder::Uint2(_) => ValueType::Uint2,
812 TypedBuilder::Uint4(_) => ValueType::Uint4,
813 TypedBuilder::Uint8(_) => ValueType::Uint8,
814 TypedBuilder::Uint16(_) => ValueType::Uint16,
815 TypedBuilder::Float4(_) => ValueType::Float4,
816 TypedBuilder::Float8(_) => ValueType::Float8,
817 TypedBuilder::Date(_) => ValueType::Date,
818 TypedBuilder::DateTime(_) => ValueType::DateTime,
819 TypedBuilder::Time(_) => ValueType::Time,
820 TypedBuilder::Duration(_) => ValueType::Duration,
821 TypedBuilder::IdentityId(_) => ValueType::IdentityId,
822 TypedBuilder::Uuid4(_) => ValueType::Uuid4,
823 TypedBuilder::Uuid7(_) => ValueType::Uuid7,
824 TypedBuilder::DictionaryId {
825 ..
826 } => ValueType::DictionaryId,
827 TypedBuilder::Utf8 {
828 ..
829 } => ValueType::Utf8,
830 TypedBuilder::Blob {
831 ..
832 } => ValueType::Blob,
833 TypedBuilder::Decimal(b) => ValueType::decimal(b.precision(), b.scale()),
834 TypedBuilder::Any {
835 declared_type,
836 ..
837 } => declared_type.clone().unwrap_or(ValueType::Any),
838 TypedBuilder::Digest {
839 inner,
840 accuracy,
841 ..
842 } => ValueType::Digest {
843 inner: Box::new(inner.clone()),
844 accuracy: *accuracy,
845 },
846 TypedBuilder::None(_) => ValueType::Any,
847 }
848 }
849
850 fn finish(self) -> (FieldType, ArrayRef) {
851 let value_type = self.get_type();
852 let bare = |array: ArrayRef| {
853 (
854 FieldType {
855 value_type: Some(value_type.clone()),
856 ..FieldType::default()
857 },
858 array,
859 )
860 };
861 match self {
862 TypedBuilder::Bool(mut b) => bare(Arc::new(b.finish())),
863 TypedBuilder::Int1(mut b) => bare(Arc::new(b.finish())),
864 TypedBuilder::Int2(mut b) => bare(Arc::new(b.finish())),
865 TypedBuilder::Int4(mut b) => bare(Arc::new(b.finish())),
866 TypedBuilder::Int8(mut b) => bare(Arc::new(b.finish())),
867 TypedBuilder::Int16(mut b) => bare(Arc::new(b.finish())),
868 TypedBuilder::Uint1(mut b) => bare(Arc::new(b.finish())),
869 TypedBuilder::Uint2(mut b) => bare(Arc::new(b.finish())),
870 TypedBuilder::Uint4(mut b) => bare(Arc::new(b.finish())),
871 TypedBuilder::Uint8(mut b) => bare(Arc::new(b.finish())),
872 TypedBuilder::Uint16(mut b) => bare(Arc::new(b.finish())),
873 TypedBuilder::Float4(mut b) => bare(Arc::new(b.finish())),
874 TypedBuilder::Float8(mut b) => bare(Arc::new(b.finish())),
875 TypedBuilder::Date(mut b) => bare(Arc::new(b.finish())),
876 TypedBuilder::DateTime(mut b) => bare(Arc::new(b.finish())),
877 TypedBuilder::Time(mut b) => bare(Arc::new(b.finish())),
878 TypedBuilder::Duration(mut b) => bare(Arc::new(b.finish())),
879 TypedBuilder::IdentityId(mut b) => bare(Arc::new(b.finish())),
880 TypedBuilder::Uuid4(mut b) => bare(Arc::new(b.finish())),
881 TypedBuilder::Uuid7(mut b) => bare(Arc::new(b.finish())),
882 TypedBuilder::DictionaryId {
883 mut builder,
884 dictionary_id,
885 } => (
886 FieldType {
887 value_type: Some(value_type),
888 dictionary_id,
889 ..FieldType::default()
890 },
891 Arc::new(builder.finish()),
892 ),
893 TypedBuilder::Utf8 {
894 mut builder,
895 max_bytes,
896 } => (
897 FieldType {
898 value_type: Some(value_type),
899 max_bytes: limit(max_bytes),
900 ..FieldType::default()
901 },
902 Arc::new(builder.finish()),
903 ),
904 TypedBuilder::Blob {
905 mut builder,
906 max_bytes,
907 } => (
908 FieldType {
909 value_type: Some(value_type),
910 max_bytes: limit(max_bytes),
911 ..FieldType::default()
912 },
913 Arc::new(builder.finish()),
914 ),
915 TypedBuilder::Decimal(mut b) => bare(b.finish().into_array()),
916 TypedBuilder::Any {
917 mut builder,
918 declared_type,
919 } => (
920 FieldType {
921 value_type: Some(value_type),
922 declared_type,
923 ..FieldType::default()
924 },
925 Arc::new(builder.finish()),
926 ),
927 TypedBuilder::Digest {
928 mut builder,
929 ..
930 } => bare(Arc::new(builder.finish())),
931 TypedBuilder::None(mut b) => (FieldType::default(), Arc::new(b.finish())),
932 }
933 }
934
935 fn from_view(data: &ViewData) -> TypedBuilder {
936 match data {
937 ViewData::Bool(a) => {
938 let mut builder = BooleanBuilder::with_capacity(a.len());
939 builder.append_array(a);
940 TypedBuilder::Bool(builder)
941 }
942 ViewData::Int1(a) => TypedBuilder::Int1(primitive_builder((*a).clone())),
943 ViewData::Int2(a) => TypedBuilder::Int2(primitive_builder((*a).clone())),
944 ViewData::Int4(a) => TypedBuilder::Int4(primitive_builder((*a).clone())),
945 ViewData::Int8(a) => TypedBuilder::Int8(primitive_builder((*a).clone())),
946 ViewData::Int16(a) => TypedBuilder::Int16(WideBuilder::from_array(a)),
947 ViewData::Uint1(a) => TypedBuilder::Uint1(primitive_builder((*a).clone())),
948 ViewData::Uint2(a) => TypedBuilder::Uint2(primitive_builder((*a).clone())),
949 ViewData::Uint4(a) => TypedBuilder::Uint4(primitive_builder((*a).clone())),
950 ViewData::Uint8(a) => TypedBuilder::Uint8(primitive_builder((*a).clone())),
951 ViewData::Uint16(a) => TypedBuilder::Uint16(WideBuilder::from_array(a)),
952 ViewData::Float4(a) => TypedBuilder::Float4(primitive_builder((*a).clone())),
953 ViewData::Float8(a) => TypedBuilder::Float8(primitive_builder((*a).clone())),
954 ViewData::Date(a) => TypedBuilder::Date(primitive_builder((*a).clone())),
955 ViewData::DateTime(a) => TypedBuilder::DateTime(primitive_builder((*a).clone())),
956 ViewData::Time(a) => TypedBuilder::Time(primitive_builder((*a).clone())),
957 ViewData::Duration(a) => TypedBuilder::Duration(primitive_builder((*a).clone())),
958 ViewData::IdentityId(a) => TypedBuilder::IdentityId(fixed_size_builder(a)),
959 ViewData::Uuid4(a) => TypedBuilder::Uuid4(fixed_size_builder(a)),
960 ViewData::Uuid7(a) => TypedBuilder::Uuid7(fixed_size_builder(a)),
961 ViewData::DictionaryId {
962 container,
963 dictionary_id,
964 } => TypedBuilder::DictionaryId {
965 builder: fixed_size_builder(container),
966 dictionary_id: *dictionary_id,
967 },
968 ViewData::Utf8 {
969 container,
970 max_bytes,
971 } => TypedBuilder::Utf8 {
972 builder: varlen_builder((*container).clone()),
973 max_bytes: *max_bytes,
974 },
975 ViewData::Blob {
976 container,
977 max_bytes,
978 } => TypedBuilder::Blob {
979 builder: varlen_builder((*container).clone()),
980 max_bytes: *max_bytes,
981 },
982 ViewData::Decimal(a) => {
983 TypedBuilder::Decimal(DecimalBuilder::from_array(DecimalArray::from(*a)))
984 }
985 ViewData::Any {
986 container,
987 declared_type,
988 } => TypedBuilder::Any {
989 builder: varlen_builder((*container).clone()),
990 declared_type: declared_type.clone(),
991 },
992 ViewData::Digest {
993 container,
994 inner,
995 accuracy,
996 } => TypedBuilder::Digest {
997 builder: varlen_builder((*container).clone()),
998 inner: inner.clone(),
999 accuracy: *accuracy,
1000 },
1001 ViewData::None {
1002 array,
1003 } => {
1004 let mut builder = NullBuilder::new();
1005 builder.append_nulls(array.len());
1006 TypedBuilder::None(builder)
1007 }
1008 }
1009 }
1010}
1011
1012fn limit(max_bytes: MaxBytes) -> Option<MaxBytes> {
1013 (max_bytes != MaxBytes::MAX).then_some(max_bytes)
1014}
1015
1016pub(crate) fn primitive_builder<A>(array: PrimitiveArray<A>) -> PrimitiveBuilder<A>
1017where
1018 A: ArrowPrimitiveType,
1019{
1020 let data_type = array.data_type().clone();
1021 match array.into_builder() {
1022 Ok(builder) => builder.with_data_type(data_type),
1023 Err(array) => {
1024 let mut builder = PrimitiveBuilder::with_capacity(array.len());
1025 builder.append_array(&array);
1026 builder.with_data_type(data_type)
1027 }
1028 }
1029}
1030
1031pub(crate) fn append_fixed(builder: &mut FixedSizeBinaryBuilder, row: &[u8]) {
1032 if builder.append_value(row).is_err() {
1033 panic!(
1034 "a fixed size builder of {} byte rows can not take a row of {} bytes",
1035 builder.finish_cloned().value_length(),
1036 row.len()
1037 );
1038 }
1039}
1040
1041fn fixed_size_builder(array: &FixedSizeBinaryArray) -> FixedSizeBinaryBuilder {
1042 let mut builder = FixedSizeBinaryBuilder::with_capacity(array.len(), array.value_length());
1043 append_fixed_array(&mut builder, array)
1044 .expect("copying a fixed size array into a builder of its own width failed");
1045 builder
1046}
1047
1048pub(crate) fn append_fixed_array(builder: &mut FixedSizeBinaryBuilder, array: &FixedSizeBinaryArray) -> Result<()> {
1049 builder.append_array(array).map_err(|e| internal_error!("fixed size append failed: {}", e))
1050}
1051
1052pub(crate) fn varlen_builder<T>(array: GenericByteArray<T>) -> GenericByteBuilder<T>
1053where
1054 T: ByteArrayType<Offset = i64>,
1055{
1056 let array = if array.value_offsets()[0] == 0 {
1057 match array.into_builder() {
1058 Ok(builder) => return builder,
1059 Err(array) => array,
1060 }
1061 } else {
1062 array
1063 };
1064 let (data, _) = varlen_array::compact_parts(&array);
1065 let mut builder = GenericByteBuilder::<T>::with_capacity(array.len(), data.len());
1066 append_varlen(&mut builder, &array)
1067 .expect("copying a shared or offset utf8 / blob array into a new builder failed");
1068 builder
1069}
1070
1071pub(crate) fn append_varlen<T>(builder: &mut GenericByteBuilder<T>, array: &GenericByteArray<T>) -> Result<()>
1072where
1073 T: ByteArrayType<Offset = i64>,
1074{
1075 builder.append_array(array).map_err(|e| internal_error!("utf8 / blob append failed: {}", e))
1076}
1077
1078#[cfg(test)]
1079mod tests {
1080 use std::str::FromStr;
1081
1082 use arrow_array::ArrayRef;
1083 use arrow_buffer::{BooleanBuffer, NullBuffer};
1084 use arrow_schema::FieldRef;
1085 use reifydb_value::value::{
1086 Value,
1087 column_view::{ColumnView, ViewData},
1088 constraint::{precision::Precision, scale::Scale},
1089 decimal::Decimal,
1090 value_type::ValueType,
1091 };
1092
1093 use super::*;
1094 use crate::value::column::{factory, nulls::with_nulls};
1095
1096 fn concat(parts: &[(FieldRef, ArrayRef)]) -> (FieldRef, ArrayRef) {
1097 let (first, rest) = parts.split_first().unwrap();
1098 let mut builder = ColumnBuilder::from_view(&ColumnView::try_from(first).unwrap());
1099 for part in rest {
1100 builder.extend(&ColumnView::try_from(part).unwrap()).unwrap();
1101 }
1102 builder.finish("c")
1103 }
1104
1105 #[test]
1106 fn concat_keeps_a_nullable_column_nullable_across_chunks() {
1107 let first = with_nulls(factory::int4("c", [1, 2]), NullBuffer::new_valid(2)).unwrap();
1109 let second = factory::int4("c", [3, 4]);
1110
1111 let joined = concat(&[first, second]);
1112 let joined = ColumnView::try_from(&joined).unwrap();
1113
1114 assert_eq!(joined.len(), 4);
1115 assert!(joined.is_nullable());
1116 assert_eq!(joined.get_type(), ValueType::Option(Box::new(ValueType::Int4)));
1117 assert_eq!(joined.get_value(3), Value::Int4(4));
1118 }
1119
1120 #[test]
1121 fn concat_carries_the_none_rows_of_every_chunk() {
1122 let first = factory::int4_with_bitvec("c", [1, 0], BooleanBuffer::from(vec![true, false]));
1124 let second = factory::int4_with_bitvec("c", [0, 4], BooleanBuffer::from(vec![false, true]));
1125
1126 let joined = concat(&[first, second]);
1127 let joined = ColumnView::try_from(&joined).unwrap();
1128
1129 assert_eq!(joined.get_value(0), Value::Int4(1));
1130 assert_eq!(joined.get_value(1), Value::none_of(ValueType::Int4));
1131 assert_eq!(joined.get_value(2), Value::none_of(ValueType::Int4));
1132 assert_eq!(joined.get_value(3), Value::Int4(4));
1133 }
1134
1135 #[test]
1136 fn concat_keeps_the_decimal_precision_and_scale() {
1137 let first =
1139 factory::decimal("c", Precision::new(9), Scale::new(2), [Decimal::from_str("1.25").unwrap()]);
1140 let second =
1141 factory::decimal("c", Precision::new(9), Scale::new(2), [Decimal::from_str("2.50").unwrap()]);
1142
1143 let joined = concat(&[first, second]);
1144 let joined = ColumnView::try_from(&joined).unwrap();
1145
1146 let ViewData::Decimal(array) = &joined.data else {
1147 panic!("expected a decimal column");
1148 };
1149 assert_eq!(array.precision(), Precision::new(9));
1150 assert_eq!(array.scale(), Scale::new(2));
1151 assert_eq!(joined.len(), 2);
1152 }
1153}