1use std::marker::PhantomData;
19use std::mem::size_of;
20use std::sync::Arc;
21
22use datafusion_common::{
23 DataFusionError, Result, ScalarValue, exec_datafusion_err, exec_err, internal_err,
24 plan_err,
25};
26
27use arrow::array::{
28 Array, ArrayAccessor, ArrayDataBuilder, ArrayRef, BinaryArray, BinaryViewArray,
29 ByteView, GenericStringArray, LargeBinaryArray, LargeStringArray, OffsetSizeTrait,
30 StringArray, StringViewArray, as_largestring_array, make_view,
31};
32use arrow::buffer::{Buffer, MutableBuffer, NullBuffer, ScalarBuffer};
33use arrow::datatypes::DataType;
34use arrow_buffer::ArrowNativeType;
35use datafusion_common::cast::{
36 as_binary_array, as_binary_view_array, as_large_binary_array, as_string_array,
37 as_string_view_array,
38};
39use datafusion_expr_common::columnar_value::ColumnarValue;
40
41pub(crate) trait ConcatBuilder {
43 fn write<const CHECK_VALID: bool>(
44 &mut self,
45 column: &ColumnarValueRef,
46 i: usize,
47 ) -> Result<()>;
48
49 fn append_offset(&mut self) -> Result<()>;
50
51 fn finish(self, null_buffer: Option<NullBuffer>) -> Result<ArrayRef>;
52}
53
54pub(crate) struct ConcatGenericStringBuilder<O: OffsetSizeTrait + ArrowNativeType> {
65 offsets_buffer: MutableBuffer,
66 value_buffer: MutableBuffer,
67 _phantom: PhantomData<O>,
68}
69pub(crate) type ConcatStringBuilder = ConcatGenericStringBuilder<i32>;
70pub(crate) type ConcatLargeStringBuilder = ConcatGenericStringBuilder<i64>;
71
72impl<O: OffsetSizeTrait + ArrowNativeType> ConcatGenericStringBuilder<O> {
73 pub fn with_capacity(item_capacity: usize, data_capacity: usize) -> Self {
74 let capacity = item_capacity
75 .checked_add(1)
76 .map(|i| i.saturating_mul(size_of::<O>()))
77 .expect("capacity integer overflow");
78
79 let mut offsets_buffer = MutableBuffer::with_capacity(capacity);
80 unsafe { offsets_buffer.push_unchecked(O::usize_as(0)) };
82 Self {
83 offsets_buffer,
84 value_buffer: MutableBuffer::with_capacity(data_capacity),
85 _phantom: PhantomData,
86 }
87 }
88}
89
90impl<O: OffsetSizeTrait + ArrowNativeType> ConcatBuilder
91 for ConcatGenericStringBuilder<O>
92{
93 fn write<const CHECK_VALID: bool>(
94 &mut self,
95 column: &ColumnarValueRef,
96 i: usize,
97 ) -> Result<()> {
98 match column {
99 ColumnarValueRef::Scalar(s) => {
100 std::str::from_utf8(s).map_err(|_| {
101 exec_datafusion_err!("concat: scalar bytes are not valid UTF-8")
102 })?;
103 self.value_buffer.extend_from_slice(s);
104 }
105 ColumnarValueRef::NullableArray(array) => {
106 if !CHECK_VALID || array.is_valid(i) {
107 self.value_buffer
108 .extend_from_slice(array.value(i).as_bytes());
109 }
110 }
111 ColumnarValueRef::NullableLargeStringArray(array) => {
112 if !CHECK_VALID || array.is_valid(i) {
113 self.value_buffer
114 .extend_from_slice(array.value(i).as_bytes());
115 }
116 }
117 ColumnarValueRef::NullableStringViewArray(array) => {
118 if !CHECK_VALID || array.is_valid(i) {
119 self.value_buffer
120 .extend_from_slice(array.value(i).as_bytes());
121 }
122 }
123 ColumnarValueRef::NonNullableArray(array) => {
124 self.value_buffer
125 .extend_from_slice(array.value(i).as_bytes());
126 }
127 ColumnarValueRef::NonNullableLargeStringArray(array) => {
128 self.value_buffer
129 .extend_from_slice(array.value(i).as_bytes());
130 }
131 ColumnarValueRef::NonNullableStringViewArray(array) => {
132 self.value_buffer
133 .extend_from_slice(array.value(i).as_bytes());
134 }
135 _ => {
136 return exec_err!(
137 "concat: unexpected column type for string builder: {column:?}"
138 );
139 }
140 }
141 Ok(())
142 }
143
144 fn append_offset(&mut self) -> Result<()> {
145 let next_offset: O = O::from_usize(self.value_buffer.len())
146 .ok_or_else(|| exec_datafusion_err!("byte array offset overflow"))?;
147 self.offsets_buffer.push(next_offset);
148 Ok(())
149 }
150
151 fn finish(self, null_buffer: Option<NullBuffer>) -> Result<ArrayRef> {
159 let row_count = self.offsets_buffer.len() / size_of::<O>() - 1;
160 if let Some(ref null_buffer) = null_buffer
161 && null_buffer.len() != row_count
162 {
163 return internal_err!(
164 "Null buffer and offsets buffer must be the same length"
165 );
166 }
167 let array_builder = ArrayDataBuilder::new(GenericStringArray::<O>::DATA_TYPE)
168 .len(row_count)
169 .add_buffer(self.offsets_buffer.into())
170 .add_buffer(self.value_buffer.into())
171 .nulls(null_buffer);
172 let array_data = unsafe { array_builder.build_unchecked() };
175 let array = GenericStringArray::<O>::from(array_data);
176 Ok(Arc::new(array))
177 }
178}
179
180pub(crate) struct ConcatStringViewBuilder {
191 views: Vec<u128>,
192 data: Vec<u8>,
193 block: Vec<u8>,
194}
195
196impl ConcatStringViewBuilder {
197 pub fn with_capacity(item_capacity: usize, data_capacity: usize) -> Self {
198 Self {
199 views: Vec::with_capacity(item_capacity),
200 data: Vec::with_capacity(data_capacity),
201 block: vec![],
202 }
203 }
204}
205
206impl ConcatBuilder for ConcatStringViewBuilder {
207 fn write<const CHECK_VALID: bool>(
208 &mut self,
209 column: &ColumnarValueRef,
210 i: usize,
211 ) -> Result<()> {
212 match column {
213 ColumnarValueRef::Scalar(s) => {
214 std::str::from_utf8(s).map_err(|_| {
215 exec_datafusion_err!("concat: scalar bytes are not valid UTF-8")
216 })?;
217 self.block.extend_from_slice(s);
218 }
219 ColumnarValueRef::NullableArray(array) => {
220 if !CHECK_VALID || array.is_valid(i) {
221 self.block.extend_from_slice(array.value(i).as_bytes());
222 }
223 }
224 ColumnarValueRef::NullableLargeStringArray(array) => {
225 if !CHECK_VALID || array.is_valid(i) {
226 self.block.extend_from_slice(array.value(i).as_bytes());
227 }
228 }
229 ColumnarValueRef::NullableStringViewArray(array) => {
230 if !CHECK_VALID || array.is_valid(i) {
231 self.block.extend_from_slice(array.value(i).as_bytes());
232 }
233 }
234 ColumnarValueRef::NonNullableArray(array) => {
235 self.block.extend_from_slice(array.value(i).as_bytes());
236 }
237 ColumnarValueRef::NonNullableLargeStringArray(array) => {
238 self.block.extend_from_slice(array.value(i).as_bytes());
239 }
240 ColumnarValueRef::NonNullableStringViewArray(array) => {
241 self.block.extend_from_slice(array.value(i).as_bytes());
242 }
243 _ => {
244 return exec_err!(
245 "concat: unexpected column type for string view builder: {column:?}"
246 );
247 }
248 }
249 Ok(())
250 }
251
252 fn append_offset(&mut self) -> Result<()> {
255 let v = &self.block;
256 if v.len() > 12 {
257 let offset: u32 = self
258 .data
259 .len()
260 .try_into()
261 .map_err(|_| exec_datafusion_err!("byte array offset overflow"))?;
262 self.data.extend_from_slice(v);
263 self.views.push(make_view(v, 0, offset));
264 } else {
265 self.views.push(make_view(v, 0, 0));
266 }
267
268 self.block.clear();
269 Ok(())
270 }
271
272 fn finish(self, null_buffer: Option<NullBuffer>) -> Result<ArrayRef> {
280 if let Some(ref nulls) = null_buffer
281 && nulls.len() != self.views.len()
282 {
283 return internal_err!(
284 "Null buffer length ({}) must match row count ({})",
285 nulls.len(),
286 self.views.len()
287 );
288 }
289
290 let buffers: Vec<Buffer> = if self.data.is_empty() {
291 vec![]
292 } else {
293 vec![Buffer::from(self.data)]
294 };
295
296 let array = unsafe {
300 StringViewArray::new_unchecked(
301 ScalarBuffer::from(self.views),
302 buffers,
303 null_buffer,
304 )
305 };
306 Ok(Arc::new(array))
307 }
308}
309
310pub(crate) struct GenericStringArrayBuilder<O: OffsetSizeTrait> {
329 offsets_buffer: MutableBuffer,
330 value_buffer: MutableBuffer,
331 placeholder_count: usize,
332 _phantom: PhantomData<O>,
333}
334
335fn offset_overflow_error<O: OffsetSizeTrait>() -> DataFusionError {
336 exec_datafusion_err!(
337 "byte array offset overflow: output size exceeds {} bytes",
338 O::MAX_OFFSET
339 )
340}
341
342fn string_view_overflow_error(field: &str) -> DataFusionError {
343 exec_datafusion_err!("byte array offset overflow: {field} exceeds i32::MAX")
344}
345
346fn try_offset<O: OffsetSizeTrait>(len: usize) -> Result<O> {
347 if len > O::MAX_OFFSET {
348 return Err(offset_overflow_error::<O>());
349 }
350 Ok(O::usize_as(len))
351}
352
353impl<O: OffsetSizeTrait> GenericStringArrayBuilder<O> {
354 pub fn with_capacity(item_capacity: usize, data_capacity: usize) -> Self {
355 let capacity = item_capacity
356 .checked_add(1)
357 .map(|i| i.saturating_mul(size_of::<O>()))
358 .expect("capacity integer overflow");
359
360 let mut offsets_buffer = MutableBuffer::with_capacity(capacity);
361 offsets_buffer.push(O::usize_as(0));
362 Self {
363 offsets_buffer,
364 value_buffer: MutableBuffer::with_capacity(data_capacity),
365 placeholder_count: 0,
366 _phantom: PhantomData,
367 }
368 }
369
370 #[inline]
371 fn try_push_offset_for_len(&mut self, len: usize) -> Result<()> {
372 let next_offset = try_offset::<O>(len)?;
373 self.offsets_buffer.push(next_offset);
374 Ok(())
375 }
376
377 #[inline]
378 fn try_append_bytes<F>(&mut self, additional_len: usize, append: F) -> Result<()>
379 where
380 F: FnOnce(&mut MutableBuffer),
381 {
382 let next_len = self
383 .value_buffer
384 .len()
385 .checked_add(additional_len)
386 .ok_or_else(offset_overflow_error::<O>)?;
387 let next_offset = try_offset::<O>(next_len)?;
388 append(&mut self.value_buffer);
389 debug_assert_eq!(self.value_buffer.len(), next_len);
390 self.offsets_buffer.push(next_offset);
391 Ok(())
392 }
393
394 #[inline]
401 pub fn try_append_value(&mut self, value: &str) -> Result<()> {
402 self.try_append_bytes(value.len(), |value_buffer| {
403 value_buffer.extend_from_slice(value.as_bytes());
404 })
405 }
406
407 #[inline]
414 pub fn try_append_placeholder(&mut self) -> Result<()> {
415 self.try_push_offset_for_len(self.value_buffer.len())?;
416 self.placeholder_count += 1;
417 Ok(())
418 }
419
420 #[inline]
429 pub fn append_value(&mut self, value: &str) {
430 self.try_append_value(value)
431 .expect("byte array offset overflow");
432 }
433
434 #[inline]
439 pub fn append_placeholder(&mut self) {
440 self.try_append_placeholder()
441 .expect("byte array offset overflow");
442 }
443
444 #[inline]
456 pub unsafe fn try_append_byte_map<F: FnMut(u8) -> u8>(
457 &mut self,
458 src: &[u8],
459 mut map: F,
460 ) -> Result<()> {
461 self.try_append_bytes(src.len(), |value_buffer| {
462 value_buffer.extend(src.iter().map(|&b| map(b)));
463 })
464 }
465
466 #[inline]
480 pub unsafe fn append_byte_map<F: FnMut(u8) -> u8>(&mut self, src: &[u8], map: F) {
481 unsafe { self.try_append_byte_map(src, map) }
483 .expect("byte array offset overflow");
484 }
485
486 #[inline]
493 pub fn try_append_with<F>(&mut self, f: F) -> Result<()>
494 where
495 F: FnOnce(&mut GenericStringWriter<'_>),
496 {
497 let old_len = self.value_buffer.len();
498 let mut writer = GenericStringWriter {
499 value_buffer: &mut self.value_buffer,
500 };
501 f(&mut writer);
502 let next_offset = match try_offset::<O>(self.value_buffer.len()) {
503 Ok(offset) => offset,
504 Err(e) => {
505 unsafe { self.value_buffer.set_len(old_len) };
508 return Err(e);
509 }
510 };
511 self.offsets_buffer.push(next_offset);
512 Ok(())
513 }
514
515 #[inline]
524 pub fn append_with<F>(&mut self, f: F)
525 where
526 F: FnOnce(&mut GenericStringWriter<'_>),
527 {
528 let mut writer = GenericStringWriter {
532 value_buffer: &mut self.value_buffer,
533 };
534 f(&mut writer);
535 let next_offset =
536 O::from_usize(self.value_buffer.len()).expect("byte array offset overflow");
537 self.offsets_buffer.push(next_offset);
538 }
539
540 pub fn finish(
548 self,
549 null_buffer: Option<NullBuffer>,
550 ) -> Result<GenericStringArray<O>> {
551 let row_count = self.offsets_buffer.len() / size_of::<O>() - 1;
552 if let Some(ref n) = null_buffer
553 && n.len() != row_count
554 {
555 return internal_err!(
556 "Null buffer length ({}) must match row count ({row_count})",
557 n.len()
558 );
559 }
560 let null_count = null_buffer.as_ref().map_or(0, |n| n.null_count());
561 debug_assert!(
562 null_count >= self.placeholder_count,
563 "{} placeholder rows but null buffer has {null_count} nulls",
564 self.placeholder_count,
565 );
566 let array_data = ArrayDataBuilder::new(GenericStringArray::<O>::DATA_TYPE)
567 .len(row_count)
568 .add_buffer(self.offsets_buffer.into())
569 .add_buffer(self.value_buffer.into())
570 .nulls(null_buffer);
571 let array_data = unsafe { array_data.build_unchecked() };
574 Ok(GenericStringArray::<O>::from(array_data))
575 }
576}
577
578pub(crate) const STRING_VIEW_INIT_BLOCK_SIZE: u32 = 8 * 1024;
581pub(crate) const STRING_VIEW_MAX_BLOCK_SIZE: u32 = 2 * 1024 * 1024;
584
585pub(crate) trait StringWriter {
587 fn write_str(&mut self, s: &str);
588 fn write_char(&mut self, c: char);
589}
590
591pub(crate) struct GenericStringWriter<'a> {
594 value_buffer: &'a mut MutableBuffer,
595}
596
597impl StringWriter for GenericStringWriter<'_> {
598 #[inline(always)]
599 fn write_str(&mut self, s: &str) {
600 push_bytes_to_mutable_buffer(self.value_buffer, s.as_bytes());
601 }
602
603 #[inline(always)]
604 fn write_char(&mut self, c: char) {
605 push_char_to_mutable_buffer(self.value_buffer, c);
606 }
607}
608
609#[inline(always)]
613fn push_bytes_to_mutable_buffer(value_buffer: &mut MutableBuffer, bytes: &[u8]) {
614 let n = bytes.len();
615 let old_len = value_buffer.len();
616 value_buffer.reserve(n);
617
618 unsafe {
621 let dst = value_buffer.as_mut_ptr().add(old_len);
622 let src = bytes.as_ptr();
623 match n {
624 0 => {}
625 1 => std::ptr::copy_nonoverlapping(src, dst, 1),
626 2 => std::ptr::copy_nonoverlapping(src, dst, 2),
627 3 => std::ptr::copy_nonoverlapping(src, dst, 3),
628 4 => std::ptr::copy_nonoverlapping(src, dst, 4),
629 5 => std::ptr::copy_nonoverlapping(src, dst, 5),
630 6 => std::ptr::copy_nonoverlapping(src, dst, 6),
631 7 => std::ptr::copy_nonoverlapping(src, dst, 7),
632 8 => std::ptr::copy_nonoverlapping(src, dst, 8),
633 _ => std::ptr::copy_nonoverlapping(src, dst, n),
634 }
635 value_buffer.set_len(old_len + n);
636 }
637}
638
639#[inline(always)]
640fn push_char_to_mutable_buffer(value_buffer: &mut MutableBuffer, c: char) {
641 let len = c.len_utf8();
642 let old_len = value_buffer.len();
643 value_buffer.reserve(len);
644
645 unsafe {
648 let dst = value_buffer.as_mut_ptr().add(old_len);
649 if len == 1 {
650 *dst = c as u8;
651 } else {
652 c.encode_utf8(std::slice::from_raw_parts_mut(dst, len));
653 }
654 value_buffer.set_len(old_len + len);
655 }
656}
657
658pub(crate) struct StringViewArrayBuilder {
665 views: Vec<u128>,
666 in_progress: Vec<u8>,
667 completed: Vec<Buffer>,
668 block_size: u32,
669 placeholder_count: usize,
670}
671
672impl StringViewArrayBuilder {
673 pub fn with_capacity(item_capacity: usize) -> Self {
674 Self {
675 views: Vec::with_capacity(item_capacity),
676 in_progress: Vec::new(),
677 completed: Vec::new(),
678 block_size: STRING_VIEW_INIT_BLOCK_SIZE,
679 placeholder_count: 0,
680 }
681 }
682
683 fn next_block_size(&mut self) -> u32 {
685 if self.block_size < STRING_VIEW_MAX_BLOCK_SIZE {
686 self.block_size = self.block_size.saturating_mul(2);
687 }
688 self.block_size
689 }
690
691 #[inline]
701 pub fn try_append_value(&mut self, value: &str) -> Result<()> {
702 let v = value.as_bytes();
703 let length: u32 = i32::try_from(v.len())
704 .map_err(|_| string_view_overflow_error("value length"))?
705 as u32;
706 if length <= 12 {
707 self.views.push(make_view(v, 0, 0));
708 return Ok(());
709 }
710
711 self.try_ensure_long_capacity(length)?;
712
713 let offset: u32 = i32::try_from(self.in_progress.len())
714 .map_err(|_| string_view_overflow_error("offset"))?
715 as u32;
716 let buffer_index: u32 = i32::try_from(self.completed.len())
717 .map_err(|_| string_view_overflow_error("buffer count"))?
718 as u32;
719 self.in_progress.extend_from_slice(v);
720 self.views.push(Self::make_long_view_checked(
721 length,
722 buffer_index,
723 offset,
724 v,
725 ));
726 Ok(())
727 }
728
729 #[inline]
739 pub fn append_value(&mut self, value: &str) {
740 self.try_append_value(value)
741 .expect("byte array offset overflow");
742 }
743
744 #[inline]
751 pub fn try_append_placeholder(&mut self) -> Result<()> {
752 self.append_placeholder();
753 Ok(())
754 }
755
756 #[inline]
761 pub fn append_placeholder(&mut self) {
762 self.views.push(0);
764 self.placeholder_count += 1;
765 }
766
767 #[inline]
769 fn try_ensure_long_capacity(&mut self, length: u32) -> Result<()> {
770 let required_cap = self
771 .in_progress
772 .len()
773 .checked_add(length as usize)
774 .ok_or_else(|| string_view_overflow_error("string view block size"))?;
775 if self.in_progress.capacity() < required_cap {
776 self.flush_in_progress();
777 let to_reserve = (length as usize).max(self.next_block_size() as usize);
778 #[expect(
779 clippy::disallowed_methods,
780 reason = "StringView's block size bounds growth, so reserve cannot overflow capacity arithmetically. This hot loop intentionally avoids the extra `try_reserve` checks. It remains subject to allocator failure/OOM, which must be managed externally."
781 )]
782 self.in_progress.reserve(to_reserve);
783 }
784 Ok(())
785 }
786
787 #[inline]
792 fn ensure_long_capacity(&mut self, length: u32) {
793 self.try_ensure_long_capacity(length)
794 .expect("byte array offset overflow");
795 }
796
797 #[inline]
805 fn make_long_view_checked(
806 length: u32,
807 buffer_index: u32,
808 offset: u32,
809 prefix_bytes: &[u8],
810 ) -> u128 {
811 ByteView {
812 length,
813 prefix: u32::from_le_bytes(prefix_bytes[..4].try_into().unwrap()),
815 buffer_index,
816 offset,
817 }
818 .into()
819 }
820
821 #[inline]
822 fn make_long_view(&self, length: u32, offset: u32, prefix_bytes: &[u8]) -> u128 {
823 let buffer_index: u32 = i32::try_from(self.completed.len())
824 .expect("buffer count exceeds i32::MAX")
825 as u32;
826 Self::make_long_view_checked(length, buffer_index, offset, prefix_bytes)
827 }
828
829 #[inline]
842 pub unsafe fn append_byte_map<F: FnMut(u8) -> u8>(&mut self, src: &[u8], mut map: F) {
843 let length: u32 =
844 i32::try_from(src.len()).expect("value length exceeds i32::MAX") as u32;
845 if length <= 12 {
846 let mut bytes = [0u8; 12];
847 for (d, &b) in bytes[..src.len()].iter_mut().zip(src) {
848 *d = map(b);
849 }
850 self.views.push(make_view(&bytes[..src.len()], 0, 0));
851 return;
852 }
853
854 self.ensure_long_capacity(length);
855
856 let cursor = self.in_progress.len();
857 let offset: u32 = i32::try_from(cursor).expect("offset exceeds i32::MAX") as u32;
858 self.in_progress.extend(src.iter().map(|&b| map(b)));
859 self.views
860 .push(self.make_long_view(length, offset, &self.in_progress[cursor..]));
861 }
862
863 #[inline]
871 pub fn append_with<F>(&mut self, f: F)
872 where
873 F: FnOnce(&mut StringViewWriter<'_>),
874 {
875 let mut writer = StringViewWriter {
876 inline_buf: [0u8; 12],
877 inline_len: 0,
878 spill_cursor: None,
879 builder: self,
880 };
881 f(&mut writer);
882 let StringViewWriter {
886 inline_buf,
887 inline_len,
888 spill_cursor,
889 ..
890 } = writer;
891
892 match spill_cursor {
893 None => {
894 self.views
895 .push(make_view(&inline_buf[..inline_len as usize], 0, 0));
896 }
897 Some(start) => {
898 let end = self.in_progress.len();
899 let length: u32 = i32::try_from(end - start)
900 .expect("value length exceeds i32::MAX")
901 as u32;
902 let offset: u32 =
903 i32::try_from(start).expect("offset exceeds i32::MAX") as u32;
904 self.views.push(self.make_long_view(
905 length,
906 offset,
907 &self.in_progress[start..],
908 ));
909 }
910 }
911 }
912
913 fn flush_in_progress(&mut self) {
914 if !self.in_progress.is_empty() {
915 let block = std::mem::take(&mut self.in_progress);
916 self.completed.push(Buffer::from_vec(block));
917 }
918 }
919
920 pub fn finish(mut self, null_buffer: Option<NullBuffer>) -> Result<StringViewArray> {
928 if let Some(ref n) = null_buffer
929 && n.len() != self.views.len()
930 {
931 return internal_err!(
932 "Null buffer length ({}) must match row count ({})",
933 n.len(),
934 self.views.len()
935 );
936 }
937 let null_count = null_buffer.as_ref().map_or(0, |n| n.null_count());
938 debug_assert!(
939 null_count >= self.placeholder_count,
940 "{} placeholder rows but null buffer has {null_count} nulls",
941 self.placeholder_count,
942 );
943 self.flush_in_progress();
944 let array = unsafe {
949 StringViewArray::new_unchecked(
950 ScalarBuffer::from(self.views),
951 self.completed,
952 null_buffer,
953 )
954 };
955 Ok(array)
956 }
957}
958
959pub(crate) struct StringViewWriter<'a> {
967 inline_buf: [u8; 12],
968 inline_len: u8,
969 spill_cursor: Option<usize>,
972 builder: &'a mut StringViewArrayBuilder,
973}
974
975impl StringWriter for StringViewWriter<'_> {
976 #[inline]
977 fn write_str(&mut self, s: &str) {
978 let bytes = s.as_bytes();
979 if self.spill_cursor.is_some() {
980 self.builder.in_progress.extend_from_slice(bytes);
981 return;
982 }
983
984 let inline_len = self.inline_len as usize;
985 let new_len = inline_len + bytes.len();
986 if new_len <= 12 {
987 self.inline_buf[inline_len..new_len].copy_from_slice(bytes);
988 self.inline_len = new_len as u8;
989 return;
990 }
991
992 self.builder.ensure_long_capacity(new_len as u32);
996 let cursor = self.builder.in_progress.len();
997 self.builder
998 .in_progress
999 .extend_from_slice(&self.inline_buf[..inline_len]);
1000 self.builder.in_progress.extend_from_slice(bytes);
1001 self.spill_cursor = Some(cursor);
1002 }
1003
1004 #[inline]
1005 fn write_char(&mut self, c: char) {
1006 let len = c.len_utf8();
1007 if self.spill_cursor.is_some() {
1008 push_char_to_vec(&mut self.builder.in_progress, c);
1009 return;
1010 }
1011
1012 let inline_len = self.inline_len as usize;
1013 let new_len = inline_len + len;
1014 if new_len <= 12 {
1015 c.encode_utf8(&mut self.inline_buf[inline_len..new_len]);
1016 self.inline_len = new_len as u8;
1017 return;
1018 }
1019
1020 self.builder.ensure_long_capacity(new_len as u32);
1021 let cursor = self.builder.in_progress.len();
1022 self.builder
1023 .in_progress
1024 .extend_from_slice(&self.inline_buf[..inline_len]);
1025 push_char_to_vec(&mut self.builder.in_progress, c);
1026 self.spill_cursor = Some(cursor);
1027 }
1028}
1029
1030#[inline]
1031fn push_char_to_vec(v: &mut Vec<u8>, c: char) {
1032 let mut buf = [0u8; 4];
1033 v.extend_from_slice(c.encode_utf8(&mut buf).as_bytes());
1034}
1035
1036pub(crate) trait BulkNullStringArrayBuilder {
1063 type Writer<'a>: StringWriter
1067 where
1068 Self: 'a;
1069
1070 fn append_value(&mut self, value: &str);
1077
1078 fn append_placeholder(&mut self);
1081
1082 fn append_with<F>(&mut self, f: F)
1093 where
1094 F: for<'a> FnOnce(&mut Self::Writer<'a>);
1095
1096 unsafe fn append_byte_map<F: FnMut(u8) -> u8>(&mut self, src: &[u8], map: F);
1113
1114 fn finish(self, nulls: Option<NullBuffer>) -> Result<ArrayRef>;
1121}
1122
1123impl<O: OffsetSizeTrait> BulkNullStringArrayBuilder for GenericStringArrayBuilder<O> {
1124 type Writer<'a> = GenericStringWriter<'a>;
1125
1126 #[inline]
1127 fn append_value(&mut self, value: &str) {
1128 GenericStringArrayBuilder::<O>::append_value(self, value)
1129 }
1130 #[inline]
1131 fn append_placeholder(&mut self) {
1132 GenericStringArrayBuilder::<O>::append_placeholder(self)
1133 }
1134 #[inline]
1135 fn append_with<F>(&mut self, f: F)
1136 where
1137 F: for<'a> FnOnce(&mut Self::Writer<'a>),
1138 {
1139 GenericStringArrayBuilder::<O>::append_with(self, f)
1140 }
1141 #[inline]
1142 unsafe fn append_byte_map<F: FnMut(u8) -> u8>(&mut self, src: &[u8], map: F) {
1143 unsafe { GenericStringArrayBuilder::<O>::append_byte_map(self, src, map) }
1145 }
1146 fn finish(self, nulls: Option<NullBuffer>) -> Result<ArrayRef> {
1147 Ok(Arc::new(GenericStringArrayBuilder::<O>::finish(
1148 self, nulls,
1149 )?))
1150 }
1151}
1152
1153impl BulkNullStringArrayBuilder for StringViewArrayBuilder {
1154 type Writer<'a> = StringViewWriter<'a>;
1155
1156 #[inline]
1157 fn append_value(&mut self, value: &str) {
1158 StringViewArrayBuilder::append_value(self, value)
1159 }
1160 #[inline]
1161 fn append_placeholder(&mut self) {
1162 StringViewArrayBuilder::append_placeholder(self)
1163 }
1164 #[inline]
1165 fn append_with<F>(&mut self, f: F)
1166 where
1167 F: for<'a> FnOnce(&mut Self::Writer<'a>),
1168 {
1169 StringViewArrayBuilder::append_with(self, f)
1170 }
1171 #[inline]
1172 unsafe fn append_byte_map<F: FnMut(u8) -> u8>(&mut self, src: &[u8], map: F) {
1173 unsafe { StringViewArrayBuilder::append_byte_map(self, src, map) }
1175 }
1176 fn finish(self, nulls: Option<NullBuffer>) -> Result<ArrayRef> {
1177 Ok(Arc::new(StringViewArrayBuilder::finish(self, nulls)?))
1178 }
1179}
1180
1181#[inline(never)]
1199pub(crate) fn append_view(
1200 views_buffer: &mut Vec<u128>,
1201 original_view: &u128,
1202 substr: &str,
1203 start_offset: u32,
1204) {
1205 let substr_len = substr.len();
1206 let sub_view = if substr_len > 12 {
1207 let view = ByteView::from(*original_view);
1208 make_view(
1209 substr.as_bytes(),
1210 view.buffer_index,
1211 view.offset + start_offset,
1212 )
1213 } else {
1214 make_view(substr.as_bytes(), 0, 0)
1215 };
1216 views_buffer.push(sub_view);
1217}
1218
1219#[derive(Debug)]
1220pub(crate) enum ColumnarValueRef<'a> {
1221 Scalar(&'a [u8]),
1222 NullableArray(&'a StringArray),
1223 NonNullableArray(&'a StringArray),
1224 NullableLargeStringArray(&'a LargeStringArray),
1225 NonNullableLargeStringArray(&'a LargeStringArray),
1226 NullableStringViewArray(&'a StringViewArray),
1227 NonNullableStringViewArray(&'a StringViewArray),
1228 NullableBinaryArray(&'a BinaryArray),
1229 NonNullableBinaryArray(&'a BinaryArray),
1230 NullableLargeBinaryArray(&'a LargeBinaryArray),
1231 NonNullableLargeBinaryArray(&'a LargeBinaryArray),
1232 NullableBinaryViewArray(&'a BinaryViewArray),
1233 NonNullableBinaryViewArray(&'a BinaryViewArray),
1234}
1235
1236impl ColumnarValueRef<'_> {
1237 #[inline]
1238 pub fn is_valid(&self, i: usize) -> bool {
1239 match &self {
1240 Self::Scalar(_)
1241 | Self::NonNullableArray(_)
1242 | Self::NonNullableLargeStringArray(_)
1243 | Self::NonNullableStringViewArray(_)
1244 | Self::NonNullableBinaryArray(_)
1245 | Self::NonNullableLargeBinaryArray(_)
1246 | Self::NonNullableBinaryViewArray(_) => true,
1247 Self::NullableArray(array) => array.is_valid(i),
1248 Self::NullableStringViewArray(array) => array.is_valid(i),
1249 Self::NullableLargeStringArray(array) => array.is_valid(i),
1250 Self::NullableBinaryArray(array) => array.is_valid(i),
1251 Self::NullableLargeBinaryArray(array) => array.is_valid(i),
1252 Self::NullableBinaryViewArray(array) => array.is_valid(i),
1253 }
1254 }
1255
1256 #[inline]
1257 pub fn nulls(&self) -> Option<NullBuffer> {
1258 match &self {
1259 Self::Scalar(_)
1260 | Self::NonNullableArray(_)
1261 | Self::NonNullableStringViewArray(_)
1262 | Self::NonNullableLargeStringArray(_)
1263 | Self::NonNullableBinaryArray(_)
1264 | Self::NonNullableLargeBinaryArray(_)
1265 | Self::NonNullableBinaryViewArray(_) => None,
1266 Self::NullableArray(array) => array.nulls().cloned(),
1267 Self::NullableStringViewArray(array) => array.nulls().cloned(),
1268 Self::NullableLargeStringArray(array) => array.nulls().cloned(),
1269 Self::NullableBinaryArray(array) => array.nulls().cloned(),
1270 Self::NullableLargeBinaryArray(array) => array.nulls().cloned(),
1271 Self::NullableBinaryViewArray(array) => array.nulls().cloned(),
1272 }
1273 }
1274
1275 pub(crate) fn from_columnar_value<'a>(
1280 col: &'a ColumnarValue,
1281 data_size: &mut usize,
1282 len: usize,
1283 size_factor: usize,
1284 convert_to_str: bool,
1285 ) -> Result<Option<ColumnarValueRef<'a>>> {
1286 match col {
1287 ColumnarValue::Scalar(ScalarValue::Utf8(maybe_value))
1288 | ColumnarValue::Scalar(ScalarValue::LargeUtf8(maybe_value))
1289 | ColumnarValue::Scalar(ScalarValue::Utf8View(maybe_value)) => {
1290 if let Some(s) = maybe_value {
1291 *data_size += s.len() * len * size_factor;
1292 Ok(Some(ColumnarValueRef::Scalar(s.as_bytes())))
1293 } else {
1294 Ok(None)
1295 }
1296 }
1297 ColumnarValue::Scalar(ScalarValue::Binary(maybe_value))
1298 | ColumnarValue::Scalar(ScalarValue::LargeBinary(maybe_value))
1299 | ColumnarValue::Scalar(ScalarValue::BinaryView(maybe_value))
1300 | ColumnarValue::Scalar(ScalarValue::FixedSizeBinary(_, maybe_value)) => {
1301 if let Some(b) = maybe_value {
1302 *data_size += b.len() * len * size_factor;
1303 Ok(Some(ColumnarValueRef::Scalar(b.as_slice())))
1304 } else {
1305 Ok(None)
1306 }
1307 }
1308 ColumnarValue::Scalar(scalar) if scalar.is_null() => {
1309 Ok(None)
1311 }
1312 ColumnarValue::Scalar(scalar) if convert_to_str => {
1313 match scalar.try_as_str() {
1314 Some(Some(s)) => {
1315 *data_size += s.len() * len * size_factor;
1316 Ok(Some(ColumnarValueRef::Scalar(s.as_bytes())))
1317 }
1318 Some(None) => unreachable!("null handled above"),
1319 None => {
1320 internal_err!("Expected string or binary, got {scalar:?}")
1321 }
1322 }
1323 }
1324 ColumnarValue::Array(array) => match array.data_type() {
1325 DataType::Utf8 => {
1326 let string_array = as_string_array(array)?;
1327 *data_size += string_array.values().len() * size_factor;
1328 let column = if array.is_nullable() {
1329 ColumnarValueRef::NullableArray(string_array)
1330 } else {
1331 ColumnarValueRef::NonNullableArray(string_array)
1332 };
1333 Ok(Some(column))
1334 }
1335 DataType::LargeUtf8 => {
1336 let string_array = as_largestring_array(array);
1337 *data_size += string_array.values().len() * size_factor;
1338 let column = if array.is_nullable() {
1339 ColumnarValueRef::NullableLargeStringArray(string_array)
1340 } else {
1341 ColumnarValueRef::NonNullableLargeStringArray(string_array)
1342 };
1343 Ok(Some(column))
1344 }
1345 DataType::Utf8View => {
1346 let string_array = as_string_view_array(array)?;
1347 *data_size += string_array.total_buffer_bytes_used() * size_factor;
1348 let column = if array.is_nullable() {
1349 ColumnarValueRef::NullableStringViewArray(string_array)
1350 } else {
1351 ColumnarValueRef::NonNullableStringViewArray(string_array)
1352 };
1353 Ok(Some(column))
1354 }
1355 DataType::Binary => {
1356 let binary_array = as_binary_array(array)?;
1357 *data_size += binary_array.values().len() * size_factor;
1358 let column = if array.is_nullable() {
1359 ColumnarValueRef::NullableBinaryArray(binary_array)
1360 } else {
1361 ColumnarValueRef::NonNullableBinaryArray(binary_array)
1362 };
1363 Ok(Some(column))
1364 }
1365 DataType::LargeBinary => {
1366 let binary_array = as_large_binary_array(array)?;
1367 *data_size += binary_array.values().len() * size_factor;
1368 let column = if array.is_nullable() {
1369 ColumnarValueRef::NullableLargeBinaryArray(binary_array)
1370 } else {
1371 ColumnarValueRef::NonNullableLargeBinaryArray(binary_array)
1372 };
1373 Ok(Some(column))
1374 }
1375 DataType::BinaryView => {
1376 let binary_array = as_binary_view_array(array)?;
1377 *data_size += binary_array.total_buffer_bytes_used() * size_factor;
1378 let column = if array.is_nullable() {
1379 ColumnarValueRef::NullableBinaryViewArray(binary_array)
1380 } else {
1381 ColumnarValueRef::NonNullableBinaryViewArray(binary_array)
1382 };
1383 Ok(Some(column))
1384 }
1385 other => {
1386 plan_err!(
1387 "Input was {other} which is not a supported datatype for concat function"
1388 )
1389 }
1390 },
1391 _ => {
1392 plan_err!(
1393 "Input was {col} which is not a supported datatype for concat function"
1394 )
1395 }
1396 }
1397 }
1398}
1399
1400pub(crate) fn widest_binary_type(types: &[DataType]) -> DataType {
1403 if types.iter().any(|t| matches!(t, DataType::BinaryView)) {
1404 DataType::BinaryView
1405 } else if types
1406 .iter()
1407 .any(|t| matches!(t, DataType::LargeBinary | DataType::FixedSizeBinary(_)))
1408 {
1409 DataType::LargeBinary
1410 } else {
1411 DataType::Binary
1412 }
1413}
1414
1415pub(crate) fn widest_string_type(types: &[DataType]) -> DataType {
1418 if types.iter().any(|t| matches!(t, DataType::Utf8View)) {
1419 DataType::Utf8View
1420 } else if types.iter().any(|t| matches!(t, DataType::LargeUtf8)) {
1421 DataType::LargeUtf8
1422 } else {
1423 DataType::Utf8
1424 }
1425}
1426
1427#[cfg(test)]
1428mod tests {
1429 use super::*;
1430
1431 fn run_scenario<B, F>(mut builder: B, expected: &[Option<&str>], scenario: F)
1440 where
1441 B: BulkNullStringArrayBuilder,
1442 F: FnOnce(&mut B),
1443 {
1444 scenario(&mut builder);
1445 let bits: Vec<bool> = expected.iter().map(|x| x.is_some()).collect();
1446 let nulls = if bits.iter().any(|v| !v) {
1447 Some(NullBuffer::from(bits))
1448 } else {
1449 None
1450 };
1451 let array = builder.finish(nulls).unwrap();
1452 let owned: Vec<Option<&str>> = expected.to_vec();
1453 if let Some(a) = array.as_any().downcast_ref::<StringArray>() {
1454 assert_eq!(a, &StringArray::from(owned));
1455 } else if let Some(a) = array.as_any().downcast_ref::<LargeStringArray>() {
1456 assert_eq!(a, &LargeStringArray::from(owned));
1457 } else if let Some(a) = array.as_any().downcast_ref::<StringViewArray>() {
1458 assert_eq!(a, &StringViewArray::from(owned));
1459 } else {
1460 panic!("unexpected array type");
1461 }
1462 }
1463
1464 macro_rules! check_on_all_builders {
1470 ($expected:expr, $scenario:expr $(,)?) => {{
1471 let expected = $expected;
1472 run_scenario(
1473 GenericStringArrayBuilder::<i32>::with_capacity(0, 0),
1474 expected,
1475 $scenario,
1476 );
1477 run_scenario(
1478 GenericStringArrayBuilder::<i64>::with_capacity(0, 0),
1479 expected,
1480 $scenario,
1481 );
1482 run_scenario(
1483 StringViewArrayBuilder::with_capacity(0),
1484 expected,
1485 $scenario,
1486 );
1487 }};
1488 }
1489
1490 fn assert_finish_errs_on_length_mismatch<B>(mut builder: B)
1491 where
1492 B: BulkNullStringArrayBuilder,
1493 {
1494 builder.append_value("a");
1495 builder.append_value("b");
1496 let nulls = NullBuffer::from(vec![true, false, true]);
1497 assert!(builder.finish(Some(nulls)).is_err());
1498 }
1499
1500 #[test]
1501 #[should_panic(expected = "capacity integer overflow")]
1502 fn test_overflow_concat_string_builder() {
1503 let _builder = ConcatStringBuilder::with_capacity(usize::MAX, usize::MAX);
1504 }
1505
1506 #[test]
1507 #[should_panic(expected = "capacity integer overflow")]
1508 fn test_overflow_concat_large_string_builder() {
1509 let _builder = ConcatLargeStringBuilder::with_capacity(usize::MAX, usize::MAX);
1510 }
1511
1512 #[test]
1513 fn bulk_append_value_with_nulls() {
1514 check_on_all_builders!(
1515 &[
1516 Some("a string longer than twelve bytes"),
1517 None,
1518 Some("short"),
1519 None,
1520 ],
1521 |b| {
1522 b.append_value("a string longer than twelve bytes");
1523 b.append_placeholder();
1524 b.append_value("short");
1525 b.append_placeholder();
1526 },
1527 );
1528 }
1529
1530 #[test]
1531 fn bulk_empty_builder() {
1532 check_on_all_builders!(&[], |_b| {});
1533 }
1534
1535 #[test]
1536 fn bulk_all_placeholders() {
1537 check_on_all_builders!(&[None, None, None], |b| {
1538 b.append_placeholder();
1539 b.append_placeholder();
1540 b.append_placeholder();
1541 });
1542 }
1543
1544 #[test]
1545 fn bulk_append_value_no_nulls() {
1546 check_on_all_builders!(
1547 &[
1548 Some("foo"),
1549 Some(""),
1550 Some("a string longer than twelve bytes")
1551 ],
1552 |b| {
1553 b.append_value("foo");
1554 b.append_value("");
1555 b.append_value("a string longer than twelve bytes");
1556 },
1557 );
1558 }
1559
1560 #[test]
1561 fn bulk_append_with() {
1562 check_on_all_builders!(
1563 &[
1564 Some("hello"),
1565 None,
1566 Some("hello world"),
1567 Some("a long string of 25 bytes"),
1568 Some(""),
1569 ],
1570 |b| {
1571 b.append_with(|w| w.write_str("hello"));
1572 b.append_placeholder();
1573 b.append_with(|w| {
1574 w.write_str("hello ");
1575 w.write_str("world");
1576 });
1577 b.append_with(|w| w.write_str("a long string of 25 bytes"));
1578 b.append_with(|_w| {});
1579 },
1580 );
1581 }
1582
1583 #[test]
1584 fn bulk_append_with_chars() {
1585 check_on_all_builders!(&[Some("hé!"), Some("x")], |b| {
1586 b.append_with(|w| {
1587 w.write_char('h');
1588 w.write_char('é');
1589 w.write_char('!');
1590 });
1591 b.append_with(|w| w.write_char('x'));
1592 });
1593 }
1594
1595 #[test]
1596 fn bulk_append_byte_map() {
1597 check_on_all_builders!(&[Some("HELLO"), Some("aXcaX"), Some("")], |b| unsafe {
1599 b.append_byte_map(b"hello", |x| x.to_ascii_uppercase());
1600 b.append_byte_map(b"abcab", |x| if x == b'b' { b'X' } else { x });
1601 b.append_byte_map(b"", |x| x);
1602 },);
1603 }
1604
1605 #[test]
1606 fn bulk_finish_errors_on_null_buffer_length_mismatch() {
1607 assert_finish_errs_on_length_mismatch(
1608 GenericStringArrayBuilder::<i32>::with_capacity(2, 4),
1609 );
1610 assert_finish_errs_on_length_mismatch(
1611 GenericStringArrayBuilder::<i64>::with_capacity(2, 4),
1612 );
1613 assert_finish_errs_on_length_mismatch(StringViewArrayBuilder::with_capacity(2));
1614 }
1615
1616 #[test]
1617 fn generic_string_builder_try_append_success_path() {
1618 let mut builder = GenericStringArrayBuilder::<i32>::with_capacity(4, 16);
1619 builder.try_append_value("abc").unwrap();
1620 builder.try_append_placeholder().unwrap();
1621 unsafe {
1623 builder
1624 .try_append_byte_map(b"de", |b| b.to_ascii_uppercase())
1625 .unwrap();
1626 }
1627 builder
1628 .try_append_with(|w| {
1629 w.write_str("f");
1630 w.write_char('é');
1631 })
1632 .unwrap();
1633
1634 let nulls = Some(NullBuffer::from(vec![true, false, true, true]));
1635 let array = builder.finish(nulls).unwrap();
1636 assert_eq!(
1637 &array,
1638 &StringArray::from(vec![Some("abc"), None, Some("DE"), Some("fé")])
1639 );
1640 }
1641
1642 #[test]
1643 fn generic_string_builder_mixed_append_success_path() {
1644 let mut builder = GenericStringArrayBuilder::<i32>::with_capacity(4, 16);
1645 builder.append_value("ab");
1646 builder.try_append_value("cd").unwrap();
1647 unsafe {
1649 builder.append_byte_map(b"ef", |b| b.to_ascii_uppercase());
1650 builder
1651 .try_append_byte_map(b"gh", |b| b.to_ascii_uppercase())
1652 .unwrap();
1653 }
1654
1655 let array = builder.finish(None).unwrap();
1656 assert_eq!(
1657 &array,
1658 &StringArray::from(vec![Some("ab"), Some("cd"), Some("EF"), Some("GH")])
1659 );
1660 }
1661
1662 #[test]
1663 fn string_view_builder_try_append_success_path() {
1664 let mut builder = StringViewArrayBuilder::with_capacity(3);
1665 builder.try_append_value("abc").unwrap();
1666 builder.try_append_placeholder().unwrap();
1667 builder.try_append_value("a long string value").unwrap();
1668
1669 let nulls = Some(NullBuffer::from(vec![true, false, true]));
1670 let array = builder.finish(nulls).unwrap();
1671 assert_eq!(array.value(0), "abc");
1672 assert!(array.is_null(1));
1673 assert_eq!(array.value(2), "a long string value");
1674 }
1675
1676 #[test]
1677 fn generic_string_builder_try_offset_overflow() {
1678 let err = try_offset::<i32>(i32::MAX as usize + 1)
1679 .unwrap_err()
1680 .to_string();
1681 assert!(
1682 err.contains("byte array offset overflow"),
1683 "unexpected error: {err}"
1684 );
1685 }
1686
1687 #[test]
1688 fn generic_string_builder_try_append_bytes_overflow() {
1689 let mut builder = GenericStringArrayBuilder::<i32>::with_capacity(0, 0);
1690 let err = builder
1691 .try_append_bytes(i32::MAX as usize + 1, |_| unreachable!())
1692 .unwrap_err()
1693 .to_string();
1694 assert!(
1695 err.contains("byte array offset overflow"),
1696 "unexpected error: {err}"
1697 );
1698 }
1699
1700 #[test]
1701 #[cfg(debug_assertions)]
1702 #[should_panic(expected = "placeholder rows")]
1703 fn string_array_builder_placeholder_without_null_mask() {
1704 let mut builder = GenericStringArrayBuilder::<i32>::with_capacity(2, 4);
1705 builder.append_value("a");
1706 builder.append_placeholder();
1707 let nulls = NullBuffer::from(vec![true, true]);
1709 let _ = builder.finish(Some(nulls));
1710 }
1711
1712 #[test]
1713 #[cfg(debug_assertions)]
1714 #[should_panic(expected = "placeholder rows")]
1715 fn string_array_builder_placeholder_with_none_null_buffer() {
1716 let mut builder = GenericStringArrayBuilder::<i32>::with_capacity(1, 4);
1717 builder.append_placeholder();
1718 let _ = builder.finish(None);
1719 }
1720
1721 #[test]
1722 #[cfg(debug_assertions)]
1723 #[should_panic(expected = "placeholder rows")]
1724 fn string_view_array_builder_placeholder_without_null_mask() {
1725 let mut builder = StringViewArrayBuilder::with_capacity(2);
1726 builder.append_value("a");
1727 builder.append_placeholder();
1728 let nulls = NullBuffer::from(vec![true, true]);
1729 let _ = builder.finish(Some(nulls));
1730 }
1731
1732 #[test]
1733 #[cfg(debug_assertions)]
1734 #[should_panic(expected = "placeholder rows")]
1735 fn string_view_array_builder_placeholder_with_none_null_buffer() {
1736 let mut builder = StringViewArrayBuilder::with_capacity(1);
1737 builder.append_placeholder();
1738 let _ = builder.finish(None);
1739 }
1740
1741 #[test]
1742 fn string_view_array_builder_append_with_inline() {
1743 let mut builder = StringViewArrayBuilder::with_capacity(4);
1745 let inputs = ["hello", "world!", "", "0123456789ab"];
1746 for s in &inputs {
1747 builder.append_with(|w| w.write_str(s));
1748 }
1749 let array = builder.finish(None).unwrap();
1750 assert_eq!(array.len(), inputs.len());
1751 for (i, s) in inputs.iter().enumerate() {
1752 assert_eq!(array.value(i), *s);
1753 }
1754 assert_eq!(array.data_buffers().len(), 0);
1755 }
1756
1757 #[test]
1758 fn string_view_array_builder_append_byte_map() {
1759 let mut builder = StringViewArrayBuilder::with_capacity(4);
1760 unsafe {
1762 builder.append_byte_map(b"hello", |b| b.to_ascii_uppercase());
1763 builder.append_byte_map(b"a long string of 25 bytes", |b| {
1764 if b == b' ' { b'_' } else { b }
1765 });
1766 builder.append_byte_map(b"abcdefghijkl", |b| b);
1768 builder.append_byte_map(b"", |b| b);
1769 }
1770 let array = builder.finish(None).unwrap();
1771 assert_eq!(array.value(0), "HELLO");
1772 assert_eq!(array.value(1), "a_long_string_of_25_bytes");
1773 assert_eq!(array.value(2), "abcdefghijkl");
1774 assert_eq!(array.value(3), "");
1775 assert_eq!(array.data_buffers().len(), 1);
1776 assert_eq!(array.data_buffers()[0].len(), 25);
1777 }
1778
1779 #[test]
1780 fn string_view_array_builder_append_with_at_inline_boundary() {
1781 let mut builder = StringViewArrayBuilder::with_capacity(2);
1783 builder.append_with(|w| {
1784 w.write_str("hello");
1785 w.write_str(" world!");
1786 });
1787 builder.append_with(|w| {
1788 for _ in 0..6 {
1789 w.write_str("ab");
1790 }
1791 });
1792 let array = builder.finish(None).unwrap();
1793 assert_eq!(array.value(0), "hello world!");
1794 assert_eq!(array.value(1), "abababababab");
1795 assert_eq!(array.data_buffers().len(), 0);
1796 }
1797
1798 #[test]
1799 fn string_view_array_builder_append_with_spill_on_overflow() {
1800 let mut builder = StringViewArrayBuilder::with_capacity(1);
1802 builder.append_with(|w| {
1803 w.write_str("hello world!");
1804 w.write_str("X");
1805 });
1806 let array = builder.finish(None).unwrap();
1807 assert_eq!(array.value(0), "hello world!X");
1808 assert_eq!(array.data_buffers().len(), 1);
1809 assert_eq!(array.data_buffers()[0].len(), 13);
1810 }
1811
1812 #[test]
1813 fn string_view_array_builder_append_with_long_single_write() {
1814 let mut builder = StringViewArrayBuilder::with_capacity(1);
1817 builder.append_with(|w| w.write_str("a long string of 25 bytes"));
1818 let array = builder.finish(None).unwrap();
1819 assert_eq!(array.value(0), "a long string of 25 bytes");
1820 assert_eq!(array.data_buffers().len(), 1);
1821 assert_eq!(array.data_buffers()[0].len(), 25);
1822 }
1823
1824 #[test]
1825 fn string_view_array_builder_append_with_many_small_writes_spilling() {
1826 let mut builder = StringViewArrayBuilder::with_capacity(1);
1828 builder.append_with(|w| {
1829 for _ in 0..30 {
1830 w.write_str("ab");
1831 }
1832 });
1833 let array = builder.finish(None).unwrap();
1834 assert_eq!(array.value(0), "ab".repeat(30));
1835 assert_eq!(array.data_buffers().len(), 1);
1836 assert_eq!(array.data_buffers()[0].len(), 60);
1837 }
1838
1839 #[test]
1840 fn string_view_array_builder_append_with_chars() {
1841 let mut builder = StringViewArrayBuilder::with_capacity(2);
1844 builder.append_with(|w| {
1845 w.write_char('é');
1846 w.write_char('!');
1847 });
1848 builder.append_with(|w| {
1849 for _ in 0..10 {
1850 w.write_char('🦀');
1851 }
1852 });
1853 let array = builder.finish(None).unwrap();
1854 assert_eq!(array.value(0), "é!");
1855 assert_eq!(array.value(1), "🦀".repeat(10));
1856 }
1857
1858 #[test]
1859 fn string_view_array_builder_append_with_block_rotation() {
1860 const STR_LEN: usize = 500;
1863 const N: usize = 40;
1864 let s = "x".repeat(STR_LEN);
1865 let mut builder = StringViewArrayBuilder::with_capacity(N);
1866 for _ in 0..N {
1867 builder.append_with(|w| w.write_str(&s));
1868 }
1869 let array = builder.finish(None).unwrap();
1870 assert_eq!(array.len(), N);
1871 assert!(
1872 array.data_buffers().len() >= 2,
1873 "expected multiple data buffers, got {}",
1874 array.data_buffers().len()
1875 );
1876 let total: usize = array.data_buffers().iter().map(|b| b.len()).sum();
1877 assert_eq!(total, N * STR_LEN);
1878 for i in 0..N {
1879 assert_eq!(array.value(i), s);
1880 }
1881 }
1882
1883 #[test]
1884 fn string_view_array_builder_flushes_full_blocks() {
1885 let value = "x".repeat(300);
1889 let mut builder = StringViewArrayBuilder::with_capacity(100);
1890 for _ in 0..100 {
1891 builder.append_value(&value);
1892 }
1893 let array = builder.finish(None).unwrap();
1894 assert_eq!(array.len(), 100);
1895 assert!(
1896 array.data_buffers().len() > 1,
1897 "expected multiple data buffers, got {}",
1898 array.data_buffers().len()
1899 );
1900 for i in 0..100 {
1901 assert_eq!(array.value(i), value);
1902 }
1903 }
1904}