Skip to content

Commit f44eccd

Browse files
committed
suppport bitwise and as an example
1 parent 1c63759 commit f44eccd

File tree

4 files changed

+171
-0
lines changed

4 files changed

+171
-0
lines changed

datafusion/src/logical_plan/operators.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ pub enum Operator {
6464
RegexNotMatch,
6565
/// Case insensitive regex not match
6666
RegexNotIMatch,
67+
/// Bitwise and, like `&`
68+
BitwiseAnd,
6769
}
6870

6971
impl fmt::Display for Operator {
@@ -90,6 +92,7 @@ impl fmt::Display for Operator {
9092
Operator::RegexNotIMatch => "!~*",
9193
Operator::IsDistinctFrom => "IS DISTINCT FROM",
9294
Operator::IsNotDistinctFrom => "IS NOT DISTINCT FROM",
95+
Operator::BitwiseAnd => "&",
9396
};
9497
write!(f, "{}", display)
9598
}

datafusion/src/physical_plan/coercion_rule/binary_rule.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub(crate) fn coerce_types(
3131
) -> Result<DataType> {
3232
// This result MUST be compatible with `binary_coerce`
3333
let result = match op {
34+
Operator::BitwiseAnd => bitwise_coercion(lhs_type, rhs_type),
3435
Operator::And | Operator::Or => match (lhs_type, rhs_type) {
3536
// logical binary boolean operators can only be evaluated in bools
3637
(DataType::Boolean, DataType::Boolean) => Some(DataType::Boolean),
@@ -72,6 +73,25 @@ pub(crate) fn coerce_types(
7273
}
7374
}
7475

76+
fn bitwise_coercion(left_type: &DataType, right_type: &DataType) -> Option<DataType> {
77+
use arrow::datatypes::DataType::*;
78+
79+
if !is_numeric(left_type) || !is_numeric(right_type) {
80+
return None;
81+
}
82+
if left_type == right_type && !is_dictionary(left_type) {
83+
return Some(left_type.clone());
84+
}
85+
// TODO support other data type
86+
match (left_type, right_type) {
87+
(Int64, _) | (_, Int64) => Some(Int64),
88+
(Int32, _) | (_, Int32) => Some(Int32),
89+
(Int16, _) | (_, Int16) => Some(Int16),
90+
(Int8, _) | (_, Int8) => Some(Int8),
91+
_ => None,
92+
}
93+
}
94+
7595
fn comparison_eq_coercion(lhs_type: &DataType, rhs_type: &DataType) -> Option<DataType> {
7696
// can't compare dictionaries directly due to
7797
// https://github.com/apache/arrow-rs/issues/1201

datafusion/src/physical_plan/expressions/binary.rs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,141 @@ fn modulus_decimal(left: &DecimalArray, right: &DecimalArray) -> Result<DecimalA
334334
Ok(decimal_builder.finish())
335335
}
336336

337+
fn bitwise_and(left: ArrayRef, right: ArrayRef) -> Result<ArrayRef> {
338+
let len = left.len();
339+
match &left.data_type() {
340+
DataType::Int8 => {
341+
let left = left.as_any().downcast_ref::<Int8Array>().unwrap();
342+
let right = right.as_any().downcast_ref::<Int8Array>().unwrap();
343+
let result = (0..len)
344+
.into_iter()
345+
.map(|i| {
346+
if left.is_null(i) || right.is_null(i) {
347+
None
348+
} else {
349+
Some(left.value(i) & right.value(i))
350+
}
351+
})
352+
.collect::<Int8Array>();
353+
Ok(Arc::new(result))
354+
}
355+
DataType::Int16 => {
356+
let left = left.as_any().downcast_ref::<Int16Array>().unwrap();
357+
let right = right.as_any().downcast_ref::<Int16Array>().unwrap();
358+
let result = (0..len)
359+
.into_iter()
360+
.map(|i| {
361+
if left.is_null(i) || right.is_null(i) {
362+
None
363+
} else {
364+
Some(left.value(i) & right.value(i))
365+
}
366+
})
367+
.collect::<Int16Array>();
368+
Ok(Arc::new(result))
369+
}
370+
DataType::Int32 => {
371+
let left = left.as_any().downcast_ref::<Int32Array>().unwrap();
372+
let right = right.as_any().downcast_ref::<Int32Array>().unwrap();
373+
let result = (0..len)
374+
.into_iter()
375+
.map(|i| {
376+
if left.is_null(i) || right.is_null(i) {
377+
None
378+
} else {
379+
Some(left.value(i) & right.value(i))
380+
}
381+
})
382+
.collect::<Int32Array>();
383+
Ok(Arc::new(result))
384+
}
385+
DataType::Int64 => {
386+
let left = left.as_any().downcast_ref::<Int64Array>().unwrap();
387+
let right = right.as_any().downcast_ref::<Int64Array>().unwrap();
388+
let result = (0..len)
389+
.into_iter()
390+
.map(|i| {
391+
if left.is_null(i) || right.is_null(i) {
392+
None
393+
} else {
394+
Some(left.value(i) & right.value(i))
395+
}
396+
})
397+
.collect::<Int64Array>();
398+
Ok(Arc::new(result))
399+
}
400+
other => Err(DataFusionError::Internal(format!(
401+
"Data type {:?} not supported for binary operation '{}' on dyn arrays",
402+
other,
403+
Operator::BitwiseAnd
404+
))),
405+
}
406+
}
407+
408+
fn bitwise_and_scalar(array: &ArrayRef, scalar: ScalarValue) -> Option<Result<ArrayRef>> {
409+
let len = array.len();
410+
let result = match array.data_type() {
411+
DataType::Int8 => {
412+
let array = array.as_any().downcast_ref::<Int8Array>().unwrap();
413+
if scalar.is_null() {
414+
Ok(new_null_array(array.data_type(), len))
415+
} else {
416+
let right: i8 = scalar.try_into().unwrap();
417+
let result = (0..len)
418+
.into_iter()
419+
.map(|i| Some(array.value(i) & right))
420+
.collect::<Int8Array>();
421+
Ok(Arc::new(result) as ArrayRef)
422+
}
423+
}
424+
DataType::Int16 => {
425+
let array = array.as_any().downcast_ref::<Int16Array>().unwrap();
426+
if scalar.is_null() {
427+
Ok(new_null_array(array.data_type(), len))
428+
} else {
429+
let right: i16 = scalar.try_into().unwrap();
430+
let result = (0..len)
431+
.into_iter()
432+
.map(|i| Some(array.value(i) & right))
433+
.collect::<Int16Array>();
434+
Ok(Arc::new(result) as ArrayRef)
435+
}
436+
}
437+
DataType::Int32 => {
438+
let array = array.as_any().downcast_ref::<Int32Array>().unwrap();
439+
if scalar.is_null() {
440+
Ok(new_null_array(array.data_type(), len))
441+
} else {
442+
let right: i32 = scalar.try_into().unwrap();
443+
let result = (0..len)
444+
.into_iter()
445+
.map(|i| Some(array.value(i) & right))
446+
.collect::<Int32Array>();
447+
Ok(Arc::new(result) as ArrayRef)
448+
}
449+
}
450+
DataType::Int64 => {
451+
let array = array.as_any().downcast_ref::<Int64Array>().unwrap();
452+
if scalar.is_null() {
453+
Ok(new_null_array(array.data_type(), len))
454+
} else {
455+
let right: i64 = scalar.try_into().unwrap();
456+
let result = (0..len)
457+
.into_iter()
458+
.map(|i| Some(array.value(i) & right))
459+
.collect::<Int64Array>();
460+
Ok(Arc::new(result) as ArrayRef)
461+
}
462+
}
463+
other => Err(DataFusionError::Internal(format!(
464+
"Data type {:?} not supported for binary operation '{}' on dyn arrays",
465+
other,
466+
Operator::BitwiseAnd
467+
))),
468+
};
469+
Some(result)
470+
}
471+
337472
/// Binary expression
338473
#[derive(Debug)]
339474
pub struct BinaryExpr {
@@ -564,6 +699,14 @@ macro_rules! binary_primitive_array_op {
564699
}};
565700
}
566701

702+
/// The binary_bitwise_array_op macro only evaluates for integer types
703+
/// like int64, int32
704+
// macro_rules! binary_bitwise_array_op {
705+
// ($LEFT:expr, $RIGHT: expr, $OP:ident) => {{
706+
//
707+
// }};
708+
// }
709+
567710
/// Invoke a compute kernel on an array and a scalar
568711
/// The binary_primitive_array_op_scalar macro only evaluates for primitive
569712
/// types like integers and floats.
@@ -811,6 +954,8 @@ pub fn binary_operator_data_type(
811954
| Operator::RegexNotIMatch
812955
| Operator::IsDistinctFrom
813956
| Operator::IsNotDistinctFrom => Ok(DataType::Boolean),
957+
// bitwise operations return the common coerced type
958+
Operator::BitwiseAnd => Ok(result_type),
814959
// math operations return the same value as the common coerced type
815960
Operator::Plus
816961
| Operator::Minus
@@ -939,6 +1084,7 @@ impl BinaryExpr {
9391084
true,
9401085
true
9411086
),
1087+
Operator::BitwiseAnd => bitwise_and_scalar(array, scalar.clone()),
9421088
// if scalar operation is not supported - fallback to array implementation
9431089
_ => None,
9441090
};
@@ -1027,6 +1173,7 @@ impl BinaryExpr {
10271173
Operator::RegexNotIMatch => {
10281174
binary_string_array_flag_op!(left, right, regexp_is_match, true, true)
10291175
}
1176+
Operator::BitwiseAnd => bitwise_and(left, right),
10301177
}
10311178
}
10321179
}

datafusion/src/sql/planner.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
12501250
BinaryOperator::PGRegexIMatch => Ok(Operator::RegexIMatch),
12511251
BinaryOperator::PGRegexNotMatch => Ok(Operator::RegexNotMatch),
12521252
BinaryOperator::PGRegexNotIMatch => Ok(Operator::RegexNotIMatch),
1253+
BinaryOperator::BitwiseAnd => Ok(Operator::BitwiseAnd),
12531254
_ => Err(DataFusionError::NotImplemented(format!(
12541255
"Unsupported SQL binary operator {:?}",
12551256
op

0 commit comments

Comments
 (0)