vortex_onpair/compute/
compare.rs1use vortex_array::ArrayRef;
5use vortex_array::ArrayView;
6use vortex_array::ExecutionCtx;
7use vortex_array::IntoArray;
8use vortex_array::arrays::BoolArray;
9use vortex_array::arrays::ConstantArray;
10use vortex_array::builtins::ArrayBuiltins;
11use vortex_array::dtype::DType;
12use vortex_array::scalar::Scalar;
13use vortex_array::scalar_fn::fns::binary::CompareKernel;
14use vortex_array::scalar_fn::fns::operators::CompareOperator;
15use vortex_buffer::BitBuffer;
16use vortex_error::VortexResult;
17
18use crate::OnPair;
19use crate::OnPairArraySlotsExt;
20
21impl CompareKernel for OnPair {
22 fn compare(
23 lhs: ArrayView<'_, Self>,
24 rhs: &ArrayRef,
25 operator: CompareOperator,
26 ctx: &mut ExecutionCtx,
27 ) -> VortexResult<Option<ArrayRef>> {
28 let Some(constant) = rhs.as_constant() else {
29 return Ok(None);
30 };
31 let is_empty = match constant.dtype() {
32 DType::Utf8(_) => constant.as_utf8().is_empty(),
33 DType::Binary(_) => constant.as_binary().is_empty(),
34 _ => return Ok(None),
35 };
36 if is_empty != Some(true) {
37 return Ok(None);
38 }
39
40 let lengths = lhs.uncompressed_lengths();
41 let buffer = match operator {
42 CompareOperator::Gte => BitBuffer::new_set(lhs.len()),
44 CompareOperator::Lt => BitBuffer::new_unset(lhs.len()),
46 _ => lengths
47 .binary(
48 ConstantArray::new(Scalar::zero_value(lengths.dtype()), lengths.len())
49 .into_array(),
50 operator.into(),
51 )?
52 .execute(ctx)?,
53 };
54 Ok(Some(
55 BoolArray::new(
56 buffer,
57 lhs.validity()?
58 .union_nullability(constant.dtype().nullability()),
59 )
60 .into_array(),
61 ))
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use std::sync::LazyLock;
68
69 use rstest::rstest;
70 use vortex_array::IntoArray;
71 use vortex_array::VortexSessionExecute;
72 use vortex_array::array_session;
73 use vortex_array::arrays::BoolArray;
74 use vortex_array::arrays::ConstantArray;
75 use vortex_array::arrays::VarBinArray;
76 use vortex_array::assert_arrays_eq;
77 use vortex_array::builtins::ArrayBuiltins;
78 use vortex_array::dtype::DType;
79 use vortex_array::dtype::Nullability;
80 use vortex_array::scalar::Scalar;
81 use vortex_array::scalar_fn::fns::operators::Operator;
82 use vortex_error::VortexResult;
83 use vortex_session::VortexSession;
84
85 use crate::compress::DEFAULT_DICT12_CONFIG;
86 use crate::compress::onpair_compress;
87
88 static SESSION: LazyLock<VortexSession> = LazyLock::new(array_session);
89
90 #[cfg_attr(miri, ignore)]
91 #[rstest]
92 #[case(Operator::Eq, [true, false, true, false])]
93 #[case(Operator::NotEq, [false, true, false, true])]
94 #[case(Operator::Gt, [false, true, false, true])]
95 #[case(Operator::Gte, [true, true, true, true])]
96 #[case(Operator::Lt, [false, false, false, false])]
97 #[case(Operator::Lte, [true, false, true, false])]
98 fn compare_empty_string(#[case] op: Operator, #[case] expected: [bool; 4]) -> VortexResult<()> {
99 let input = VarBinArray::from_iter(
100 [Some(""), Some("a"), Some(""), Some("bbb")],
101 DType::Utf8(Nullability::NonNullable),
102 );
103 let mut ctx = SESSION.create_execution_ctx();
104 let arr = onpair_compress(input.as_array(), DEFAULT_DICT12_CONFIG, &mut ctx)?.into_array();
105
106 let result = arr
107 .binary(ConstantArray::new("", input.len()).into_array(), op)?
108 .execute::<BoolArray>(&mut ctx)?;
109 assert_arrays_eq!(&result, &BoolArray::from_iter(expected), &mut ctx);
110 Ok(())
111 }
112
113 #[cfg_attr(miri, ignore)]
114 #[test]
115 fn compare_empty_string_nullable() -> VortexResult<()> {
116 let input = VarBinArray::from_iter(
117 [Some(""), None, Some("x")],
118 DType::Utf8(Nullability::Nullable),
119 );
120 let mut ctx = SESSION.create_execution_ctx();
121 let arr = onpair_compress(input.as_array(), DEFAULT_DICT12_CONFIG, &mut ctx)?.into_array();
122
123 let eq_empty = arr
124 .clone()
125 .binary(ConstantArray::new("", arr.len()).into_array(), Operator::Eq)?
126 .execute::<BoolArray>(&mut ctx)?;
127 assert_arrays_eq!(
128 &eq_empty,
129 &BoolArray::from_iter([Some(true), None, Some(false)]),
130 &mut ctx
131 );
132
133 let null_rhs =
134 ConstantArray::new(Scalar::null(DType::Utf8(Nullability::Nullable)), arr.len());
135 let eq_null = arr
136 .binary(null_rhs.into_array(), Operator::Eq)?
137 .execute::<BoolArray>(&mut ctx)?;
138 assert_arrays_eq!(
139 &eq_null,
140 &BoolArray::from_iter([None::<bool>, None, None]),
141 &mut ctx
142 );
143 Ok(())
144 }
145}