jorgecarleitao commented on a change in pull request #8204:
URL: https://github.com/apache/arrow/pull/8204#discussion_r489891307
##########
File path: rust/datafusion/src/physical_plan/expressions.rs
##########
@@ -1331,6 +1331,82 @@ pub fn not(arg: Arc<dyn PhysicalExpr>) -> Arc<dyn
PhysicalExpr> {
Arc::new(NotExpr::new(arg))
}
+/// IS NULL expression
+#[derive(Debug)]
+pub struct IsNullExpr {
+ arg: Arc<dyn PhysicalExpr>,
+}
+
+impl IsNullExpr {
+ /// Create new not expression
+ pub fn new(arg: Arc<dyn PhysicalExpr>) -> Self {
+ Self { arg }
+ }
+}
+
+impl fmt::Display for IsNullExpr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{} IS NULL", self.arg)
+ }
+}
+impl PhysicalExpr for IsNullExpr {
+ fn data_type(&self, _input_schema: &Schema) -> Result<DataType> {
+ return Ok(DataType::Boolean);
+ }
+
+ fn nullable(&self, _input_schema: &Schema) -> Result<bool> {
+ Ok(false)
+ }
+
+ fn evaluate(&self, batch: &RecordBatch) -> Result<ArrayRef> {
+ let arg = self.arg.evaluate(batch)?;
+ return Ok(Arc::new(arrow::compute::is_null(&arg)?));
+ }
+}
+
+/// Create an IS NULL expression
+pub fn is_null(arg: Arc<dyn PhysicalExpr>) -> Result<Arc<dyn PhysicalExpr>> {
+ Ok(Arc::new(IsNullExpr::new(arg)))
+}
+
+/// IS NULL expression
+#[derive(Debug)]
+pub struct IsNotNullExpr {
+ arg: Arc<dyn PhysicalExpr>,
+}
+
+impl IsNotNullExpr {
+ /// Create new not expression
+ pub fn new(arg: Arc<dyn PhysicalExpr>) -> Self {
+ Self { arg }
+ }
+}
+
+impl fmt::Display for IsNotNullExpr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{} IS NULL", self.arg)
Review comment:
`IS NOT NULL`?
##########
File path: rust/arrow/src/compute/kernels/boolean.rs
##########
@@ -266,4 +334,150 @@ mod tests {
assert_eq!(false, c.value(2));
assert_eq!(true, c.value(3));
}
+
+ #[test]
+ fn test_nonnull_array_is_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![1, 2, 3, 4]));
+
+ let res = is_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
+ assert_eq!(false, res.value(0));
+ assert_eq!(false, res.value(1));
+ assert_eq!(false, res.value(2));
+ assert_eq!(false, res.value(3));
+ }
+
+ #[test]
+ fn test_nonnull_array_with_offset_is_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![
+ 1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1,
+ ]));
+ let a = a.slice(8, 4);
+
+ let res = is_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
+ assert_eq!(false, res.value(0));
+ assert_eq!(false, res.value(1));
+ assert_eq!(false, res.value(2));
+ assert_eq!(false, res.value(3));
+ }
+
+ #[test]
+ fn test_nonnull_array_is_not_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![1, 2, 3, 4]));
+
+ let res = is_not_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
+ assert_eq!(true, res.value(0));
+ assert_eq!(true, res.value(1));
+ assert_eq!(true, res.value(2));
+ assert_eq!(true, res.value(3));
+ }
+
+ #[test]
+ fn test_nonnull_array_with_offset_is_not_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![
+ 1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1,
+ ]));
+ let a = a.slice(8, 4);
+
+ let res = is_not_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
+ assert_eq!(true, res.value(0));
+ assert_eq!(true, res.value(1));
+ assert_eq!(true, res.value(2));
+ assert_eq!(true, res.value(3));
+ }
+
+ #[test]
+ fn test_nullable_array_is_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![Some(1), None,
Some(3), None]));
+
+ let res = is_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
+ assert_eq!(false, res.value(0));
+ assert_eq!(true, res.value(1));
+ assert_eq!(false, res.value(2));
+ assert_eq!(true, res.value(3));
+ }
+
+ #[test]
+ fn test_nullable_array_with_offset_is_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ Some(1),
+ None,
+ Some(2),
+ None,
+ Some(3),
+ Some(4),
+ None,
+ None,
+ ]));
+ let a = a.slice(8, 4);
+
+ let res = is_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
+ assert_eq!(false, res.value(0));
+ assert_eq!(true, res.value(1));
+ assert_eq!(false, res.value(2));
+ assert_eq!(true, res.value(3));
+ }
+
+ #[test]
+ fn test_nullable_array_is_not_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![Some(1), None,
Some(3), None]));
+
+ let res = is_not_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
+ assert_eq!(true, res.value(0));
+ assert_eq!(false, res.value(1));
+ assert_eq!(true, res.value(2));
+ assert_eq!(false, res.value(3));
+ }
+
+ #[test]
+ fn test_nullable_array_with_offset_is_not_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ Some(1),
Review comment:
`// offset 8 starts here` ? ^_^
##########
File path: rust/datafusion/tests/sql.rs
##########
@@ -797,3 +797,51 @@ fn to_timstamp() -> Result<()> {
assert_eq!(expected, actual);
Ok(())
}
+
+#[test]
+fn query_is_null() -> Result<()> {
+ let schema = Arc::new(Schema::new(vec![Field::new("c1", DataType::Float64,
true)]));
+
+ let data = RecordBatch::try_new(
+ schema.clone(),
+ vec![Arc::new(Float64Array::from(vec![
+ Some(1.0),
+ None,
+ Some(f64::NAN),
Review comment:
💯 nan is not null :)
##########
File path: rust/arrow/src/compute/kernels/boolean.rs
##########
@@ -266,4 +334,150 @@ mod tests {
assert_eq!(false, c.value(2));
assert_eq!(true, c.value(3));
}
+
+ #[test]
+ fn test_nonnull_array_is_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![1, 2, 3, 4]));
+
+ let res = is_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
+ assert_eq!(false, res.value(0));
+ assert_eq!(false, res.value(1));
+ assert_eq!(false, res.value(2));
+ assert_eq!(false, res.value(3));
+ }
+
+ #[test]
+ fn test_nonnull_array_with_offset_is_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![
+ 1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1,
+ ]));
+ let a = a.slice(8, 4);
+
+ let res = is_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
+ assert_eq!(false, res.value(0));
+ assert_eq!(false, res.value(1));
+ assert_eq!(false, res.value(2));
+ assert_eq!(false, res.value(3));
+ }
+
+ #[test]
+ fn test_nonnull_array_is_not_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![1, 2, 3, 4]));
+
+ let res = is_not_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
+ assert_eq!(true, res.value(0));
+ assert_eq!(true, res.value(1));
+ assert_eq!(true, res.value(2));
+ assert_eq!(true, res.value(3));
+ }
+
+ #[test]
+ fn test_nonnull_array_with_offset_is_not_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![
+ 1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1,
+ ]));
+ let a = a.slice(8, 4);
+
+ let res = is_not_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
+ assert_eq!(true, res.value(0));
+ assert_eq!(true, res.value(1));
+ assert_eq!(true, res.value(2));
+ assert_eq!(true, res.value(3));
+ }
+
+ #[test]
+ fn test_nullable_array_is_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![Some(1), None,
Some(3), None]));
+
+ let res = is_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
+ assert_eq!(false, res.value(0));
+ assert_eq!(true, res.value(1));
+ assert_eq!(false, res.value(2));
+ assert_eq!(true, res.value(3));
+ }
+
+ #[test]
+ fn test_nullable_array_with_offset_is_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ Some(1),
+ None,
+ Some(2),
+ None,
+ Some(3),
+ Some(4),
+ None,
+ None,
+ ]));
+ let a = a.slice(8, 4);
+
+ let res = is_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
+ assert_eq!(false, res.value(0));
+ assert_eq!(true, res.value(1));
+ assert_eq!(false, res.value(2));
+ assert_eq!(true, res.value(3));
+ }
+
+ #[test]
+ fn test_nullable_array_is_not_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![Some(1), None,
Some(3), None]));
+
+ let res = is_not_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
Review comment:
assert no null counts?
##########
File path: rust/arrow/src/compute/kernels/boolean.rs
##########
@@ -266,4 +334,150 @@ mod tests {
assert_eq!(false, c.value(2));
assert_eq!(true, c.value(3));
}
+
+ #[test]
+ fn test_nonnull_array_is_null() {
+ let a: ArrayRef = Arc::new(Int32Array::from(vec![1, 2, 3, 4]));
+
+ let res = is_null(&a).unwrap();
+
+ assert_eq!(4, res.len());
Review comment:
assert no null counts?
##########
File path: rust/datafusion/src/physical_plan/expressions.rs
##########
@@ -2499,4 +2574,56 @@ mod tests {
Ok(())
}
+
+ #[test]
+ fn is_null_op() -> Result<()> {
+ let schema = Schema::new(vec![Field::new("a", DataType::Utf8, true)]);
+ let a = StringArray::from(vec![Some("foo"), None]);
+ let batch = RecordBatch::try_new(Arc::new(schema.clone()),
vec![Arc::new(a)])?;
+
+ // expression: "a is null"
+ let expr = is_null(col("a")).unwrap();
+ let result = expr.evaluate(&batch)?;
+
+ let expected = vec![false, true];
+
+ let result = result
+ .as_any()
+ .downcast_ref::<BooleanArray>()
+ .expect("failed to downcast to BooleanArray");
+
+ assert_eq!(result.len(), expected.len());
+
+ for i in 0..expected.len() {
+ assert_eq!(result.value(i), expected[i]);
+ }
+
+ Ok(())
+ }
+
+ #[test]
+ fn is_not_null_op() -> Result<()> {
+ let schema = Schema::new(vec![Field::new("a", DataType::Utf8, true)]);
+ let a = StringArray::from(vec![Some("foo"), None]);
+ let batch = RecordBatch::try_new(Arc::new(schema.clone()),
vec![Arc::new(a)])?;
+
+ // expression: "a is null"
Review comment:
not null?
##########
File path: rust/datafusion/src/physical_plan/expressions.rs
##########
@@ -2499,4 +2574,56 @@ mod tests {
Ok(())
}
+
+ #[test]
+ fn is_null_op() -> Result<()> {
+ let schema = Schema::new(vec![Field::new("a", DataType::Utf8, true)]);
+ let a = StringArray::from(vec![Some("foo"), None]);
+ let batch = RecordBatch::try_new(Arc::new(schema.clone()),
vec![Arc::new(a)])?;
+
+ // expression: "a is null"
+ let expr = is_null(col("a")).unwrap();
+ let result = expr.evaluate(&batch)?;
+
+ let expected = vec![false, true];
+
+ let result = result
+ .as_any()
+ .downcast_ref::<BooleanArray>()
+ .expect("failed to downcast to BooleanArray");
+
+ assert_eq!(result.len(), expected.len());
+
+ for i in 0..expected.len() {
+ assert_eq!(result.value(i), expected[i]);
+ }
+
+ Ok(())
+ }
+
+ #[test]
+ fn is_not_null_op() -> Result<()> {
+ let schema = Schema::new(vec![Field::new("a", DataType::Utf8, true)]);
+ let a = StringArray::from(vec![Some("foo"), None]);
+ let batch = RecordBatch::try_new(Arc::new(schema.clone()),
vec![Arc::new(a)])?;
+
+ // expression: "a is null"
+ let expr = is_not_null(col("a")).unwrap();
+ let result = expr.evaluate(&batch)?;
+
+ let expected = vec![true, false];
+
+ let result = result
+ .as_any()
+ .downcast_ref::<BooleanArray>()
+ .expect("failed to downcast to BooleanArray");
+
+ assert_eq!(result.len(), expected.len());
+
Review comment:
If we use
```
let expected = &BooleanArray::from(vec![true, false]);
```
then we can use
```
assert_eq!(result, expected);
```
here, which may be more expressive of our intent.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]