You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by al...@apache.org on 2021/11/02 20:22:24 UTC

[arrow-datafusion] branch master updated: Add algebraic simplifications to constant_folding (#1208)

This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-datafusion.git


The following commit(s) were added to refs/heads/master by this push:
     new bbd8e1b  Add algebraic simplifications to constant_folding (#1208)
bbd8e1b is described below

commit bbd8e1b9a80f049c8998dd70aa3323089fa315c7
Author: Matthew Turner <ma...@outlook.com>
AuthorDate: Tue Nov 2 16:20:33 2021 -0400

    Add algebraic simplifications to constant_folding (#1208)
    
    * Add Or branch to constant folding
    
    * Add test for Or
    
    * Simplify or match
    
    * Add And operator
    
    * Updated Or and And logic
    
    * Updated Or and And to handle nulls and added tests
---
 datafusion/src/optimizer/constant_folding.rs | 207 +++++++++++++++++++++++++++
 1 file changed, 207 insertions(+)

diff --git a/datafusion/src/optimizer/constant_folding.rs b/datafusion/src/optimizer/constant_folding.rs
index 8c29da4..dace622 100644
--- a/datafusion/src/optimizer/constant_folding.rs
+++ b/datafusion/src/optimizer/constant_folding.rs
@@ -210,6 +210,104 @@ impl<'a> ExprRewriter for Simplifier<'a> {
                         right,
                     },
                 },
+                Operator::Or => match (left.as_ref(), right.as_ref()) {
+                    (Expr::Literal(ScalarValue::Boolean(b)), _)
+                        if self.is_boolean_type(&right) =>
+                    {
+                        match b {
+                            Some(true) => Expr::Literal(ScalarValue::Boolean(Some(true))),
+                            Some(false) => match *right {
+                                Expr::Literal(ScalarValue::Boolean(None)) => {
+                                    Expr::Literal(ScalarValue::Boolean(None))
+                                }
+                                _ => *right,
+                            },
+                            None => match *right {
+                                Expr::Literal(ScalarValue::Boolean(Some(true))) => {
+                                    Expr::Literal(ScalarValue::Boolean(Some(true)))
+                                }
+                                Expr::Literal(ScalarValue::Boolean(Some(false))) => {
+                                    Expr::Literal(ScalarValue::Boolean(None))
+                                }
+                                _ => *right,
+                            },
+                        }
+                    }
+                    (_, Expr::Literal(ScalarValue::Boolean(b)))
+                        if self.is_boolean_type(&left) =>
+                    {
+                        match b {
+                            Some(true) => Expr::Literal(ScalarValue::Boolean(Some(true))),
+                            Some(false) => match *left {
+                                Expr::Literal(ScalarValue::Boolean(None)) => {
+                                    Expr::Literal(ScalarValue::Boolean(None))
+                                }
+                                _ => *left,
+                            },
+                            None => match *left {
+                                Expr::Literal(ScalarValue::Boolean(Some(true))) => {
+                                    Expr::Literal(ScalarValue::Boolean(Some(true)))
+                                }
+                                Expr::Literal(ScalarValue::Boolean(Some(false))) => {
+                                    Expr::Literal(ScalarValue::Boolean(None))
+                                }
+                                _ => *left,
+                            },
+                        }
+                    }
+                    _ => Expr::BinaryExpr {
+                        left,
+                        op: Operator::Or,
+                        right,
+                    },
+                },
+                Operator::And => match (left.as_ref(), right.as_ref()) {
+                    (Expr::Literal(ScalarValue::Boolean(b)), _)
+                        if self.is_boolean_type(&right) =>
+                    {
+                        // match b {
+                        //     Some(false) => {
+                        //         Expr::Literal(ScalarValue::Boolean(Some(false)))
+                        //     }
+                        //     _ => *right,
+                        // }
+                        match b {
+                            Some(true) => match *right {
+                                Expr::Literal(ScalarValue::Boolean(None)) => {
+                                    Expr::Literal(ScalarValue::Boolean(None))
+                                }
+                                _ => *right,
+                            },
+                            Some(false) => {
+                                Expr::Literal(ScalarValue::Boolean(Some(false)))
+                            }
+                            None => match *right {
+                                Expr::Literal(ScalarValue::Boolean(Some(true))) => {
+                                    Expr::Literal(ScalarValue::Boolean(None))
+                                }
+                                Expr::Literal(ScalarValue::Boolean(Some(false))) => {
+                                    Expr::Literal(ScalarValue::Boolean(Some(false)))
+                                }
+                                _ => *right,
+                            },
+                        }
+                    }
+                    (_, Expr::Literal(ScalarValue::Boolean(b)))
+                        if self.is_boolean_type(&left) =>
+                    {
+                        match b {
+                            Some(false) => {
+                                Expr::Literal(ScalarValue::Boolean(Some(false)))
+                            }
+                            _ => *left,
+                        }
+                    }
+                    _ => Expr::BinaryExpr {
+                        left,
+                        op: Operator::And,
+                        right,
+                    },
+                },
                 _ => Expr::BinaryExpr { left, op, right },
             },
             // Not(Not(expr)) --> expr
@@ -811,4 +909,113 @@ mod tests {
 
         assert_eq!(expected, actual);
     }
+    #[test]
+    fn optimize_expr_bool_or() -> Result<()> {
+        let schema = expr_test_schema();
+        let mut rewriter = Simplifier {
+            schemas: vec![&schema],
+        };
+
+        // col || true is always true
+        assert_eq!(
+            (col("c2").or(Expr::Literal(ScalarValue::Boolean(Some(true)))))
+                .rewrite(&mut rewriter)?,
+            lit(ScalarValue::Boolean(Some(true))),
+        );
+
+        // col || false is always col
+        assert_eq!(
+            (col("c2").or(Expr::Literal(ScalarValue::Boolean(Some(false)))))
+                .rewrite(&mut rewriter)?,
+            col("c2"),
+        );
+
+        // true || null is always true
+        assert_eq!(
+            (Expr::Literal(ScalarValue::Boolean(Some(true)))
+                .or(Expr::Literal(ScalarValue::Boolean(None))))
+            .rewrite(&mut rewriter)?,
+            lit(ScalarValue::Boolean(Some(true))),
+        );
+
+        // null || true is always true
+        assert_eq!(
+            (Expr::Literal(ScalarValue::Boolean(None))
+                .or(Expr::Literal(ScalarValue::Boolean(Some(true)))))
+            .rewrite(&mut rewriter)?,
+            lit(ScalarValue::Boolean(Some(true))),
+        );
+
+        // false || null is always null
+        assert_eq!(
+            (Expr::Literal(ScalarValue::Boolean(Some(false)))
+                .or(Expr::Literal(ScalarValue::Boolean(None))))
+            .rewrite(&mut rewriter)?,
+            lit(ScalarValue::Boolean(None)),
+        );
+
+        // null || false is always null
+        assert_eq!(
+            (Expr::Literal(ScalarValue::Boolean(None))
+                .or(Expr::Literal(ScalarValue::Boolean(Some(false)))))
+            .rewrite(&mut rewriter)?,
+            lit(ScalarValue::Boolean(None)),
+        );
+
+        Ok(())
+    }
+    #[test]
+    fn optimize_expr_bool_and() -> Result<()> {
+        let schema = expr_test_schema();
+        let mut rewriter = Simplifier {
+            schemas: vec![&schema],
+        };
+
+        // col & true is always col
+        assert_eq!(
+            (col("c2").and(Expr::Literal(ScalarValue::Boolean(Some(true)))))
+                .rewrite(&mut rewriter)?,
+            col("c2"),
+        );
+        // col & false is always false
+        assert_eq!(
+            (col("c2").and(Expr::Literal(ScalarValue::Boolean(Some(false)))))
+                .rewrite(&mut rewriter)?,
+            lit(ScalarValue::Boolean(Some(false))),
+        );
+
+        // true && null is always null
+        assert_eq!(
+            (Expr::Literal(ScalarValue::Boolean(Some(true)))
+                .and(Expr::Literal(ScalarValue::Boolean(None))))
+            .rewrite(&mut rewriter)?,
+            lit(ScalarValue::Boolean(None)),
+        );
+
+        // null && true is always null
+        assert_eq!(
+            (Expr::Literal(ScalarValue::Boolean(None))
+                .and(Expr::Literal(ScalarValue::Boolean(Some(true)))))
+            .rewrite(&mut rewriter)?,
+            lit(ScalarValue::Boolean(None)),
+        );
+
+        // false && null is always false
+        assert_eq!(
+            (Expr::Literal(ScalarValue::Boolean(Some(false)))
+                .and(Expr::Literal(ScalarValue::Boolean(None))))
+            .rewrite(&mut rewriter)?,
+            lit(ScalarValue::Boolean(Some(false))),
+        );
+
+        // null && false is always false
+        assert_eq!(
+            (Expr::Literal(ScalarValue::Boolean(None))
+                .and(Expr::Literal(ScalarValue::Boolean(Some(false)))))
+            .rewrite(&mut rewriter)?,
+            lit(ScalarValue::Boolean(Some(false))),
+        );
+
+        Ok(())
+    }
 }