1use arrow_array::builder::BooleanBuilder;
8use arrow_array::cast::AsArray;
9use arrow_array::types::{Float32Type, Float64Type, RunEndIndexType};
10use arrow_array::{Array, BooleanArray, RunArray, downcast_run_array};
11use arrow_buffer::{ArrowNativeType, BooleanBuffer};
12use arrow_schema::{DataType, Field};
13
14use crate::arrow::arrow_writer::{
15 FixedLenByteArrayVisitor, PrimitiveVisitor, visit_fixed_len_byte_array, visit_i32, visit_i64,
16};
17use crate::arrow::schema::arrow_to_parquet_type;
18use crate::basic::{ConvertedType, LogicalType, TimeUnit, Type as PhysicalType};
19use crate::bloom_filter::Sbbf;
20use crate::data_type::AsBytes;
21use crate::errors::{ParquetError, Result};
22use crate::schema::types::{ColumnDescriptor, Type};
23
24#[derive(Debug, Clone)]
76pub struct ArrowSbbf<'a> {
77 sbbf: &'a Sbbf,
78 arrow_type: DataType,
80 physical_type: PhysicalType,
81 type_length: usize,
87}
88
89impl<'a> ArrowSbbf<'a> {
90 pub fn try_new(
100 sbbf: &'a Sbbf,
101 column: &ColumnDescriptor,
102 arrow_type: DataType,
103 ) -> Result<Self> {
104 validate(column.self_type(), &arrow_type)?;
105 Ok(Self {
106 sbbf,
107 arrow_type,
108 physical_type: column.physical_type(),
109 type_length: column.type_length().try_into().unwrap_or(0),
112 })
113 }
114
115 pub fn arrow_type(&self) -> &DataType {
117 &self.arrow_type
118 }
119
120 pub fn check(&self, array: &dyn Array) -> Result<BooleanArray> {
129 if let Some(dictionary) = array.as_any_dictionary_opt() {
130 let values = self.check(dictionary.values().as_ref())?;
131 let found = arrow_select::take::take(&values, dictionary.keys(), None)?;
132 return Ok(found.as_boolean().clone());
133 }
134 let value_type = value_type(&self.arrow_type);
135 match array.data_type() {
136 DataType::Null => return Ok(BooleanArray::new_null(array.len())),
137 DataType::RunEndEncoded(_, _) => {
138 return downcast_run_array!(
139 array => self.check_run_array(array),
140 _ => unreachable!("RunEndEncoded array is not a RunArray"),
141 );
142 }
143 data_type if data_type != value_type => {
144 return Err(ParquetError::General(format!(
145 "Cannot check {data_type} values with an ArrowSbbf for {value_type} values"
146 )));
147 }
148 _ => {}
149 }
150
151 let sbbf = self.sbbf;
154 let found = match self.physical_type {
155 PhysicalType::INT32 => visit_i32(array, CheckPrimitive { sbbf })?,
156 PhysicalType::INT64 => visit_i64(array, CheckPrimitive { sbbf })?,
157 PhysicalType::FLOAT => {
158 CheckPrimitive { sbbf }.slice(array.as_primitive::<Float32Type>().values())?
159 }
160 PhysicalType::DOUBLE => {
161 CheckPrimitive { sbbf }.slice(array.as_primitive::<Float64Type>().values())?
162 }
163 PhysicalType::BOOLEAN => array
164 .as_boolean()
165 .values()
166 .iter()
167 .map(|v| sbbf.check(&v))
168 .collect(),
169 PhysicalType::BYTE_ARRAY => check_byte_array(sbbf, array),
170 PhysicalType::FIXED_LEN_BYTE_ARRAY => {
171 let visitor = CheckFixedLenByteArray {
172 sbbf,
173 len: array.len(),
174 type_length: self.type_length,
175 };
176 visit_fixed_len_byte_array(array, visitor)?
177 }
178 PhysicalType::INT96 => unreachable!("ArrowWriter does not write INT96 columns"),
179 };
180 Ok(BooleanArray::new(found, array.logical_nulls()))
181 }
182
183 fn check_run_array<R: RunEndIndexType>(&self, array: &RunArray<R>) -> Result<BooleanArray> {
185 let found = self.check(array.values_slice().as_ref())?;
186 let mut builder = BooleanBuilder::with_capacity(array.len());
187 let mut run_start = 0;
188 for (i, run_end) in array.run_ends().sliced_values().enumerate() {
189 let run_end = run_end.as_usize();
190 match found.is_valid(i) {
191 true => builder.append_n(run_end - run_start, found.value(i)),
192 false => builder.append_nulls(run_end - run_start),
193 }
194 run_start = run_end;
195 }
196 Ok(builder.finish())
197 }
198}
199
200fn value_type(data_type: &DataType) -> &DataType {
203 match data_type {
204 DataType::Dictionary(_, values) => value_type(values),
205 DataType::RunEndEncoded(_, values) => value_type(values.data_type()),
206 _ => data_type,
207 }
208}
209
210fn validate(column: &Type, arrow_type: &DataType) -> Result<()> {
216 if !arrow_type.is_nested() {
217 let field = Field::new(column.name(), arrow_type.clone(), true);
218 for coerce_types in [false, true] {
221 let written = arrow_to_parquet_type(&field, coerce_types)?;
222 if is_stored_as(&written, column) {
223 return Ok(());
224 }
225 }
226 }
227 Err(type_mismatch(column, arrow_type))
228}
229
230fn type_mismatch(column: &Type, arrow_type: &DataType) -> ParquetError {
231 ParquetError::General(format!(
232 "Cannot check a bloom filter of type {} with {arrow_type} values",
233 describe(column)
234 ))
235}
236
237fn is_stored_as(written: &Type, column: &Type) -> bool {
245 let physical_type = column.get_physical_type();
246 match (decimal_scale(written), decimal_scale(column)) {
247 (Some(written_scale), Some(scale)) => {
250 written_scale == scale && physical_type != PhysicalType::BYTE_ARRAY
251 }
252 (None, None) => {
253 written.get_physical_type() == physical_type
254 && (physical_type != PhysicalType::FIXED_LEN_BYTE_ARRAY
255 || type_length(written) == type_length(column))
256 && time_unit(written) == time_unit(column)
260 }
261 _ => false,
262 }
263}
264
265fn decimal_scale(t: &Type) -> Option<i32> {
267 let info = t.get_basic_info();
268 let decimal = matches!(info.logical_type_ref(), Some(LogicalType::Decimal(_)))
269 || info.converted_type() == ConvertedType::DECIMAL;
270 decimal.then(|| t.get_scale())
271}
272
273fn time_unit(t: &Type) -> Option<TimeUnit> {
275 let info = t.get_basic_info();
276 match info.logical_type_ref() {
277 Some(LogicalType::Time(time) | LogicalType::Timestamp(time)) => Some(time.unit),
278 _ => match info.converted_type() {
279 ConvertedType::TIME_MILLIS | ConvertedType::TIMESTAMP_MILLIS => Some(TimeUnit::MILLIS),
280 ConvertedType::TIME_MICROS | ConvertedType::TIMESTAMP_MICROS => Some(TimeUnit::MICROS),
281 _ => None,
282 },
283 }
284}
285
286fn type_length(t: &Type) -> i32 {
287 match t {
288 Type::PrimitiveType { type_length, .. } => *type_length,
289 Type::GroupType { .. } => -1,
290 }
291}
292
293fn describe(column: &Type) -> String {
295 let physical_type = column.get_physical_type();
296 let length = match physical_type {
297 PhysicalType::FIXED_LEN_BYTE_ARRAY => format!("({})", type_length(column)),
298 _ => String::new(),
299 };
300 let decimal = decimal_scale(column)
301 .map(|scale| format!(" DECIMAL({}, {scale})", column.get_precision()))
302 .unwrap_or_default();
303 let unit = time_unit(column)
304 .map(|unit| format!(" ({unit:?})"))
305 .unwrap_or_default();
306 format!("{physical_type}{length}{decimal}{unit}")
307}
308
309struct CheckPrimitive<'a> {
311 sbbf: &'a Sbbf,
312}
313
314impl<T: AsBytes> PrimitiveVisitor<T> for CheckPrimitive<'_> {
315 type Output = BooleanBuffer;
316
317 fn slice(self, values: &[T]) -> Result<BooleanBuffer> {
318 Ok(values.iter().map(|v| self.sbbf.check(v)).collect())
319 }
320
321 fn map<S: Copy>(self, values: &[S], convert: impl Fn(S) -> T) -> Result<BooleanBuffer> {
322 Ok(values
323 .iter()
324 .map(|v| self.sbbf.check(&convert(*v)))
325 .collect())
326 }
327}
328
329struct CheckFixedLenByteArray<'a> {
331 sbbf: &'a Sbbf,
332 len: usize,
334 type_length: usize,
335}
336
337impl FixedLenByteArrayVisitor for CheckFixedLenByteArray<'_> {
338 type Output = BooleanBuffer;
339
340 fn decimal_length(&self, _precision: u8, _native_length: usize) -> usize {
341 self.type_length
343 }
344
345 fn values(self, length: usize, fill: impl Fn(usize, &mut [u8])) -> Result<BooleanBuffer> {
346 debug_assert_eq!(length, self.type_length);
349 let mut value = vec![0; length];
350 Ok((0..self.len)
351 .map(|i| {
352 value.fill(0);
353 fill(i, &mut value);
354 self.sbbf.check(value.as_slice())
355 })
356 .collect())
357 }
358}
359
360fn check_byte_array(sbbf: &Sbbf, array: &dyn Array) -> BooleanBuffer {
362 match array.data_type() {
363 DataType::Utf8 => check_bytes(sbbf, array.as_string::<i32>()),
364 DataType::LargeUtf8 => check_bytes(sbbf, array.as_string::<i64>()),
365 DataType::Utf8View => check_bytes(sbbf, array.as_string_view()),
366 DataType::Binary => check_bytes(sbbf, array.as_binary::<i32>()),
367 DataType::LargeBinary => check_bytes(sbbf, array.as_binary::<i64>()),
368 DataType::BinaryView => check_bytes(sbbf, array.as_binary_view()),
369 d => unreachable!("ArrowWriter does not write {d} to BYTE_ARRAY columns"),
370 }
371}
372
373fn check_bytes<'a, T: AsRef<[u8]> + ?Sized + 'a>(
374 sbbf: &Sbbf,
375 values: impl arrow_array::ArrayAccessor<Item = &'a T>,
376) -> BooleanBuffer {
377 (0..values.len())
378 .map(|i| sbbf.check(values.value(i).as_ref()))
379 .collect()
380}
381
382#[cfg(test)]
383mod tests {
384 use super::*;
385 use crate::arrow::ArrowWriter;
386 use crate::file::properties::{ReaderProperties, WriterProperties};
387 use crate::file::reader::{FileReader, SerializedFileReader};
388 use crate::file::serialized_reader::ReadOptionsBuilder;
389 use crate::schema::types::{ColumnDescPtr, ColumnPath};
390 use arrow_array::types::{Int16Type, Int32Type};
391 use arrow_array::*;
392 use arrow_buffer::{IntervalDayTime, i256};
393 use arrow_schema::{IntervalUnit, TimeUnit};
394 use bytes::Bytes;
395 use std::sync::Arc;
396
397 fn write_and_read_bloom_filters(
399 batch: &RecordBatch,
400 coerce_types: bool,
401 ) -> Vec<(Sbbf, ColumnDescPtr)> {
402 let props = WriterProperties::builder()
403 .set_bloom_filter_enabled(true)
404 .set_coerce_types(coerce_types)
405 .build();
406 let mut buffer = Vec::new();
407 let mut writer = ArrowWriter::try_new(&mut buffer, batch.schema(), Some(props)).unwrap();
408 writer.write(batch).unwrap();
409 writer.close().unwrap();
410
411 let options = ReadOptionsBuilder::new()
412 .with_reader_properties(
413 ReaderProperties::builder()
414 .set_read_bloom_filter(true)
415 .build(),
416 )
417 .build();
418 let reader = SerializedFileReader::new_with_options(Bytes::from(buffer), options).unwrap();
419 let row_group = reader.get_row_group(0).unwrap();
420 (0..batch.num_columns())
421 .map(|i| {
422 let sbbf = row_group.get_column_bloom_filter(i).unwrap().clone();
423 let column = reader.metadata().row_group(0).column(i).column_descr_ptr();
424 (sbbf, column)
425 })
426 .collect()
427 }
428
429 fn write_and_read_bloom_filter(array: ArrayRef, coerce_types: bool) -> (Sbbf, ColumnDescPtr) {
431 let batch = RecordBatch::try_from_iter([("c", array)]).unwrap();
432 write_and_read_bloom_filters(&batch, coerce_types)
433 .pop()
434 .unwrap()
435 }
436
437 struct Written {
439 sbbf: Sbbf,
440 column: ColumnDescPtr,
441 }
442
443 impl Written {
444 fn new(array: impl Array + 'static) -> Self {
446 Self::with_coerce_types(Arc::new(array), false)
447 }
448
449 fn with_coerce_types(array: ArrayRef, coerce_types: bool) -> Self {
450 let (sbbf, column) = write_and_read_bloom_filter(array, coerce_types);
451 Self { sbbf, column }
452 }
453
454 fn arrow_sbbf(&self, arrow_type: DataType) -> ArrowSbbf<'_> {
456 ArrowSbbf::try_new(&self.sbbf, &self.column, arrow_type).unwrap()
457 }
458
459 fn check(&self, array: &dyn Array) -> BooleanArray {
461 let arrow_type = array.data_type().clone();
462 self.arrow_sbbf(arrow_type).check(array).unwrap()
463 }
464
465 fn assert_found(&self, array: &dyn Array, expected: &[bool]) {
467 assert_eq!(self.check(array), BooleanArray::from(expected.to_vec()));
468 }
469
470 fn assert_rejects(&self, arrow_type: DataType, column_type: &str) {
473 let err = ArrowSbbf::try_new(&self.sbbf, &self.column, arrow_type.clone()).unwrap_err();
474 assert_eq!(
475 err.to_string(),
476 format!(
477 "Parquet error: Cannot check a bloom filter of type {column_type} with {arrow_type} values"
478 )
479 );
480 }
481 }
482
483 fn assert_round_trip(written: ArrayRef, absent: ArrayRef, coerce_types: bool) {
485 let column = Written::with_coerce_types(written.clone(), coerce_types);
486 column.assert_found(written.as_ref(), &vec![true; written.len()]);
487 column.assert_found(absent.as_ref(), &vec![false; absent.len()]);
488 }
489
490 #[test]
491 fn time_units_must_match() {
492 let written = TimestampMillisecondArray::from(vec![1_000, 2_000]);
493 let column = Written::new(written.clone());
494 column.assert_found(&written, &[true, true]);
495
496 for unit in [
499 TimeUnit::Second,
500 TimeUnit::Microsecond,
501 TimeUnit::Nanosecond,
502 ] {
503 column.assert_rejects(DataType::Timestamp(unit, None), "INT64 (MILLIS)");
504 }
505 column.assert_rejects(DataType::Int64, "INT64 (MILLIS)");
507
508 let column = Written::new(Time64MicrosecondArray::from(vec![1_000]));
509 column.assert_rejects(DataType::Time64(TimeUnit::Nanosecond), "INT64 (MICROS)");
510
511 let written = TimestampSecondArray::from(vec![1, 2]);
514 let column = Written::new(written.clone());
515 column.assert_found(&written, &[true, true]);
516 column.assert_rejects(DataType::Timestamp(TimeUnit::Millisecond, None), "INT64");
517 let column = Written::new(Time32SecondArray::from(vec![1, 2]));
518 column.assert_rejects(DataType::Time32(TimeUnit::Millisecond), "INT32");
519 }
520
521 #[test]
522 fn narrow_integers() {
523 assert_round_trip(
524 Arc::new(Int8Array::from(vec![i8::MIN, -1, 0, 1, i8::MAX])),
525 Arc::new(Int8Array::from(vec![-2, 2, 100])),
526 false,
527 );
528 assert_round_trip(
529 Arc::new(Int16Array::from(vec![i16::MIN, -1, 0, 1, i16::MAX])),
530 Arc::new(Int16Array::from(vec![-2, 2, 1000])),
531 false,
532 );
533 assert_round_trip(
534 Arc::new(UInt8Array::from(vec![0, 1, 128, u8::MAX])),
535 Arc::new(UInt8Array::from(vec![2, 127, 200])),
536 false,
537 );
538 assert_round_trip(
539 Arc::new(UInt16Array::from(vec![0, 1, 32768, u16::MAX])),
540 Arc::new(UInt16Array::from(vec![2, 32767, 60000])),
541 false,
542 );
543 }
544
545 #[test]
546 fn unsigned_integers_above_signed_max() {
547 assert_round_trip(
548 Arc::new(UInt32Array::from(vec![0, i32::MAX as u32 + 1, u32::MAX])),
549 Arc::new(UInt32Array::from(vec![1, u32::MAX - 1])),
550 false,
551 );
552 assert_round_trip(
553 Arc::new(UInt64Array::from(vec![0, i64::MAX as u64 + 1, u64::MAX])),
554 Arc::new(UInt64Array::from(vec![1, u64::MAX - 1])),
555 false,
556 );
557 }
558
559 #[test]
560 fn date64() {
561 let day = 86_400_000;
562 let written: ArrayRef = Arc::new(Date64Array::from(vec![0, day, 365 * day]));
563 let absent: ArrayRef = Arc::new(Date64Array::from(vec![2 * day, 366 * day]));
564 assert_round_trip(written.clone(), absent.clone(), false);
566 assert_round_trip(written, absent, true);
568 }
569
570 #[test]
571 fn date64_stored_as_days() {
572 let written: ArrayRef = Arc::new(Date64Array::from(vec![5 * 86_400_000, -1]));
574 let column = Written::with_coerce_types(written.clone(), true);
575 assert!(column.sbbf.check(&5_i32));
576 assert!(column.sbbf.check(&0_i32));
577 column.assert_found(written.as_ref(), &[true, true]);
578 }
579
580 #[test]
581 fn decimals() {
582 for precision in [5, 15, 30] {
584 assert_round_trip(
585 Arc::new(decimal128(vec![-12345, 0, 12345], precision, 2)),
586 Arc::new(decimal128(vec![-1, 1, 54321], precision, 2)),
587 false,
588 );
589 }
590 }
591
592 fn decimal128(values: Vec<i128>, precision: u8, scale: i8) -> Decimal128Array {
593 Decimal128Array::from(values)
594 .with_precision_and_scale(precision, scale)
595 .unwrap()
596 }
597
598 #[test]
599 fn decimal_precision_differs_from_column() {
600 let column = Written::new(decimal128(vec![12345, -12345], 30, 2));
602 assert_eq!(column.column.type_length(), 13);
603
604 for precision in [20, 30, 38] {
606 let values = decimal128(vec![12345, -12345, 54321], precision, 2);
607 column.assert_found(&values, &[true, true, false]);
608 }
609 let decimal256 = Decimal256Array::from(vec![i256::from(12345), i256::from(-12345)])
610 .with_precision_and_scale(76, 2)
611 .unwrap();
612 column.assert_found(&decimal256, &[true, true]);
613
614 let decimal32 = Decimal32Array::from(vec![12345, -12345, 54321])
616 .with_precision_and_scale(9, 2)
617 .unwrap();
618 column.assert_found(&decimal32, &[true, true, false]);
619 let decimal64 = Decimal64Array::from(vec![12345, -12345, 54321])
620 .with_precision_and_scale(18, 2)
621 .unwrap();
622 column.assert_found(&decimal64, &[true, true, false]);
623
624 let wide = 1_i128 << 104;
627 let values = decimal128(vec![12345 + wide, -12345 - wide], 38, 2);
628 column.assert_found(&values, &[true, true]);
629 }
630
631 #[test]
632 fn decimal_column_longer_than_i256() {
633 let column = Type::primitive_type_builder("c", PhysicalType::FIXED_LEN_BYTE_ARRAY)
636 .with_length(33)
637 .with_logical_type(Some(LogicalType::decimal(2, 10)))
638 .with_precision(10)
639 .with_scale(2)
640 .build()
641 .unwrap();
642 let column = ColumnDescriptor::new(Arc::new(column), 1, 0, ColumnPath::from("c"));
643 let mut sbbf = Sbbf::new_with_ndv_fpp(10, 0.01).unwrap();
644 for (sign, value) in [(0, 12345), (0xFF, -12345)] {
645 let mut bytes = vec![sign];
646 bytes.extend_from_slice(&i256::from(value).to_be_bytes());
647 sbbf.insert(bytes.as_slice());
648 }
649 let column = Written {
650 sbbf,
651 column: Arc::new(column),
652 };
653 column.assert_found(
654 &decimal128(vec![12345, -12345, 54321], 10, 2),
655 &[true, true, false],
656 );
657 }
658
659 #[test]
660 fn narrower_decimal_type_than_column() {
661 let written = Decimal64Array::from(vec![12345, -12345])
663 .with_precision_and_scale(12, 2)
664 .unwrap();
665 let column = Written::new(written);
666 assert_eq!(column.column.physical_type(), PhysicalType::INT64);
667
668 let decimal32 = Decimal32Array::from(vec![12345, -12345, 54321])
669 .with_precision_and_scale(9, 2)
670 .unwrap();
671 column.assert_found(&decimal32, &[true, true, false]);
672 }
673
674 #[test]
675 fn decimal_too_large_for_precision() {
676 for precision in [5, 15, 20] {
680 let written = decimal128(vec![i128::MAX / 3, -(i128::MAX / 3)], precision, 2);
681 Written::new(written.clone()).assert_found(&written, &[true, true]);
682 }
683 }
684
685 #[test]
686 fn decimal_scale_differs_from_column() {
687 for (precision, column_type) in [
689 (5, "INT32 DECIMAL(5, 2)"),
690 (15, "INT64 DECIMAL(15, 2)"),
691 (30, "FIXED_LEN_BYTE_ARRAY(13) DECIMAL(30, 2)"),
692 ] {
693 let written = decimal128(vec![12345], precision, 2);
694 let column = Written::new(written.clone());
695 column.assert_found(&written, &[true]);
696
697 column.assert_rejects(DataType::Decimal128(precision, 3), column_type);
699 }
700
701 let column = Written::new(Int32Array::from(vec![12345]));
703 column.assert_rejects(DataType::Decimal128(5, 0), "INT32");
704 }
705
706 #[test]
707 fn decimal_column_requires_decimal_values() {
708 for (precision, column_type) in [
710 (5, "INT32 DECIMAL(5, 2)"),
711 (15, "INT64 DECIMAL(15, 2)"),
712 (30, "FIXED_LEN_BYTE_ARRAY(13) DECIMAL(30, 2)"),
713 ] {
714 let column = Written::new(decimal128(vec![500], precision, 2));
715 column.assert_rejects(DataType::Int32, column_type);
717 }
718
719 let column = Written::new(decimal128(vec![500], 30, 2));
720 column.assert_rejects(
721 DataType::FixedSizeBinary(13),
722 "FIXED_LEN_BYTE_ARRAY(13) DECIMAL(30, 2)",
723 );
724 }
725
726 #[test]
727 fn fixed_size_binary_length_differs_from_column() {
728 let written = FixedSizeBinaryArray::try_from_iter([b"abcd", b"efgh"].into_iter()).unwrap();
729 let column = Written::new(written.clone());
730 column.assert_found(&written, &[true, true]);
731 column.assert_rejects(DataType::FixedSizeBinary(3), "FIXED_LEN_BYTE_ARRAY(4)");
732 }
733
734 #[test]
735 fn float16() {
736 let f16 = half::f16::from_f32;
737 assert_round_trip(
738 Arc::new(Float16Array::from(vec![f16(-1.5), f16(0.0), f16(2.25)])),
739 Arc::new(Float16Array::from(vec![f16(1.5), f16(3.0)])),
740 false,
741 );
742 }
743
744 #[test]
745 fn intervals() {
746 assert_round_trip(
747 Arc::new(IntervalYearMonthArray::from(vec![-1, 0, 13])),
748 Arc::new(IntervalYearMonthArray::from(vec![1, 12])),
749 false,
750 );
751 let interval = IntervalDayTime::new;
752 assert_round_trip(
753 Arc::new(IntervalDayTimeArray::from(vec![
754 interval(1, 2),
755 interval(-3, 4),
756 ])),
757 Arc::new(IntervalDayTimeArray::from(vec![
758 interval(2, 1),
759 interval(0, 0),
760 ])),
761 false,
762 );
763 }
764
765 #[test]
766 fn strings() {
767 assert_round_trip(
768 Arc::new(StringArray::from(vec!["a", "bc", ""])),
769 Arc::new(StringArray::from(vec!["b", "abc"])),
770 false,
771 );
772 }
773
774 #[test]
775 fn dictionary_and_nulls() {
776 let column = Written::new(Int8Array::from(vec![1, 2, 3]));
777 let sbbf = column.arrow_sbbf(DataType::Int8);
778
779 let found = sbbf
780 .check(&Int8Array::from(vec![Some(1), None, Some(4)]))
781 .unwrap();
782 assert_eq!(
783 found,
784 BooleanArray::from(vec![Some(true), None, Some(false)])
785 );
786
787 let dictionary = DictionaryArray::<Int32Type>::new(
788 Int32Array::from(vec![Some(1), None, Some(0), Some(1)]),
789 Arc::new(Int8Array::from(vec![4, 3])),
790 );
791 let found = sbbf.check(&dictionary).unwrap();
792 assert_eq!(
793 found,
794 BooleanArray::from(vec![Some(true), None, Some(false), Some(true)])
795 );
796
797 let found = sbbf.check(&NullArray::new(2)).unwrap();
798 assert_eq!(found, BooleanArray::new_null(2));
799 }
800
801 #[test]
802 fn null_array() {
803 let columns: [ArrayRef; 2] = [
804 Arc::new(Float64Array::from(vec![1.5])),
805 Arc::new(StringArray::from(vec!["a"])),
806 ];
807 for written in columns {
808 let arrow_type = written.data_type().clone();
809 let column = Written::with_coerce_types(written, false);
810 let found = column
811 .arrow_sbbf(arrow_type)
812 .check(&NullArray::new(2))
813 .unwrap();
814 assert_eq!(found, BooleanArray::from(vec![None, None]));
815 }
816 }
817
818 #[test]
819 fn run_end_encoded() {
820 let run_ends = Int32Array::from(vec![2, 3, 5, 6]);
821 let values = Int16Array::from(vec![1, -2, 7, 3]);
822 let written = RunArray::<Int32Type>::try_new(&run_ends, &values).unwrap();
823 let column = Written::new(written);
824 let sbbf = column.arrow_sbbf(DataType::Int16);
825
826 let values = Int16Array::from(vec![Some(-2), Some(4), None, Some(1)]);
827 let array =
828 RunArray::<Int16Type>::try_new(&Int16Array::from(vec![1, 3, 4, 6]), &values).unwrap();
829 let found = sbbf.check(&array).unwrap();
830 assert_eq!(
831 found,
832 BooleanArray::from(vec![
833 Some(true),
834 Some(false),
835 Some(false),
836 None,
837 Some(true),
838 Some(true)
839 ])
840 );
841
842 let found = sbbf.check(&array.slice(2, 3)).unwrap();
843 assert_eq!(
844 found,
845 BooleanArray::from(vec![Some(false), None, Some(true)])
846 );
847 }
848
849 #[test]
850 fn unsupported_type() {
851 let column = Written::new(Int8Array::from(vec![1, 2, 3]));
852 column.assert_rejects(DataType::Utf8, "INT32");
853 column.assert_rejects(DataType::new_list(DataType::Int8, true), "INT32");
854
855 let column =
856 Written::new(FixedSizeBinaryArray::try_from_iter([b"abcd"].into_iter()).unwrap());
857 column.assert_rejects(DataType::Int32, "FIXED_LEN_BYTE_ARRAY(4)");
858 column.assert_rejects(
859 DataType::Interval(IntervalUnit::MonthDayNano),
860 "FIXED_LEN_BYTE_ARRAY(4)",
861 );
862 }
863
864 #[test]
865 fn array_type_differs_from_arrow_type() {
866 let column = Written::new(Int8Array::from(vec![1, 2, 3]));
867 let err = column
868 .arrow_sbbf(DataType::Int8)
869 .check(&Int16Array::from(vec![1]))
870 .unwrap_err();
871 assert_eq!(
872 err.to_string(),
873 "Parquet error: Cannot check Int16 values with an ArrowSbbf for Int8 values"
874 );
875
876 let dictionary = DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Int8));
878 let found = column
879 .arrow_sbbf(dictionary)
880 .check(&Int8Array::from(vec![1, 4]))
881 .unwrap();
882 assert_eq!(found, BooleanArray::from(vec![true, false]));
883 }
884
885 fn with_null<T>(values: [T; 4]) -> Vec<Option<T>> {
887 let mut values: Vec<_> = values.into_iter().map(Some).collect();
888 values.insert(2, None);
889 values
890 }
891
892 fn writer_type_columns() -> Vec<(&'static str, ArrayRef)> {
895 let day = 86_400_000;
896 let f16 = half::f16::from_f32;
897 let fsb = |values: Vec<Option<&[u8; 4]>>| -> ArrayRef {
898 Arc::new(
899 FixedSizeBinaryArray::try_from_sparse_iter_with_size(values.into_iter(), 4)
900 .unwrap(),
901 )
902 };
903 let decimal32 = |precision| -> ArrayRef {
906 let values = with_null([-12345, 1, 12345, i32::MAX / 3]);
907 Arc::new(
908 Decimal32Array::from(values)
909 .with_precision_and_scale(precision, 2)
910 .unwrap(),
911 )
912 };
913 let decimal64 = |precision| -> ArrayRef {
914 let values = with_null([-12345, 1, 12345, i64::MAX / 3]);
915 Arc::new(
916 Decimal64Array::from(values)
917 .with_precision_and_scale(precision, 2)
918 .unwrap(),
919 )
920 };
921 let decimal128 = |precision| -> ArrayRef {
922 let values = with_null([-12345, 1, 12345, i128::MAX / 3]);
923 Arc::new(
924 Decimal128Array::from(values)
925 .with_precision_and_scale(precision, 2)
926 .unwrap(),
927 )
928 };
929 let decimal256 = |precision| -> ArrayRef {
930 let large = i256::MAX.wrapping_div(i256::from(3));
931 let values = with_null([i256::from(-12345), i256::from(1), i256::from(12345), large]);
932 Arc::new(
933 Decimal256Array::from(values)
934 .with_precision_and_scale(precision, 2)
935 .unwrap(),
936 )
937 };
938 let strings = with_null(["", "a", "longer than twelve bytes", "é"]);
939 let binaries: Vec<_> = strings.iter().map(|s| s.map(str::as_bytes)).collect();
940 let interval = IntervalDayTime::new;
941 let day_times = with_null([
942 interval(1, 2),
943 interval(-3, 4),
944 interval(0, 0),
945 interval(i32::MAX, i32::MIN),
946 ]);
947 let int16s = Int16Array::from(vec![
948 Some(9),
949 Some(-7),
950 None,
951 Some(3),
952 Some(i16::MIN),
953 Some(5),
954 ]);
955 let keys = Int32Array::from(with_null([0, 1, 2, 3]));
958 let ree_int8 = RunArray::<Int32Type>::try_new(
959 &Int32Array::from(vec![2, 3, 5]),
960 &Int8Array::from(vec![Some(-3), None, Some(i8::MAX)]),
961 );
962 let ree_utf8 = RunArray::<Int16Type>::try_new(
963 &Int16Array::from(vec![1, 3, 5]),
964 &StringArray::from(vec![Some("a"), None, Some("b")]),
965 );
966
967 let time32s = with_null([0, 1, 3600, 86399]);
968 let time64s = with_null([0, 1, 3600, 86399]);
969 let i64s = with_null([-1, 0, 1, i64::MAX]);
970 let float16s = with_null([f16(-1.5), f16(0.0), f16(-0.0), half::f16::NAN]);
971 let date64s = with_null([-1, 0, 5 * day + 1, -5 * day - 1]);
973 let timestamp_ms = TimestampMillisecondArray::from(i64s.clone()).with_timezone("+01:00");
974
975 vec![
976 (
977 "int8",
978 Arc::new(Int8Array::from(with_null([i8::MIN, -1, 1, i8::MAX]))),
979 ),
980 (
981 "int16",
982 Arc::new(Int16Array::from(with_null([i16::MIN, -1, 1, i16::MAX]))),
983 ),
984 (
985 "int32",
986 Arc::new(Int32Array::from(with_null([i32::MIN, -1, 1, i32::MAX]))),
987 ),
988 (
989 "int64",
990 Arc::new(Int64Array::from(with_null([i64::MIN, -1, 1, i64::MAX]))),
991 ),
992 (
993 "uint8",
994 Arc::new(UInt8Array::from(with_null([0, 1, 128, u8::MAX]))),
995 ),
996 (
997 "uint16",
998 Arc::new(UInt16Array::from(with_null([0, 1, 32768, u16::MAX]))),
999 ),
1000 (
1001 "uint32",
1002 Arc::new(UInt32Array::from(with_null([0, 1, 1 << 31, u32::MAX]))),
1003 ),
1004 (
1005 "uint64",
1006 Arc::new(UInt64Array::from(with_null([0, 1, 1 << 63, u64::MAX]))),
1007 ),
1008 ("float16", Arc::new(Float16Array::from(float16s))),
1009 (
1010 "float32",
1011 Arc::new(Float32Array::from(with_null([-1.5, 0.0, -0.0, f32::NAN]))),
1012 ),
1013 (
1014 "float64",
1015 Arc::new(Float64Array::from(with_null([
1016 -1.5,
1017 0.0,
1018 f64::INFINITY,
1019 f64::NAN,
1020 ]))),
1021 ),
1022 (
1023 "bool",
1024 Arc::new(BooleanArray::from(with_null([true, false, true, false]))),
1025 ),
1026 (
1027 "date32",
1028 Arc::new(Date32Array::from(with_null([-1, 0, 1, 20000]))),
1029 ),
1030 ("date64", Arc::new(Date64Array::from(date64s))),
1031 (
1032 "time32_s",
1033 Arc::new(Time32SecondArray::from(time32s.clone())),
1034 ),
1035 ("time32_ms", Arc::new(Time32MillisecondArray::from(time32s))),
1036 (
1037 "time64_us",
1038 Arc::new(Time64MicrosecondArray::from(time64s.clone())),
1039 ),
1040 ("time64_ns", Arc::new(Time64NanosecondArray::from(time64s))),
1041 (
1042 "timestamp_s",
1043 Arc::new(TimestampSecondArray::from(i64s.clone())),
1044 ),
1045 ("timestamp_ms", Arc::new(timestamp_ms)),
1046 (
1047 "timestamp_us",
1048 Arc::new(TimestampMicrosecondArray::from(i64s.clone())),
1049 ),
1050 (
1051 "timestamp_ns",
1052 Arc::new(TimestampNanosecondArray::from(i64s.clone())),
1053 ),
1054 (
1055 "duration_s",
1056 Arc::new(DurationSecondArray::from(i64s.clone())),
1057 ),
1058 (
1059 "duration_ms",
1060 Arc::new(DurationMillisecondArray::from(i64s.clone())),
1061 ),
1062 (
1063 "duration_us",
1064 Arc::new(DurationMicrosecondArray::from(i64s.clone())),
1065 ),
1066 ("duration_ns", Arc::new(DurationNanosecondArray::from(i64s))),
1067 ("decimal32_5", decimal32(5)),
1069 ("decimal32_9", decimal32(9)),
1070 ("decimal64_5", decimal64(5)),
1071 ("decimal64_18", decimal64(18)),
1072 ("decimal128_5", decimal128(5)),
1073 ("decimal128_15", decimal128(15)),
1074 ("decimal128_20", decimal128(20)),
1075 ("decimal128_38", decimal128(38)),
1076 ("decimal256_5", decimal256(5)),
1077 ("decimal256_15", decimal256(15)),
1078 ("decimal256_30", decimal256(30)),
1079 ("decimal256_76", decimal256(76)),
1080 (
1081 "interval_year_month",
1082 Arc::new(IntervalYearMonthArray::from(with_null([
1083 -1,
1084 0,
1085 13,
1086 i32::MAX,
1087 ]))),
1088 ),
1089 (
1090 "interval_day_time",
1091 Arc::new(IntervalDayTimeArray::from(day_times)),
1092 ),
1093 (
1094 "fixed_size_binary",
1095 fsb(with_null([
1096 b"abcd",
1097 b"\0\0\0\0",
1098 b"\xff\xfe\xfd\xfc",
1099 b"abce",
1100 ])),
1101 ),
1102 ("utf8", Arc::new(StringArray::from(strings.clone()))),
1103 (
1104 "large_utf8",
1105 Arc::new(LargeStringArray::from(strings.clone())),
1106 ),
1107 ("utf8_view", Arc::new(StringViewArray::from(strings))),
1108 ("binary", Arc::new(BinaryArray::from(binaries.clone()))),
1109 (
1110 "large_binary",
1111 Arc::new(LargeBinaryArray::from(binaries.clone())),
1112 ),
1113 ("binary_view", Arc::new(BinaryViewArray::from(binaries))),
1114 ("sliced_int16", Arc::new(int16s.slice(1, 5))),
1115 (
1117 "dictionary_int16",
1118 Arc::new(DictionaryArray::new(
1119 keys.clone(),
1120 Arc::new(Int16Array::from(vec![-1, i16::MAX, 7, i16::MIN])),
1121 )),
1122 ),
1123 (
1124 "dictionary_decimal",
1125 Arc::new(DictionaryArray::new(
1126 keys.clone(),
1127 Arc::new(
1128 Decimal128Array::from(vec![-12345, 1, 12345, i128::MAX / 3])
1129 .with_precision_and_scale(30, 2)
1130 .unwrap(),
1131 ),
1132 )),
1133 ),
1134 (
1135 "dictionary_fixed_size_binary",
1136 Arc::new(DictionaryArray::new(
1137 keys.clone(),
1138 fsb(vec![
1139 Some(b"abcd"),
1140 Some(b"wxyz"),
1141 Some(b"efgh"),
1142 Some(b"ijkl"),
1143 ]),
1144 )),
1145 ),
1146 (
1147 "dictionary_utf8",
1148 Arc::new(DictionaryArray::new(
1149 keys,
1150 Arc::new(StringArray::from(vec![
1151 "a",
1152 "longer than twelve bytes",
1153 "b",
1154 "c",
1155 ])),
1156 )),
1157 ),
1158 ("ree_int8", Arc::new(ree_int8.unwrap())),
1159 ("ree_utf8", Arc::new(ree_utf8.unwrap())),
1160 ]
1161 }
1162
1163 #[test]
1167 fn every_writer_type() {
1168 let columns = writer_type_columns();
1169 let batch = RecordBatch::try_from_iter(columns.clone()).unwrap();
1170 let (head, tail) = (batch.slice(0, 3), batch.slice(3, 2));
1173 for coerce_types in [false, true] {
1174 let all = write_and_read_bloom_filters(&batch, coerce_types);
1175 let first_rows = write_and_read_bloom_filters(&head, coerce_types);
1176 for (i, (name, _)) in columns.iter().enumerate() {
1177 let context = format!("{name} with coerce_types {coerce_types}");
1178 let check = |(sbbf, column): &(Sbbf, ColumnDescPtr), array: &ArrayRef| {
1179 ArrowSbbf::try_new(sbbf, column, array.data_type().clone())
1180 .and_then(|sbbf| sbbf.check(array.as_ref()))
1181 .unwrap_or_else(|e| panic!("{context}: {e}"))
1182 };
1183 let array = batch.column(i);
1185 let found = check(&all[i], array);
1186 let nulls = array.logical_nulls();
1187 let valid = |i| nulls.as_ref().is_none_or(|nulls| nulls.is_valid(i));
1188 let expected: BooleanArray =
1189 (0..array.len()).map(|i| valid(i).then_some(true)).collect();
1190 assert_eq!(found, expected, "{context}");
1191
1192 if *name != "bool" {
1194 let found = check(&first_rows[i], tail.column(i));
1195 assert_eq!(found, BooleanArray::from(vec![false, false]), "{context}");
1196 }
1197 }
1198 }
1199 }
1200}