1use std::cmp::Ordering;
5
6use reifydb_core::value::column::{ColumnWithName, buffer::ColumnBuffer};
7use reifydb_value::{
8 error::Diagnostic,
9 fragment::Fragment,
10 reifydb_assertions, return_error,
11 value::{
12 container::{
13 blob::BlobContainer, bool::BoolContainer, identity_id::IdentityIdContainer,
14 number::NumberContainer, temporal::TemporalContainer, utf8::Utf8Container, uuid::UuidContainer,
15 },
16 decimal::Decimal,
17 int::Int,
18 is::{IsNumber, IsTemporal, IsUuid},
19 number::{compare::partial_cmp, promote::Promote},
20 uint::Uint,
21 value_type::ValueType,
22 },
23};
24
25use super::option::binary_op_unwrap_option;
26use crate::Result;
27
28macro_rules! dispatch_compare {
29
30 (
31 $left:expr, $right:expr;
32 $fragment:expr;
33 $($extra:tt)*
34 ) => {
35 dispatch_compare!(@rows
36 ($left, $right) ($fragment)
37 [(Float4, f32) (Float8, f64) (Int1, i8) (Int2, i16) (Int4, i32) (Int8, i64) (Int16, i128) (Uint1, u8) (Uint2, u16) (Uint4, u32) (Uint8, u64) (Uint16, u128)]
38 {$($extra)*}
39 {}
40 )
41 };
42
43
44 (@rows
45 ($left:expr, $right:expr) ($fragment:expr)
46 [($L:ident, $Lt:ty) $($rest:tt)*]
47 {$($extra:tt)*}
48 {$($acc:tt)*}
49 ) => {
50 dispatch_compare!(@rows
51 ($left, $right) ($fragment)
52 [$($rest)*]
53 {$($extra)*}
54 {
55 $($acc)*
56 (ColumnBuffer::$L(l), ColumnBuffer::Float4(r)) => { return Ok(compare_number::<Op, $Lt, f32>(l, r, $fragment)); },
57 (ColumnBuffer::$L(l), ColumnBuffer::Float8(r)) => { return Ok(compare_number::<Op, $Lt, f64>(l, r, $fragment)); },
58 (ColumnBuffer::$L(l), ColumnBuffer::Int1(r)) => { return Ok(compare_number::<Op, $Lt, i8>(l, r, $fragment)); },
59 (ColumnBuffer::$L(l), ColumnBuffer::Int2(r)) => { return Ok(compare_number::<Op, $Lt, i16>(l, r, $fragment)); },
60 (ColumnBuffer::$L(l), ColumnBuffer::Int4(r)) => { return Ok(compare_number::<Op, $Lt, i32>(l, r, $fragment)); },
61 (ColumnBuffer::$L(l), ColumnBuffer::Int8(r)) => { return Ok(compare_number::<Op, $Lt, i64>(l, r, $fragment)); },
62 (ColumnBuffer::$L(l), ColumnBuffer::Int16(r)) => { return Ok(compare_number::<Op, $Lt, i128>(l, r, $fragment)); },
63 (ColumnBuffer::$L(l), ColumnBuffer::Uint1(r)) => { return Ok(compare_number::<Op, $Lt, u8>(l, r, $fragment)); },
64 (ColumnBuffer::$L(l), ColumnBuffer::Uint2(r)) => { return Ok(compare_number::<Op, $Lt, u16>(l, r, $fragment)); },
65 (ColumnBuffer::$L(l), ColumnBuffer::Uint4(r)) => { return Ok(compare_number::<Op, $Lt, u32>(l, r, $fragment)); },
66 (ColumnBuffer::$L(l), ColumnBuffer::Uint8(r)) => { return Ok(compare_number::<Op, $Lt, u64>(l, r, $fragment)); },
67 (ColumnBuffer::$L(l), ColumnBuffer::Uint16(r)) => { return Ok(compare_number::<Op, $Lt, u128>(l, r, $fragment)); },
68 (ColumnBuffer::$L(l), ColumnBuffer::Int { container: r, .. }) => { return Ok(compare_number::<Op, $Lt, Int>(l, r, $fragment)); },
69 (ColumnBuffer::$L(l), ColumnBuffer::Uint { container: r, .. }) => { return Ok(compare_number::<Op, $Lt, Uint>(l, r, $fragment)); },
70 (ColumnBuffer::$L(l), ColumnBuffer::Decimal { container: r, .. }) => { return Ok(compare_number::<Op, $Lt, Decimal>(l, r, $fragment)); },
71 }
72 )
73 };
74
75
76 (@rows
77 ($left:expr, $right:expr) ($fragment:expr)
78 []
79 {$($extra:tt)*}
80 {$($acc:tt)*}
81 ) => {
82 match ($left, $right) {
83
84 $($acc)*
85
86
87 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Float4(r)) => { return Ok(compare_number::<Op, Int, f32>(l, r, $fragment)); },
88 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Float8(r)) => { return Ok(compare_number::<Op, Int, f64>(l, r, $fragment)); },
89 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Int1(r)) => { return Ok(compare_number::<Op, Int, i8>(l, r, $fragment)); },
90 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Int2(r)) => { return Ok(compare_number::<Op, Int, i16>(l, r, $fragment)); },
91 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Int4(r)) => { return Ok(compare_number::<Op, Int, i32>(l, r, $fragment)); },
92 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Int8(r)) => { return Ok(compare_number::<Op, Int, i64>(l, r, $fragment)); },
93 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Int16(r)) => { return Ok(compare_number::<Op, Int, i128>(l, r, $fragment)); },
94 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Uint1(r)) => { return Ok(compare_number::<Op, Int, u8>(l, r, $fragment)); },
95 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Uint2(r)) => { return Ok(compare_number::<Op, Int, u16>(l, r, $fragment)); },
96 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Uint4(r)) => { return Ok(compare_number::<Op, Int, u32>(l, r, $fragment)); },
97 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Uint8(r)) => { return Ok(compare_number::<Op, Int, u64>(l, r, $fragment)); },
98 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Uint16(r)) => { return Ok(compare_number::<Op, Int, u128>(l, r, $fragment)); },
99 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Int { container: r, .. }) => { return Ok(compare_number::<Op, Int, Int>(l, r, $fragment)); },
100 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Uint { container: r, .. }) => { return Ok(compare_number::<Op, Int, Uint>(l, r, $fragment)); },
101 (ColumnBuffer::Int { container: l, .. }, ColumnBuffer::Decimal { container: r, .. }) => { return Ok(compare_number::<Op, Int, Decimal>(l, r, $fragment)); },
102
103
104 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Float4(r)) => { return Ok(compare_number::<Op, Uint, f32>(l, r, $fragment)); },
105 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Float8(r)) => { return Ok(compare_number::<Op, Uint, f64>(l, r, $fragment)); },
106 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Int1(r)) => { return Ok(compare_number::<Op, Uint, i8>(l, r, $fragment)); },
107 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Int2(r)) => { return Ok(compare_number::<Op, Uint, i16>(l, r, $fragment)); },
108 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Int4(r)) => { return Ok(compare_number::<Op, Uint, i32>(l, r, $fragment)); },
109 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Int8(r)) => { return Ok(compare_number::<Op, Uint, i64>(l, r, $fragment)); },
110 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Int16(r)) => { return Ok(compare_number::<Op, Uint, i128>(l, r, $fragment)); },
111 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Uint1(r)) => { return Ok(compare_number::<Op, Uint, u8>(l, r, $fragment)); },
112 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Uint2(r)) => { return Ok(compare_number::<Op, Uint, u16>(l, r, $fragment)); },
113 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Uint4(r)) => { return Ok(compare_number::<Op, Uint, u32>(l, r, $fragment)); },
114 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Uint8(r)) => { return Ok(compare_number::<Op, Uint, u64>(l, r, $fragment)); },
115 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Uint16(r)) => { return Ok(compare_number::<Op, Uint, u128>(l, r, $fragment)); },
116 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Int { container: r, .. }) => { return Ok(compare_number::<Op, Uint, Int>(l, r, $fragment)); },
117 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Uint { container: r, .. }) => { return Ok(compare_number::<Op, Uint, Uint>(l, r, $fragment)); },
118 (ColumnBuffer::Uint { container: l, .. }, ColumnBuffer::Decimal { container: r, .. }) => { return Ok(compare_number::<Op, Uint, Decimal>(l, r, $fragment)); },
119
120
121 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Float4(r)) => { return Ok(compare_number::<Op, Decimal, f32>(l, r, $fragment)); },
122 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Float8(r)) => { return Ok(compare_number::<Op, Decimal, f64>(l, r, $fragment)); },
123 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Int1(r)) => { return Ok(compare_number::<Op, Decimal, i8>(l, r, $fragment)); },
124 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Int2(r)) => { return Ok(compare_number::<Op, Decimal, i16>(l, r, $fragment)); },
125 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Int4(r)) => { return Ok(compare_number::<Op, Decimal, i32>(l, r, $fragment)); },
126 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Int8(r)) => { return Ok(compare_number::<Op, Decimal, i64>(l, r, $fragment)); },
127 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Int16(r)) => { return Ok(compare_number::<Op, Decimal, i128>(l, r, $fragment)); },
128 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Uint1(r)) => { return Ok(compare_number::<Op, Decimal, u8>(l, r, $fragment)); },
129 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Uint2(r)) => { return Ok(compare_number::<Op, Decimal, u16>(l, r, $fragment)); },
130 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Uint4(r)) => { return Ok(compare_number::<Op, Decimal, u32>(l, r, $fragment)); },
131 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Uint8(r)) => { return Ok(compare_number::<Op, Decimal, u64>(l, r, $fragment)); },
132 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Uint16(r)) => { return Ok(compare_number::<Op, Decimal, u128>(l, r, $fragment)); },
133 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Int { container: r, .. }) => { return Ok(compare_number::<Op, Decimal, Int>(l, r, $fragment)); },
134 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Uint { container: r, .. }) => { return Ok(compare_number::<Op, Decimal, Uint>(l, r, $fragment)); },
135 (ColumnBuffer::Decimal { container: l, .. }, ColumnBuffer::Decimal { container: r, .. }) => { return Ok(compare_number::<Op, Decimal, Decimal>(l, r, $fragment)); },
136
137
138 $($extra)*
139 }
140 };
141}
142
143pub(crate) trait CompareOp {
144 fn compare_ordering(ordering: Option<Ordering>) -> bool;
145 fn compare_bool(_l: bool, _r: bool) -> Option<bool> {
146 None
147 }
148}
149
150pub(crate) struct Equal;
151pub(crate) struct NotEqual;
152pub(crate) struct GreaterThan;
153pub(crate) struct GreaterThanEqual;
154pub(crate) struct LessThan;
155pub(crate) struct LessThanEqual;
156
157impl CompareOp for Equal {
158 #[inline]
159 fn compare_ordering(o: Option<Ordering>) -> bool {
160 o == Some(Ordering::Equal)
161 }
162 #[inline]
163 fn compare_bool(l: bool, r: bool) -> Option<bool> {
164 Some(l == r)
165 }
166}
167
168impl CompareOp for NotEqual {
169 #[inline]
170 fn compare_ordering(o: Option<Ordering>) -> bool {
171 o != Some(Ordering::Equal)
172 }
173 #[inline]
174 fn compare_bool(l: bool, r: bool) -> Option<bool> {
175 Some(l != r)
176 }
177}
178
179impl CompareOp for GreaterThan {
180 #[inline]
181 fn compare_ordering(o: Option<Ordering>) -> bool {
182 o == Some(Ordering::Greater)
183 }
184}
185
186impl CompareOp for GreaterThanEqual {
187 #[inline]
188 fn compare_ordering(o: Option<Ordering>) -> bool {
189 matches!(o, Some(Ordering::Greater) | Some(Ordering::Equal))
190 }
191}
192
193impl CompareOp for LessThan {
194 #[inline]
195 fn compare_ordering(o: Option<Ordering>) -> bool {
196 o == Some(Ordering::Less)
197 }
198}
199
200impl CompareOp for LessThanEqual {
201 #[inline]
202 fn compare_ordering(o: Option<Ordering>) -> bool {
203 matches!(o, Some(Ordering::Less) | Some(Ordering::Equal))
204 }
205}
206
207#[inline]
208fn compare_number<Op: CompareOp, L, R>(
209 l: &NumberContainer<L>,
210 r: &NumberContainer<R>,
211 fragment: Fragment,
212) -> ColumnWithName
213where
214 L: Promote<R> + IsNumber,
215 R: IsNumber,
216 <L as Promote<R>>::Output: IsNumber,
217{
218 reifydb_assertions! {
219 assert_eq!(l.len(), r.len());
220 }
221
222 let data: Vec<bool> =
223 l.data().iter()
224 .zip(r.data().iter())
225 .map(|(l_val, r_val)| Op::compare_ordering(partial_cmp(l_val, r_val)))
226 .collect();
227
228 ColumnWithName::new(Fragment::internal(fragment.text()), ColumnBuffer::bool(data))
229}
230
231#[inline]
232fn compare_temporal<Op: CompareOp, T>(
233 l: &TemporalContainer<T>,
234 r: &TemporalContainer<T>,
235 fragment: Fragment,
236) -> ColumnWithName
237where
238 T: IsTemporal + Copy + PartialOrd,
239{
240 reifydb_assertions! {
241 assert_eq!(l.len(), r.len());
242 }
243
244 let data: Vec<bool> =
245 l.data().iter()
246 .zip(r.data().iter())
247 .map(|(l_val, r_val)| Op::compare_ordering(l_val.partial_cmp(r_val)))
248 .collect();
249
250 ColumnWithName::new(Fragment::internal(fragment.text()), ColumnBuffer::bool(data))
251}
252
253#[inline]
254fn compare_uuid<Op: CompareOp, T>(l: &UuidContainer<T>, r: &UuidContainer<T>, fragment: Fragment) -> ColumnWithName
255where
256 T: IsUuid + PartialOrd,
257{
258 reifydb_assertions! {
259 assert_eq!(l.len(), r.len());
260 }
261
262 let data: Vec<bool> =
263 l.data().iter()
264 .zip(r.data().iter())
265 .map(|(l_val, r_val)| Op::compare_ordering(l_val.partial_cmp(r_val)))
266 .collect();
267
268 ColumnWithName::new(Fragment::internal(fragment.text()), ColumnBuffer::bool(data))
269}
270
271#[inline]
272fn compare_identity_id<Op: CompareOp>(
273 l: &IdentityIdContainer,
274 r: &IdentityIdContainer,
275 fragment: Fragment,
276) -> ColumnWithName {
277 reifydb_assertions! {
278 assert_eq!(l.len(), r.len());
279 }
280
281 let data: Vec<bool> =
282 l.iter().zip(r.iter()).map(|(l_val, r_val)| Op::compare_ordering(l_val.partial_cmp(&r_val))).collect();
283
284 ColumnWithName::new(Fragment::internal(fragment.text()), ColumnBuffer::bool(data))
285}
286
287#[inline]
288fn compare_blob<Op: CompareOp>(l: &BlobContainer, r: &BlobContainer, fragment: Fragment) -> ColumnWithName {
289 reifydb_assertions! {
290 assert_eq!(l.len(), r.len());
291 }
292
293 let data: Vec<bool> = l
294 .iter_bytes()
295 .zip(r.iter_bytes())
296 .map(|(l_val, r_val)| Op::compare_ordering(l_val.partial_cmp(r_val)))
297 .collect();
298
299 ColumnWithName::new(Fragment::internal(fragment.text()), ColumnBuffer::bool(data))
300}
301
302#[inline]
303fn compare_utf8<Op: CompareOp>(l: &Utf8Container, r: &Utf8Container, fragment: Fragment) -> ColumnWithName {
304 reifydb_assertions! {
305 assert_eq!(l.len(), r.len());
306 }
307
308 let data: Vec<bool> = l
309 .iter_str()
310 .zip(r.iter_str())
311 .map(|(l_val, r_val)| Op::compare_ordering(l_val.partial_cmp(r_val)))
312 .collect();
313
314 ColumnWithName::new(Fragment::internal(fragment.text()), ColumnBuffer::bool(data))
315}
316
317#[inline]
318fn compare_bool<Op: CompareOp>(l: &BoolContainer, r: &BoolContainer, fragment: Fragment) -> Option<ColumnWithName> {
319 reifydb_assertions! {
320 assert_eq!(l.len(), r.len());
321 }
322
323 let data: Vec<bool> =
324 l.data().iter()
325 .zip(r.data().iter())
326 .filter_map(|(l_val, r_val)| Op::compare_bool(l_val, r_val))
327 .collect();
328
329 if data.len() == l.len() {
330 Some(ColumnWithName::new(Fragment::internal(fragment.text()), ColumnBuffer::bool(data)))
331 } else {
332 None
333 }
334}
335
336pub(crate) fn compare_columns<Op: CompareOp>(
337 left: &ColumnWithName,
338 right: &ColumnWithName,
339 fragment: Fragment,
340 error_fn: impl FnOnce(Fragment, ValueType, ValueType) -> Diagnostic,
341) -> Result<ColumnWithName> {
342 binary_op_unwrap_option(left, right, fragment.clone(), |left, right| {
343 dispatch_compare!(
344 &left.data(), &right.data();
345 fragment;
346
347 (ColumnBuffer::Bool(l), ColumnBuffer::Bool(r)) => {
348 if let Some(col) = compare_bool::<Op>(l, r, fragment.clone()) {
349 return Ok(col);
350 }
351 return_error!(error_fn(fragment, left.get_type(), right.get_type()))
352 }
353
354 (ColumnBuffer::Date(l), ColumnBuffer::Date(r)) => {
355 Ok(compare_temporal::<Op, _>(l, r, fragment))
356 },
357 (ColumnBuffer::DateTime(l), ColumnBuffer::DateTime(r)) => {
358 Ok(compare_temporal::<Op, _>(l, r, fragment))
359 },
360 (ColumnBuffer::Time(l), ColumnBuffer::Time(r)) => {
361 Ok(compare_temporal::<Op, _>(l, r, fragment))
362 },
363 (ColumnBuffer::Duration(l), ColumnBuffer::Duration(r)) => {
364 Ok(compare_temporal::<Op, _>(l, r, fragment))
365 },
366
367 (
368 ColumnBuffer::Utf8 {
369 container: l,
370 ..
371 },
372 ColumnBuffer::Utf8 {
373 container: r,
374 ..
375 },
376 ) => {
377 Ok(compare_utf8::<Op>(l, r, fragment))
378 },
379
380 (ColumnBuffer::Uuid4(l), ColumnBuffer::Uuid4(r)) => {
381 Ok(compare_uuid::<Op, _>(l, r, fragment))
382 },
383 (ColumnBuffer::Uuid7(l), ColumnBuffer::Uuid7(r)) => {
384 Ok(compare_uuid::<Op, _>(l, r, fragment))
385 },
386 (ColumnBuffer::IdentityId(l), ColumnBuffer::IdentityId(r)) => {
387 Ok(compare_identity_id::<Op>(l, r, fragment))
388 },
389 (
390 ColumnBuffer::Blob {
391 container: l,
392 ..
393 },
394 ColumnBuffer::Blob {
395 container: r,
396 ..
397 },
398 ) => {
399 Ok(compare_blob::<Op>(l, r, fragment))
400 },
401
402 _ => {
403 return_error!(error_fn(fragment, left.get_type(), right.get_type()))
404 },
405 )
406 })
407}