You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2014/09/11 02:54:05 UTC
git commit: [OPTIQ-399] Factorize common AND factors out of OR
predicates
Repository: incubator-optiq
Updated Branches:
refs/heads/master 6fbefcec9 -> fd20d5c41
[OPTIQ-399] Factorize common AND factors out of OR predicates
Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/fd20d5c4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/fd20d5c4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/fd20d5c4
Branch: refs/heads/master
Commit: fd20d5c41d47377aa0e0f592e409f81f5952ac82
Parents: 6fbefce
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Sep 3 18:06:16 2014 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Sep 10 16:53:36 2014 -0700
----------------------------------------------------------------------
.../main/java/org/eigenbase/rex/RexUtil.java | 103 +++++-
.../java/org/eigenbase/test/RexProgramTest.java | 334 +++++++++++--------
2 files changed, 294 insertions(+), 143 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/fd20d5c4/core/src/main/java/org/eigenbase/rex/RexUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rex/RexUtil.java b/core/src/main/java/org/eigenbase/rex/RexUtil.java
index 424ba60..5ed708d 100644
--- a/core/src/main/java/org/eigenbase/rex/RexUtil.java
+++ b/core/src/main/java/org/eigenbase/rex/RexUtil.java
@@ -31,7 +31,9 @@ import net.hydromatic.linq4j.function.*;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
/**
* Utility methods concerning row-expressions.
@@ -52,6 +54,13 @@ public class RexUtil {
}
};
+ private static final Function<Object, String> TO_STRING =
+ new Function<Object, String>() {
+ public String apply(Object input) {
+ return input.toString();
+ }
+ };
+
private RexUtil() {
}
@@ -1003,6 +1012,32 @@ public class RexUtil {
});
}
+ /** Creates an equivalent version of a node where common factors among ORs
+ * are pulled up.
+ *
+ * <p>For example,
+ *
+ * <blockquote>(a AND b) OR (a AND c AND d)</blockquote>
+ *
+ * <p>becomes
+ *
+ * <blockquote>a AND (b OR (c AND d))</blockquote>
+ *
+ * <p>Note that this result is not in CNF
+ * (see {@link #toCnf(RexBuilder, RexNode)}) because there is an AND inside an
+ * OR.
+ *
+ * <p>This form is useful if, say, {@code a} contains columns from only the
+ * left-hand side of a join, and can be pushed to the left input.
+ *
+ * @param rexBuilder Rex builder
+ * @param node Expression to transform
+ * @return Equivalent expression with common factors pulled up
+ */
+ public static RexNode pullFactors(RexBuilder rexBuilder, RexNode node) {
+ return new CnfHelper(rexBuilder).pull(node);
+ }
+
//~ Inner Classes ----------------------------------------------------------
/**
@@ -1204,8 +1239,9 @@ public class RexUtil {
default:
return rex;
}
+ default:
+ return rex;
}
- return rex;
}
private List<RexNode> toCnfs(List<RexNode> nodes) {
@@ -1223,6 +1259,71 @@ public class RexUtil {
return list;
}
+ private RexNode pull(RexNode rex) {
+ final List<RexNode> operands;
+ switch (rex.getKind()) {
+ case AND:
+ operands = flattenAnd(((RexCall) rex).getOperands());
+ return and(pullList(operands));
+ case OR:
+ operands = flattenOr(((RexCall) rex).getOperands());
+ final Map<String, RexNode> factors = commonFactors(operands);
+ if (factors.isEmpty()) {
+ return or(operands);
+ }
+ final List<RexNode> list = Lists.newArrayList();
+ for (RexNode operand : operands) {
+ list.add(removeFactor(factors, operand));
+ }
+ return and(Iterables.concat(factors.values(),
+ ImmutableList.of(or(list))));
+ default:
+ return rex;
+ }
+ }
+
+ private List<RexNode> pullList(List<RexNode> nodes) {
+ final List<RexNode> list = Lists.newArrayList();
+ for (RexNode node : nodes) {
+ RexNode pulled = pull(node);
+ switch (pulled.getKind()) {
+ case AND:
+ list.addAll(((RexCall) pulled).getOperands());
+ break;
+ default:
+ list.add(pulled);
+ }
+ }
+ return list;
+ }
+
+ private Map<String, RexNode> commonFactors(List<RexNode> nodes) {
+ final Map<String, RexNode> map = Maps.newHashMap();
+ int i = 0;
+ for (RexNode node : nodes) {
+ if (i++ == 0) {
+ for (RexNode conjunction : RelOptUtil.conjunctions(node)) {
+ map.put(conjunction.toString(), conjunction);
+ }
+ } else {
+ map.keySet().retainAll(
+ Lists.transform(RelOptUtil.conjunctions(node), TO_STRING));
+ }
+ }
+ return map;
+ }
+
+ private RexNode removeFactor(Map<String, RexNode> factors, RexNode node) {
+ List<RexNode> list = Lists.newArrayList();
+ for (RexNode operand : RelOptUtil.conjunctions(node)) {
+ if (!factors.containsKey(operand.toString())) {
+ list.add(operand);
+ }
+ }
+ return and(list);
+ }
+
+
private RexNode and(Iterable<? extends RexNode> nodes) {
return composeConjunction(rexBuilder, nodes, false);
}
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/fd20d5c4/core/src/test/java/org/eigenbase/test/RexProgramTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/eigenbase/test/RexProgramTest.java b/core/src/test/java/org/eigenbase/test/RexProgramTest.java
index 02195f3..184f1e6 100644
--- a/core/src/test/java/org/eigenbase/test/RexProgramTest.java
+++ b/core/src/test/java/org/eigenbase/test/RexProgramTest.java
@@ -65,6 +65,58 @@ public class RexProgramTest {
rexBuilder = new RexBuilder(typeFactory);
}
+ private void checkCnf(RexNode node, String expected) {
+ assertThat(RexUtil.toCnf(rexBuilder, node).toString(), equalTo(expected));
+ }
+
+ private void checkPullFactorsUnchanged(RexNode node) {
+ checkPullFactors(node, node.toString());
+ }
+
+ private void checkPullFactors(RexNode node, String expected) {
+ assertThat(RexUtil.pullFactors(rexBuilder, node).toString(),
+ equalTo(expected));
+ }
+
+ /** Returns the number of nodes (including leaves) in a Rex tree. */
+ private static int nodeCount(RexNode node) {
+ int n = 1;
+ if (node instanceof RexCall) {
+ for (RexNode operand : ((RexCall) node).getOperands()) {
+ n += nodeCount(operand);
+ }
+ }
+ return n;
+ }
+
+ private RexNode not(RexNode node) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.NOT, node);
+ }
+
+ private RexNode and(RexNode... nodes) {
+ return and(ImmutableList.copyOf(nodes));
+ }
+
+ private RexNode and(Iterable<? extends RexNode> nodes) {
+ // Does not flatten nested ANDs. We want test input to contain nested ANDs.
+ return rexBuilder.makeCall(SqlStdOperatorTable.AND,
+ ImmutableList.copyOf(nodes));
+ }
+
+ private RexNode or(RexNode... nodes) {
+ return or(ImmutableList.copyOf(nodes));
+ }
+
+ private RexNode or(Iterable<? extends RexNode> nodes) {
+ // Does not flatten nested ORs. We want test input to contain nested ORs.
+ return rexBuilder.makeCall(SqlStdOperatorTable.OR,
+ ImmutableList.copyOf(nodes));
+ }
+
+ private RexNode eq(RexNode n1, RexNode n2) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, n1, n2);
+ }
+
/**
* Tests construction of a RexProgram.
*/
@@ -101,8 +153,8 @@ public class RexProgramTest {
final String program = builder.getProgram(true).toString();
TestUtil.assertEqualsVerbose(
"(expr#0..1=[{inputs}], expr#2=[+($t0, $t1)], expr#3=[1], "
- + "expr#4=[+($t0, $t3)], expr#5=[+($t2, $t4)], "
- + "expr#6=[+($t0, $t0)], a=[$t5], b=[$t6])",
+ + "expr#4=[+($t0, $t3)], expr#5=[+($t2, $t4)], "
+ + "expr#6=[+($t0, $t0)], a=[$t5], b=[$t6])",
program);
}
@@ -265,12 +317,6 @@ public class RexProgramTest {
/** Unit test for {@link org.eigenbase.relopt.Strong}. */
@Test public void testStrong() {
final RelDataType intType = typeFactory.createSqlType(SqlTypeName.INTEGER);
- final RelDataType rowType = typeFactory.builder()
- .add("a", intType)
- .add("b", intType)
- .add("c", intType)
- .add("d", intType)
- .build();
final BitSet c = BitSets.of();
final BitSet c0 = BitSets.of(0);
@@ -280,9 +326,6 @@ public class RexProgramTest {
// input ref
final RexInputRef aRef = rexBuilder.makeInputRef(intType, 0);
- final RexInputRef bRef = rexBuilder.makeInputRef(intType, 1);
- final RexInputRef cRef = rexBuilder.makeInputRef(intType, 2);
- final RexInputRef dRef = rexBuilder.makeInputRef(intType, 3);
assertThat(strongIf(aRef, c0), is(true));
assertThat(strongIf(aRef, c1), is(false));
@@ -354,72 +397,45 @@ public class RexProgramTest {
final RexNode unknownLiteral =
rexBuilder.makeNullLiteral(SqlTypeName.BOOLEAN);
- assertThat(RexUtil.toCnf(rexBuilder, aRef).toString(), equalTo("?0.a"));
- assertThat(RexUtil.toCnf(rexBuilder, trueLiteral).toString(),
- equalTo("true"));
- assertThat(RexUtil.toCnf(rexBuilder, falseLiteral).toString(),
- equalTo("false"));
- assertThat(RexUtil.toCnf(rexBuilder, unknownLiteral).toString(),
- equalTo("null"));
- assertThat(RexUtil.toCnf(rexBuilder, and(aRef, bRef)).toString(),
- equalTo("AND(?0.a, ?0.b)"));
- assertThat(RexUtil.toCnf(rexBuilder, and(aRef, bRef, cRef)).toString(),
- equalTo("AND(?0.a, ?0.b, ?0.c)"));
-
- assertThat(RexUtil.toCnf(rexBuilder, and(or(aRef, bRef), or(cRef, dRef)))
- .toString(),
- equalTo("AND(OR(?0.a, ?0.b), OR(?0.c, ?0.d))"));
- assertThat(RexUtil.toCnf(rexBuilder, or(and(aRef, bRef), and(cRef, dRef)))
- .toString(),
- equalTo(
- "AND(OR(?0.a, ?0.c), OR(?0.a, ?0.d), OR(?0.b, ?0.c), OR(?0.b, ?0.d))"));
+ checkCnf(aRef, "?0.a");
+ checkCnf(trueLiteral, "true");
+ checkCnf(falseLiteral, "false");
+ checkCnf(unknownLiteral, "null");
+ checkCnf(and(aRef, bRef), "AND(?0.a, ?0.b)");
+ checkCnf(and(aRef, bRef, cRef), "AND(?0.a, ?0.b, ?0.c)");
+
+ checkCnf(and(or(aRef, bRef), or(cRef, dRef)),
+ "AND(OR(?0.a, ?0.b), OR(?0.c, ?0.d))");
+ checkCnf(or(and(aRef, bRef), and(cRef, dRef)),
+ "AND(OR(?0.a, ?0.c), OR(?0.a, ?0.d), OR(?0.b, ?0.c), OR(?0.b, ?0.d))");
// Input has nested ORs, output ORs are flat
- assertThat(RexUtil.toCnf(rexBuilder, or(and(aRef, bRef), or(cRef, dRef)))
- .toString(),
- equalTo("AND(OR(?0.a, ?0.c, ?0.d), OR(?0.b, ?0.c, ?0.d))"));
+ checkCnf(or(and(aRef, bRef), or(cRef, dRef)),
+ "AND(OR(?0.a, ?0.c, ?0.d), OR(?0.b, ?0.c, ?0.d))");
- assertThat(
- RexUtil.toCnf(rexBuilder, or(aRef, not(and(bRef, not(hEqSeven)))))
- .toString(),
- equalTo("OR(?0.a, NOT(?0.b), =(?0.h, 7))"));
+ checkCnf(or(aRef, not(and(bRef, not(hEqSeven)))),
+ "OR(?0.a, NOT(?0.b), =(?0.h, 7))");
// apply de Morgan's theorem
- assertThat(
- RexUtil.toCnf(rexBuilder, not(or(aRef, not(bRef))))
- .toString(),
- equalTo("AND(NOT(?0.a), ?0.b)"));
+ checkCnf(not(or(aRef, not(bRef))), "AND(NOT(?0.a), ?0.b)");
// apply de Morgan's theorem,
// filter out 'OR ... FALSE' and 'AND ... TRUE'
- assertThat(
- RexUtil.toCnf(rexBuilder,
- not(or(and(aRef, trueLiteral), not(bRef), falseLiteral)))
- .toString(),
- equalTo("AND(NOT(?0.a), ?0.b)"));
-
- assertThat(
- RexUtil.toCnf(rexBuilder, and(aRef, or(bRef, and(cRef, dRef))))
- .toString(),
- equalTo("AND(?0.a, OR(?0.b, ?0.c), OR(?0.b, ?0.d))"));
-
- assertThat(
- RexUtil.toCnf(rexBuilder,
- and(aRef, or(bRef,
- and(cRef, or(dRef,
- and(eRef, or(fRef, gRef)))))))
- .toString(),
- equalTo(
- "AND(?0.a, OR(?0.b, ?0.c), OR(?0.b, ?0.d, ?0.e), OR(?0.b, ?0.d, ?0.f, ?0.g))"));
-
- assertThat(
- RexUtil.toCnf(rexBuilder,
- and(aRef, or(bRef,
- and(cRef, or(dRef,
- and(eRef, or(fRef,
- and(gRef, or(trueLiteral, falseLiteral)))))))))
- .toString(),
- equalTo(
- "AND(?0.a, OR(?0.b, ?0.c), OR(?0.b, ?0.d, ?0.e), OR(?0.b, ?0.d, ?0.f, ?0.g))"));
+ checkCnf(not(or(and(aRef, trueLiteral), not(bRef), falseLiteral)),
+ "AND(NOT(?0.a), ?0.b)");
+
+ checkCnf(and(aRef, or(bRef, and(cRef, dRef))),
+ "AND(?0.a, OR(?0.b, ?0.c), OR(?0.b, ?0.d))");
+
+ checkCnf(and(aRef, or(bRef,
+ and(cRef, or(dRef,
+ and(eRef, or(fRef, gRef)))))),
+ "AND(?0.a, OR(?0.b, ?0.c), OR(?0.b, ?0.d, ?0.e), OR(?0.b, ?0.d, ?0.f, ?0.g))");
+
+ checkCnf(and(aRef, or(bRef,
+ and(cRef, or(dRef,
+ and(eRef, or(fRef,
+ and(gRef, or(trueLiteral, falseLiteral)))))))),
+ "AND(?0.a, OR(?0.b, ?0.c), OR(?0.b, ?0.d, ?0.e), OR(?0.b, ?0.d, ?0.f, ?0.g))");
}
/** Unit test for
@@ -450,46 +466,45 @@ public class RexProgramTest {
final RexLiteral literal3 =
rexBuilder.makeExactLiteral(BigDecimal.valueOf(3));
- assertThat(
- RexUtil.toCnf(rexBuilder,
- or(
- and(eq(xRef, literal1),
- eq(yRef, literal1),
- eq(zRef, literal1)),
- and(eq(xRef, literal2),
- eq(yRef, literal2),
- eq(aRef, literal2)),
- and(eq(xRef, literal3),
- eq(aRef, literal3),
- eq(bRef, literal3)))).toString(),
- equalTo("AND("
- + "OR(=(?0.x, 1), =(?0.x, 2), =(?0.x, 3)), "
- + "OR(=(?0.x, 1), =(?0.x, 2), =(?0.a, 3)), "
- + "OR(=(?0.x, 1), =(?0.x, 2), =(?0.b, 3)), "
- + "OR(=(?0.x, 1), =(?0.y, 2), =(?0.x, 3)), "
- + "OR(=(?0.x, 1), =(?0.y, 2), =(?0.a, 3)), "
- + "OR(=(?0.x, 1), =(?0.y, 2), =(?0.b, 3)), "
- + "OR(=(?0.x, 1), =(?0.a, 2), =(?0.x, 3)), "
- + "OR(=(?0.x, 1), =(?0.a, 2), =(?0.a, 3)), "
- + "OR(=(?0.x, 1), =(?0.a, 2), =(?0.b, 3)), "
- + "OR(=(?0.y, 1), =(?0.x, 2), =(?0.x, 3)), "
- + "OR(=(?0.y, 1), =(?0.x, 2), =(?0.a, 3)), "
- + "OR(=(?0.y, 1), =(?0.x, 2), =(?0.b, 3)), "
- + "OR(=(?0.y, 1), =(?0.y, 2), =(?0.x, 3)), "
- + "OR(=(?0.y, 1), =(?0.y, 2), =(?0.a, 3)), "
- + "OR(=(?0.y, 1), =(?0.y, 2), =(?0.b, 3)), "
- + "OR(=(?0.y, 1), =(?0.a, 2), =(?0.x, 3)), "
- + "OR(=(?0.y, 1), =(?0.a, 2), =(?0.a, 3)), "
- + "OR(=(?0.y, 1), =(?0.a, 2), =(?0.b, 3)), "
- + "OR(=(?0.z, 1), =(?0.x, 2), =(?0.x, 3)), "
- + "OR(=(?0.z, 1), =(?0.x, 2), =(?0.a, 3)), "
- + "OR(=(?0.z, 1), =(?0.x, 2), =(?0.b, 3)), "
- + "OR(=(?0.z, 1), =(?0.y, 2), =(?0.x, 3)), "
- + "OR(=(?0.z, 1), =(?0.y, 2), =(?0.a, 3)), "
- + "OR(=(?0.z, 1), =(?0.y, 2), =(?0.b, 3)), "
- + "OR(=(?0.z, 1), =(?0.a, 2), =(?0.x, 3)), "
- + "OR(=(?0.z, 1), =(?0.a, 2), =(?0.a, 3)), "
- + "OR(=(?0.z, 1), =(?0.a, 2), =(?0.b, 3)))"));
+ checkCnf(
+ or(
+ and(eq(xRef, literal1),
+ eq(yRef, literal1),
+ eq(zRef, literal1)),
+ and(eq(xRef, literal2),
+ eq(yRef, literal2),
+ eq(aRef, literal2)),
+ and(eq(xRef, literal3),
+ eq(aRef, literal3),
+ eq(bRef, literal3))),
+ "AND("
+ + "OR(=(?0.x, 1), =(?0.x, 2), =(?0.x, 3)), "
+ + "OR(=(?0.x, 1), =(?0.x, 2), =(?0.a, 3)), "
+ + "OR(=(?0.x, 1), =(?0.x, 2), =(?0.b, 3)), "
+ + "OR(=(?0.x, 1), =(?0.y, 2), =(?0.x, 3)), "
+ + "OR(=(?0.x, 1), =(?0.y, 2), =(?0.a, 3)), "
+ + "OR(=(?0.x, 1), =(?0.y, 2), =(?0.b, 3)), "
+ + "OR(=(?0.x, 1), =(?0.a, 2), =(?0.x, 3)), "
+ + "OR(=(?0.x, 1), =(?0.a, 2), =(?0.a, 3)), "
+ + "OR(=(?0.x, 1), =(?0.a, 2), =(?0.b, 3)), "
+ + "OR(=(?0.y, 1), =(?0.x, 2), =(?0.x, 3)), "
+ + "OR(=(?0.y, 1), =(?0.x, 2), =(?0.a, 3)), "
+ + "OR(=(?0.y, 1), =(?0.x, 2), =(?0.b, 3)), "
+ + "OR(=(?0.y, 1), =(?0.y, 2), =(?0.x, 3)), "
+ + "OR(=(?0.y, 1), =(?0.y, 2), =(?0.a, 3)), "
+ + "OR(=(?0.y, 1), =(?0.y, 2), =(?0.b, 3)), "
+ + "OR(=(?0.y, 1), =(?0.a, 2), =(?0.x, 3)), "
+ + "OR(=(?0.y, 1), =(?0.a, 2), =(?0.a, 3)), "
+ + "OR(=(?0.y, 1), =(?0.a, 2), =(?0.b, 3)), "
+ + "OR(=(?0.z, 1), =(?0.x, 2), =(?0.x, 3)), "
+ + "OR(=(?0.z, 1), =(?0.x, 2), =(?0.a, 3)), "
+ + "OR(=(?0.z, 1), =(?0.x, 2), =(?0.b, 3)), "
+ + "OR(=(?0.z, 1), =(?0.y, 2), =(?0.x, 3)), "
+ + "OR(=(?0.z, 1), =(?0.y, 2), =(?0.a, 3)), "
+ + "OR(=(?0.z, 1), =(?0.y, 2), =(?0.b, 3)), "
+ + "OR(=(?0.z, 1), =(?0.a, 2), =(?0.x, 3)), "
+ + "OR(=(?0.z, 1), =(?0.a, 2), =(?0.a, 3)), "
+ + "OR(=(?0.z, 1), =(?0.a, 2), =(?0.b, 3)))");
}
/** Tests formulas of various sizes whose size is exponential when converted
@@ -531,43 +546,78 @@ public class RexProgramTest {
}
}
- /** Returns the number of nodes (including leaves) in a Rex tree. */
- private static int nodeCount(RexNode node) {
- int n = 1;
- if (node instanceof RexCall) {
- for (RexNode operand : ((RexCall) node).getOperands()) {
- n += nodeCount(operand);
- }
- }
- return n;
- }
-
- private RexNode not(RexNode node) {
- return rexBuilder.makeCall(SqlStdOperatorTable.NOT, node);
- }
+ /** Unit test for {@link org.eigenbase.rex.RexUtil#pullFactors}. */
+ @Test public void testPullFactors() {
+ final RelDataType booleanType =
+ typeFactory.createSqlType(SqlTypeName.BOOLEAN);
+ final RelDataType intType = typeFactory.createSqlType(SqlTypeName.INTEGER);
+ final RelDataType rowType = typeFactory.builder()
+ .add("a", booleanType)
+ .add("b", booleanType)
+ .add("c", booleanType)
+ .add("d", booleanType)
+ .add("e", booleanType)
+ .add("f", booleanType)
+ .add("g", booleanType)
+ .add("h", intType)
+ .build();
- private RexNode and(RexNode... nodes) {
- return and(ImmutableList.copyOf(nodes));
- }
+ final RexDynamicParam range = rexBuilder.makeDynamicParam(rowType, 0);
+ final RexNode aRef = rexBuilder.makeFieldAccess(range, 0);
+ final RexNode bRef = rexBuilder.makeFieldAccess(range, 1);
+ final RexNode cRef = rexBuilder.makeFieldAccess(range, 2);
+ final RexNode dRef = rexBuilder.makeFieldAccess(range, 3);
+ final RexNode eRef = rexBuilder.makeFieldAccess(range, 4);
+ final RexNode fRef = rexBuilder.makeFieldAccess(range, 5);
+ final RexNode gRef = rexBuilder.makeFieldAccess(range, 6);
+ final RexNode hRef = rexBuilder.makeFieldAccess(range, 7);
- private RexNode and(Iterable<? extends RexNode> nodes) {
- // Does not flatten nested ANDs. We want test input to contain nested ANDs.
- return rexBuilder.makeCall(SqlStdOperatorTable.AND,
- ImmutableList.copyOf(nodes));
- }
+ final RexLiteral sevenLiteral =
+ rexBuilder.makeExactLiteral(BigDecimal.valueOf(7));
+ final RexNode hEqSeven = eq(hRef, sevenLiteral);
- private RexNode or(RexNode... nodes) {
- return or(ImmutableList.copyOf(nodes));
- }
+ final RexLiteral trueLiteral = rexBuilder.makeLiteral(true);
+ final RexLiteral falseLiteral = rexBuilder.makeLiteral(false);
+ final RexNode unknownLiteral =
+ rexBuilder.makeNullLiteral(SqlTypeName.BOOLEAN);
- private RexNode or(Iterable<? extends RexNode> nodes) {
- // Does not flatten nested ORs. We want test input to contain nested ORs.
- return rexBuilder.makeCall(SqlStdOperatorTable.OR,
- ImmutableList.copyOf(nodes));
- }
+ // Most of the expressions in testCnf are unaffected by pullFactors.
+ checkPullFactors(
+ or(and(aRef, bRef),
+ and(cRef, aRef, dRef, aRef)),
+ "AND(?0.a, OR(?0.b, AND(?0.c, ?0.d)))");
+
+ checkPullFactors(aRef, "?0.a");
+ checkPullFactors(trueLiteral, "true");
+ checkPullFactors(falseLiteral, "false");
+ checkPullFactors(unknownLiteral, "null");
+ checkPullFactors(and(aRef, bRef), "AND(?0.a, ?0.b)");
+ checkPullFactors(and(aRef, bRef, cRef), "AND(?0.a, ?0.b, ?0.c)");
+
+ checkPullFactorsUnchanged(and(or(aRef, bRef), or(cRef, dRef)));
+ checkPullFactorsUnchanged(or(and(aRef, bRef), and(cRef, dRef)));
+ // Input has nested ORs, output ORs are flat; different from CNF
+ checkPullFactors(or(and(aRef, bRef), or(cRef, dRef)),
+ "OR(AND(?0.a, ?0.b), ?0.c, ?0.d)");
+
+ checkPullFactorsUnchanged(or(aRef, not(and(bRef, not(hEqSeven)))));
+ checkPullFactorsUnchanged(not(or(aRef, not(bRef))));
+ checkPullFactorsUnchanged(
+ not(or(and(aRef, trueLiteral), not(bRef), falseLiteral)));
+ checkPullFactorsUnchanged(and(aRef, or(bRef, and(cRef, dRef))));
+
+ checkPullFactorsUnchanged(
+ and(aRef,
+ or(bRef,
+ and(cRef, or(dRef,
+ and(eRef, or(fRef, gRef)))))));
- private RexNode eq(RexNode n1, RexNode n2) {
- return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, n1, n2);
+ checkPullFactorsUnchanged(
+ and(aRef,
+ or(bRef,
+ and(cRef, or(dRef,
+ and(eRef, or(fRef,
+ and(gRef, or(trueLiteral, falseLiteral)))))))));
}
}