From f3d2f477e22af8951540b273ba045a23bfe3b921 Mon Sep 17 00:00:00 2001
From: Donnie Pinkston <donnie@cms.caltech.edu>
Date: Mon, 11 Feb 2019 18:14:12 -0800
Subject: [PATCH] Simplify/flatten composite Boolean expressions

The new ANTLRv4 parser generates left-deep nested Boolean AND/OR
expressions, which need to be flattened where appropriate.  The
BooleanOperator.simplify() method takes care of this operation.

Introducing this flattening/simplification everywhere all at once seemed
to be inadvisable, so currently it is only applied in the query AST when
schemas are computed.  Additionally, only WHERE predicates, HAVING
predicates, and ON clauses are simplified/flattened.  (NATURAL JOIN and
USING join predicates are generated programmatically, not by the parser,
and are already flattened.)
---
 .../edu/caltech/nanodb/expressions/BooleanOperator.java   | 7 +++++--
 src/main/java/edu/caltech/nanodb/queryast/FromClause.java | 1 +
 .../java/edu/caltech/nanodb/queryast/SelectClause.java    | 8 ++++++++
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/main/java/edu/caltech/nanodb/expressions/BooleanOperator.java b/src/main/java/edu/caltech/nanodb/expressions/BooleanOperator.java
index 68edee9..7284da1 100755
--- a/src/main/java/edu/caltech/nanodb/expressions/BooleanOperator.java
+++ b/src/main/java/edu/caltech/nanodb/expressions/BooleanOperator.java
@@ -72,7 +72,7 @@ public class BooleanOperator extends Expression {
             throw new NullPointerException("type cannot be null");
 
         this.type = type;
-        this.terms = new ArrayList<Expression>();
+        this.terms = new ArrayList<>();
 
         if (terms != null) {
             for (Expression term : terms)
@@ -492,9 +492,12 @@ public class BooleanOperator extends Expression {
                 // that are also BooleanOperators of the same type, since
                 // the new nodes will now be at index i.
             }
+            else {
+                // Some other kind of term - skip it.
+                i++;
+            }
         }
 
-
         return this;
     }
 
diff --git a/src/main/java/edu/caltech/nanodb/queryast/FromClause.java b/src/main/java/edu/caltech/nanodb/queryast/FromClause.java
index ac043a6..2acaa36 100755
--- a/src/main/java/edu/caltech/nanodb/queryast/FromClause.java
+++ b/src/main/java/edu/caltech/nanodb/queryast/FromClause.java
@@ -665,6 +665,7 @@ public class FromClause {
         }
 
         joinOnExpr = expr;
+        joinOnExpr = joinOnExpr.simplify();
     }
 
 
diff --git a/src/main/java/edu/caltech/nanodb/queryast/SelectClause.java b/src/main/java/edu/caltech/nanodb/queryast/SelectClause.java
index 18de708..8afa5c5 100755
--- a/src/main/java/edu/caltech/nanodb/queryast/SelectClause.java
+++ b/src/main/java/edu/caltech/nanodb/queryast/SelectClause.java
@@ -452,6 +452,10 @@ public class SelectClause {
             resolveExpressionRefs("WHERE clause", whereExpr, fromSchema,
                 /* checkParentQueries */ true);
 
+            // Simplify the expression
+            whereExpr = whereExpr.simplify();
+
+            // Compute the schemas of subqueries embedded in the WHERE clause.
             whereExpr.traverse(subquerySchemaComputer);
         }
 
@@ -470,6 +474,10 @@ public class SelectClause {
             resolveExpressionRefs("HAVING clause", havingExpr, fromSchema,
                 /* checkParentQueries */ true);
 
+            // Simplify the expression
+            havingExpr = havingExpr.simplify();
+
+            // Compute the schemas of subqueries embedded in the HAVING clause
             havingExpr.traverse(subquerySchemaComputer);
         }
 
-- 
GitLab