You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jc...@apache.org on 2017/04/26 19:18:38 UTC
[04/11] calcite git commit: [CALCITE-1682] New metadata providers for
expression column origin and all predicates in plan
http://git-wip-us.apache.org/repos/asf/calcite/blob/41b05d78/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
index 234b666..dbc230a 100644
--- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
@@ -36,11 +36,16 @@ import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.core.AggregateCall;
import org.apache.calcite.rel.core.Correlate;
import org.apache.calcite.rel.core.CorrelationId;
+import org.apache.calcite.rel.core.Filter;
import org.apache.calcite.rel.core.Join;
import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.Minus;
import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.core.SemiJoin;
import org.apache.calcite.rel.core.Sort;
+import org.apache.calcite.rel.core.TableScan;
+import org.apache.calcite.rel.core.Union;
+import org.apache.calcite.rel.core.Values;
import org.apache.calcite.rel.logical.LogicalAggregate;
import org.apache.calcite.rel.logical.LogicalExchange;
import org.apache.calcite.rel.logical.LogicalFilter;
@@ -65,9 +70,13 @@ import org.apache.calcite.rel.metadata.RelMetadataProvider;
import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexInputRef;
import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexTableInputRef;
import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.tools.Frameworks;
@@ -80,6 +89,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
import org.hamcrest.CoreMatchers;
import org.hamcrest.CustomTypeSafeMatcher;
@@ -91,17 +101,27 @@ import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
+import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.isA;
+import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.CoreMatchers.startsWith;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -133,6 +153,8 @@ public class RelMetadataTest extends SqlToRelTestBase {
private static final double DEPT_SIZE = 4d;
+ private static final String EMP_QNAME = "[CATALOG, SALES, EMP]";
+
//~ Methods ----------------------------------------------------------------
private static Matcher<? super Number> nearTo(Number v, Number epsilon) {
@@ -1481,6 +1503,631 @@ public class RelMetadataTest extends SqlToRelTestBase {
assertThat(RelMdUtil.linear(12, 0, 10, 100, 200), is(200d));
}
+ @Test public void testExpressionLineageStar() {
+ // All columns in output
+ final RelNode tableRel = convertSql("select * from emp");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref = RexInputRef.of(4, tableRel.getRowType().getFieldList());
+ final Set<RexNode> r = mq.getExpressionLineage(tableRel, ref);
+ final String inputRef = RexInputRef.of(4, tableRel.getRowType().getFieldList()).toString();
+ assertThat(r.size(), is(1));
+ final String resultString = r.iterator().next().toString();
+ assertThat(resultString, startsWith(EMP_QNAME));
+ assertThat(resultString, endsWith(inputRef));
+ }
+
+ @Test public void testExpressionLineageTwoColumns() {
+ // mgr is column 3 in catalog.sales.emp
+ // deptno is column 7 in catalog.sales.emp
+ final RelNode rel = convertSql("select mgr, deptno from emp");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref1 = RexInputRef.of(0, rel.getRowType().getFieldList());
+ final Set<RexNode> r1 = mq.getExpressionLineage(rel, ref1);
+ assertThat(r1.size(), is(1));
+ final RexTableInputRef result1 = (RexTableInputRef) r1.iterator().next();
+ assertThat(result1.getQualifiedName(), is(EMP_QNAME));
+ assertThat(result1.getIndex(), is(3));
+
+ final RexNode ref2 = RexInputRef.of(1, rel.getRowType().getFieldList());
+ final Set<RexNode> r2 = mq.getExpressionLineage(rel, ref2);
+ assertThat(r2.size(), is(1));
+ final RexTableInputRef result2 = (RexTableInputRef) r2.iterator().next();
+ assertThat(result2.getQualifiedName(), is(EMP_QNAME));
+ assertThat(result2.getIndex(), is(7));
+
+ assertThat(result1.getIdentifier(), is(result2.getIdentifier()));
+ }
+
+ @Test public void testExpressionLineageTwoColumnsSwapped() {
+ // deptno is column 7 in catalog.sales.emp
+ // mgr is column 3 in catalog.sales.emp
+ final RelNode rel = convertSql("select deptno, mgr from emp");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref1 = RexInputRef.of(0, rel.getRowType().getFieldList());
+ final Set<RexNode> r1 = mq.getExpressionLineage(rel, ref1);
+ assertThat(r1.size(), is(1));
+ final RexTableInputRef result1 = (RexTableInputRef) r1.iterator().next();
+ assertThat(result1.getQualifiedName(), is(EMP_QNAME));
+ assertThat(result1.getIndex(), is(7));
+
+ final RexNode ref2 = RexInputRef.of(1, rel.getRowType().getFieldList());
+ final Set<RexNode> r2 = mq.getExpressionLineage(rel, ref2);
+ assertThat(r2.size(), is(1));
+ final RexTableInputRef result2 = (RexTableInputRef) r2.iterator().next();
+ assertThat(result2.getQualifiedName(), is(EMP_QNAME));
+ assertThat(result2.getIndex(), is(3));
+
+ assertThat(result1.getIdentifier(), is(result2.getIdentifier()));
+ }
+
+ @Test public void testExpressionLineageCombineTwoColumns() {
+ // empno is column 0 in catalog.sales.emp
+ // deptno is column 7 in catalog.sales.emp
+ final RelNode rel = convertSql("select empno + deptno from emp");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref = RexInputRef.of(0, rel.getRowType().getFieldList());
+ final Set<RexNode> r = mq.getExpressionLineage(rel, ref);
+
+ assertThat(r.size(), is(1));
+ final RexNode result = r.iterator().next();
+ assertThat(result.getKind(), is(SqlKind.PLUS));
+ final RexCall call = (RexCall) result;
+ assertThat(call.getOperands().size(), is(2));
+ final RexTableInputRef inputRef1 = (RexTableInputRef) call.getOperands().get(0);
+ assertThat(inputRef1.getQualifiedName(), is(EMP_QNAME));
+ assertThat(inputRef1.getIndex(), is(0));
+ final RexTableInputRef inputRef2 = (RexTableInputRef) call.getOperands().get(1);
+ assertThat(inputRef2.getQualifiedName(), is(EMP_QNAME));
+ assertThat(inputRef2.getIndex(), is(7));
+ assertThat(inputRef1.getIdentifier(), is(inputRef2.getIdentifier()));
+ }
+
+ @Test public void testExpressionLineageInnerJoinLeft() {
+ // ename is column 1 in catalog.sales.emp
+ final RelNode rel = convertSql("select ename from emp,dept");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref = RexInputRef.of(0, rel.getRowType().getFieldList());
+ final Set<RexNode> r = mq.getExpressionLineage(rel, ref);
+ assertThat(r.size(), is(1));
+ final RexTableInputRef result = (RexTableInputRef) r.iterator().next();
+ assertThat(result.getQualifiedName(), is(EMP_QNAME));
+ assertThat(result.getIndex(), is(1));
+ }
+
+ @Test public void testExpressionLineageInnerJoinRight() {
+ // ename is column 0 in catalog.sales.bonus
+ final RelNode rel = convertSql("select bonus.ename from emp join bonus using (ename)");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref = RexInputRef.of(0, rel.getRowType().getFieldList());
+ final Set<RexNode> r = mq.getExpressionLineage(rel, ref);
+ assertThat(r.size(), is(1));
+ final RexTableInputRef result = (RexTableInputRef) r.iterator().next();
+ assertThat(result.getQualifiedName(), is("[CATALOG, SALES, BONUS]"));
+ assertThat(result.getIndex(), is(0));
+ }
+
+ @Test public void testExpressionLineageSelfJoin() {
+ // deptno is column 7 in catalog.sales.emp
+ // sal is column 5 in catalog.sales.emp
+ final RelNode rel = convertSql("select a.deptno, b.sal from (select * from emp limit 7) as a\n"
+ + "inner join (select * from emp limit 2) as b\n"
+ + "on a.deptno = b.deptno");
+ final RelNode tableRel = convertSql("select * from emp");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref1 = RexInputRef.of(0, rel.getRowType().getFieldList());
+ final Set<RexNode> r1 = mq.getExpressionLineage(rel, ref1);
+ final String inputRef1 = RexInputRef.of(7, tableRel.getRowType().getFieldList()).toString();
+ assertThat(r1.size(), is(1));
+ final String resultString1 = r1.iterator().next().toString();
+ assertThat(resultString1, startsWith(EMP_QNAME));
+ assertThat(resultString1, endsWith(inputRef1));
+
+ final RexNode ref2 = RexInputRef.of(1, rel.getRowType().getFieldList());
+ final Set<RexNode> r2 = mq.getExpressionLineage(rel, ref2);
+ final String inputRef2 = RexInputRef.of(5, tableRel.getRowType().getFieldList()).toString();
+ assertThat(r2.size(), is(1));
+ final String resultString2 = r2.iterator().next().toString();
+ assertThat(resultString2, startsWith(EMP_QNAME));
+ assertThat(resultString2, endsWith(inputRef2));
+
+ assertThat(((RexTableInputRef) r1.iterator().next()).getIdentifier(),
+ not(((RexTableInputRef) r2.iterator().next()).getIdentifier()));
+ }
+
+ @Test public void testExpressionLineageOuterJoin() {
+ // lineage cannot be determined
+ final RelNode rel = convertSql("select name as dname from emp left outer join dept"
+ + " on emp.deptno = dept.deptno");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref = RexInputRef.of(0, rel.getRowType().getFieldList());
+ final Set<RexNode> r = mq.getExpressionLineage(rel, ref);
+ assertNull(r);
+ }
+
+ @Test public void testExpressionLineageFilter() {
+ // ename is column 1 in catalog.sales.emp
+ final RelNode rel = convertSql("select ename from emp where deptno = 10");
+ final RelNode tableRel = convertSql("select * from emp");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref = RexInputRef.of(0, rel.getRowType().getFieldList());
+ final Set<RexNode> r = mq.getExpressionLineage(rel, ref);
+ final String inputRef = RexInputRef.of(1, tableRel.getRowType().getFieldList()).toString();
+ assertThat(r.size(), is(1));
+ final String resultString = r.iterator().next().toString();
+ assertThat(resultString, startsWith(EMP_QNAME));
+ assertThat(resultString, endsWith(inputRef));
+ }
+
+ @Test public void testExpressionLineageAggregateGroupColumn() {
+ // deptno is column 7 in catalog.sales.emp
+ final RelNode rel = convertSql("select deptno, count(*) from emp where deptno > 10 "
+ + "group by deptno having count(*) = 0");
+ final RelNode tableRel = convertSql("select * from emp");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref = RexInputRef.of(0, rel.getRowType().getFieldList());
+ final Set<RexNode> r = mq.getExpressionLineage(rel, ref);
+ final String inputRef = RexInputRef.of(7, tableRel.getRowType().getFieldList()).toString();
+ assertThat(r.size(), is(1));
+ final String resultString = r.iterator().next().toString();
+ assertThat(resultString, startsWith(EMP_QNAME));
+ assertThat(resultString, endsWith(inputRef));
+ }
+
+ @Test public void testExpressionLineageAggregateAggColumn() {
+ // lineage cannot be determined
+ final RelNode rel = convertSql("select deptno, count(*) from emp where deptno > 10 "
+ + "group by deptno having count(*) = 0");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref = RexInputRef.of(1, rel.getRowType().getFieldList());
+ final Set<RexNode> r = mq.getExpressionLineage(rel, ref);
+ assertNull(r);
+ }
+
+ @Test public void testExpressionLineageUnion() {
+ // sal is column 5 in catalog.sales.emp
+ final RelNode rel = convertSql("select sal from (\n"
+ + " select * from emp union all select * from emp) "
+ + "where deptno = 10");
+ final RelNode tableRel = convertSql("select * from emp");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref = RexInputRef.of(0, rel.getRowType().getFieldList());
+ final Set<RexNode> r = mq.getExpressionLineage(rel, ref);
+ final String inputRef = RexInputRef.of(5, tableRel.getRowType().getFieldList()).toString();
+ assertThat(r.size(), is(2));
+ for (RexNode result : r) {
+ final String resultString = result.toString();
+ assertThat(resultString, startsWith(EMP_QNAME));
+ assertThat(resultString, endsWith(inputRef));
+ }
+
+ Iterator<RexNode> it = r.iterator();
+ assertThat(((RexTableInputRef) it.next()).getIdentifier(),
+ not(((RexTableInputRef) it.next()).getIdentifier()));
+ }
+
+ @Test public void testExpressionLineageMultiUnion() {
+ // empno is column 0 in catalog.sales.emp
+ // sal is column 5 in catalog.sales.emp
+ final RelNode rel = convertSql("select a.empno + b.sal from \n"
+ + " (select empno, ename from emp,dept) a join "
+ + " (select * from emp union all select * from emp) b \n"
+ + " on a.empno = b.empno \n"
+ + " where b.deptno = 10");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref = RexInputRef.of(0, rel.getRowType().getFieldList());
+ final Set<RexNode> r = mq.getExpressionLineage(rel, ref);
+
+ // With the union, we should get two origins
+ // The first one should be the same one: join
+ // The second should come from each union input
+ final Set<String> set = new HashSet<>();
+ assertThat(r.size(), is(2));
+ for (RexNode result : r) {
+ assertThat(result.getKind(), is(SqlKind.PLUS));
+ final RexCall call = (RexCall) result;
+ assertThat(call.getOperands().size(), is(2));
+ final RexTableInputRef inputRef1 = (RexTableInputRef) call.getOperands().get(0);
+ assertThat(inputRef1.getQualifiedName(), is(EMP_QNAME));
+ // Add join alpha to set
+ set.add(inputRef1.getQualifiedName());
+ assertThat(inputRef1.getIndex(), is(0));
+ final RexTableInputRef inputRef2 = (RexTableInputRef) call.getOperands().get(1);
+ assertThat(inputRef2.getQualifiedName(), is(EMP_QNAME));
+ assertThat(inputRef2.getIndex(), is(5));
+ assertThat(inputRef1.getIdentifier(), not(inputRef2.getIdentifier()));
+ }
+ assertThat(set.size(), is(1));
+ }
+
+ @Test public void testExpressionLineageValues() {
+ // lineage cannot be determined
+ final RelNode rel = convertSql("select * from (values (1), (2)) as t(c)");
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final RexNode ref = RexInputRef.of(0, rel.getRowType().getFieldList());
+ final Set<RexNode> r = mq.getExpressionLineage(rel, ref);
+ assertNull(r);
+ }
+
+ @Test public void testAllPredicates() {
+ final Project rel = (Project) convertSql("select * from emp, dept");
+ final Join join = (Join) rel.getInput();
+ final RelOptTable empTable = join.getInput(0).getTable();
+ final RelOptTable deptTable = join.getInput(1).getTable();
+ Frameworks.withPlanner(
+ new Frameworks.PlannerAction<Void>() {
+ public Void apply(RelOptCluster cluster,
+ RelOptSchema relOptSchema,
+ SchemaPlus rootSchema) {
+ checkAllPredicates(cluster, empTable, deptTable);
+ return null;
+ }
+ });
+ }
+
+ private void checkAllPredicates(RelOptCluster cluster, RelOptTable empTable,
+ RelOptTable deptTable) {
+ final RelBuilder relBuilder = RelBuilder.proto().create(cluster, null);
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+
+ final LogicalTableScan empScan = LogicalTableScan.create(cluster, empTable);
+ relBuilder.push(empScan);
+
+ RelOptPredicateList predicates =
+ mq.getAllPredicates(empScan);
+ assertThat(predicates.pulledUpPredicates.isEmpty(), is(true));
+
+ relBuilder.filter(
+ relBuilder.equals(relBuilder.field("EMPNO"),
+ relBuilder.literal(BigDecimal.ONE)));
+
+ final RelNode filter = relBuilder.peek();
+ predicates = mq.getAllPredicates(filter);
+ assertThat(predicates.pulledUpPredicates.size(), is(1));
+ RexCall call = (RexCall) predicates.pulledUpPredicates.get(0);
+ assertThat(call.getOperands().size(), is(2));
+ RexTableInputRef inputRef1 = (RexTableInputRef) call.getOperands().get(0);
+ assertThat(inputRef1.getQualifiedName(), is(EMP_QNAME));
+ assertThat(inputRef1.getIndex(), is(0));
+
+ final LogicalTableScan deptScan =
+ LogicalTableScan.create(cluster, deptTable);
+ relBuilder.push(deptScan);
+
+ relBuilder.join(JoinRelType.INNER,
+ relBuilder.equals(relBuilder.field(2, 0, "DEPTNO"),
+ relBuilder.field(2, 1, "DEPTNO")));
+
+ relBuilder.project(relBuilder.field("DEPTNO"));
+ final RelNode project = relBuilder.peek();
+ predicates = mq.getAllPredicates(project);
+ assertThat(predicates.pulledUpPredicates.size(), is(2));
+ // From Filter
+ call = (RexCall) predicates.pulledUpPredicates.get(0);
+ assertThat(call.getOperands().size(), is(2));
+ inputRef1 = (RexTableInputRef) call.getOperands().get(0);
+ assertThat(inputRef1.getQualifiedName(), is(EMP_QNAME));
+ assertThat(inputRef1.getIndex(), is(0));
+ // From Join
+ call = (RexCall) predicates.pulledUpPredicates.get(1);
+ assertThat(call.getOperands().size(), is(2));
+ inputRef1 = (RexTableInputRef) call.getOperands().get(0);
+ assertThat(inputRef1.getQualifiedName(), is(EMP_QNAME));
+ assertThat(inputRef1.getIndex(), is(7));
+ RexTableInputRef inputRef2 = (RexTableInputRef) call.getOperands().get(1);
+ assertThat(inputRef2.getQualifiedName(), is("[CATALOG, SALES, DEPT]"));
+ assertThat(inputRef2.getIndex(), is(0));
+ }
+
+ @Test public void testAllPredicatesAggregate1() {
+ final String sql = "select a, max(b) from (\n"
+ + " select empno as a, sal as b from emp where empno = 5)subq\n"
+ + "group by a";
+ final RelNode rel = convertSql(sql);
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+ RelOptPredicateList inputSet = mq.getAllPredicates(rel);
+ ImmutableList<RexNode> pulledUpPredicates = inputSet.pulledUpPredicates;
+ assertThat(pulledUpPredicates.size(), is(1));
+ RexCall call = (RexCall) pulledUpPredicates.get(0);
+ assertThat(call.getOperands().size(), is(2));
+ final RexTableInputRef inputRef1 = (RexTableInputRef) call.getOperands().get(0);
+ assertThat(inputRef1.getQualifiedName(), is(EMP_QNAME));
+ assertThat(inputRef1.getIndex(), is(0));
+ final RexLiteral constant = (RexLiteral) call.getOperands().get(1);
+ assertThat(constant.toString(), is("5"));
+ }
+
+ @Test public void testAllPredicatesAggregate2() {
+ final String sql = "select * from (select a, max(b) from (\n"
+ + " select empno as a, sal as b from emp)subq\n"
+ + "group by a) \n"
+ + "where a = 5";
+ final RelNode rel = convertSql(sql);
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+ RelOptPredicateList inputSet = mq.getAllPredicates(rel);
+ ImmutableList<RexNode> pulledUpPredicates = inputSet.pulledUpPredicates;
+ assertThat(pulledUpPredicates.size(), is(1));
+ RexCall call = (RexCall) pulledUpPredicates.get(0);
+ assertThat(call.getOperands().size(), is(2));
+ final RexTableInputRef inputRef1 = (RexTableInputRef) call.getOperands().get(0);
+ assertThat(inputRef1.getQualifiedName(), is(EMP_QNAME));
+ assertThat(inputRef1.getIndex(), is(0));
+ final RexLiteral constant = (RexLiteral) call.getOperands().get(1);
+ assertThat(constant.toString(), is("5"));
+ }
+
+ @Test public void testAllPredicatesAggregate3() {
+ final String sql = "select * from (select a, max(b) as b from (\n"
+ + " select empno as a, sal as b from emp)subq\n"
+ + "group by a) \n"
+ + "where b = 5";
+ final RelNode rel = convertSql(sql);
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+ RelOptPredicateList inputSet = mq.getAllPredicates(rel);
+ // Filter on aggregate, we cannot infer lineage
+ assertNull(inputSet);
+ }
+
+ private void checkNodeTypeCount(String sql, Map<Class<? extends RelNode>, Integer> expected) {
+ final RelNode rel = convertSql(sql);
+ final RelMetadataQuery mq = RelMetadataQuery.instance();
+ final Multimap<Class<? extends RelNode>, RelNode> result = mq.getNodeTypes(rel);
+ assertThat(result, notNullValue());
+ final Map<Class<? extends RelNode>, Integer> resultCount = new HashMap<>();
+ for (Entry<Class<? extends RelNode>, Collection<RelNode>> e : result.asMap().entrySet()) {
+ resultCount.put(e.getKey(), e.getValue().size());
+ }
+ assertEquals(expected, resultCount);
+ }
+
+ @Test public void testNodeTypeCountEmp() {
+ final String sql = "select * from emp";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 1);
+ expected.put(Project.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountDept() {
+ final String sql = "select * from dept";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 1);
+ expected.put(Project.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountValues() {
+ final String sql = "select * from (values (1), (2)) as t(c)";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(Values.class, 1);
+ expected.put(Project.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountCartesian() {
+ final String sql = "select * from emp,dept";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 2);
+ expected.put(Join.class, 1);
+ expected.put(Project.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountJoin() {
+ final String sql = "select * from emp\n"
+ + "inner join dept on emp.deptno = dept.deptno";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 2);
+ expected.put(Join.class, 1);
+ expected.put(Project.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountJoinFinite() {
+ final String sql = "select * from (select * from emp limit 14) as emp\n"
+ + "inner join (select * from dept limit 4) as dept\n"
+ + "on emp.deptno = dept.deptno";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 2);
+ expected.put(Join.class, 1);
+ expected.put(Project.class, 3);
+ expected.put(Sort.class, 2);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountJoinEmptyFinite() {
+ final String sql = "select * from (select * from emp limit 0) as emp\n"
+ + "inner join (select * from dept limit 4) as dept\n"
+ + "on emp.deptno = dept.deptno";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 2);
+ expected.put(Join.class, 1);
+ expected.put(Project.class, 3);
+ expected.put(Sort.class, 2);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountLeftJoinEmptyFinite() {
+ final String sql = "select * from (select * from emp limit 0) as emp\n"
+ + "left join (select * from dept limit 4) as dept\n"
+ + "on emp.deptno = dept.deptno";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 2);
+ expected.put(Join.class, 1);
+ expected.put(Project.class, 3);
+ expected.put(Sort.class, 2);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountRightJoinEmptyFinite() {
+ final String sql = "select * from (select * from emp limit 0) as emp\n"
+ + "right join (select * from dept limit 4) as dept\n"
+ + "on emp.deptno = dept.deptno";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 2);
+ expected.put(Join.class, 1);
+ expected.put(Project.class, 3);
+ expected.put(Sort.class, 2);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountJoinFiniteEmpty() {
+ final String sql = "select * from (select * from emp limit 7) as emp\n"
+ + "inner join (select * from dept limit 0) as dept\n"
+ + "on emp.deptno = dept.deptno";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 2);
+ expected.put(Join.class, 1);
+ expected.put(Project.class, 3);
+ expected.put(Sort.class, 2);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountJoinEmptyEmpty() {
+ final String sql = "select * from (select * from emp limit 0) as emp\n"
+ + "inner join (select * from dept limit 0) as dept\n"
+ + "on emp.deptno = dept.deptno";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 2);
+ expected.put(Join.class, 1);
+ expected.put(Project.class, 3);
+ expected.put(Sort.class, 2);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountUnion() {
+ final String sql = "select ename from emp\n"
+ + "union all\n"
+ + "select name from dept";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 2);
+ expected.put(Project.class, 2);
+ expected.put(Union.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountUnionOnFinite() {
+ final String sql = "select ename from (select * from emp limit 100)\n"
+ + "union all\n"
+ + "select name from (select * from dept limit 40)";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 2);
+ expected.put(Union.class, 1);
+ expected.put(Project.class, 4);
+ expected.put(Sort.class, 2);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountMinusOnFinite() {
+ final String sql = "select ename from (select * from emp limit 100)\n"
+ + "except\n"
+ + "select name from (select * from dept limit 40)";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 2);
+ expected.put(Minus.class, 1);
+ expected.put(Project.class, 4);
+ expected.put(Sort.class, 2);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountFilter() {
+ final String sql = "select * from emp where ename='Mathilda'";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 1);
+ expected.put(Project.class, 1);
+ expected.put(Filter.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountSort() {
+ final String sql = "select * from emp order by ename";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 1);
+ expected.put(Project.class, 1);
+ expected.put(Sort.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountSortLimit() {
+ final String sql = "select * from emp order by ename limit 10";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 1);
+ expected.put(Project.class, 1);
+ expected.put(Sort.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountSortLimitOffset() {
+ final String sql = "select * from emp order by ename limit 10 offset 5";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 1);
+ expected.put(Project.class, 1);
+ expected.put(Sort.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountSortLimitOffsetOnFinite() {
+ final String sql = "select * from (select * from emp limit 12)\n"
+ + "order by ename limit 20 offset 5";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 1);
+ expected.put(Project.class, 2);
+ expected.put(Sort.class, 2);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountAggregate() {
+ final String sql = "select deptno from emp group by deptno";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 1);
+ expected.put(Project.class, 1);
+ expected.put(Aggregate.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountAggregateGroupingSets() {
+ final String sql = "select deptno from emp\n"
+ + "group by grouping sets ((deptno), (ename, deptno))";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 1);
+ expected.put(Project.class, 3);
+ expected.put(Aggregate.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountAggregateEmptyKeyOnEmptyTable() {
+ final String sql = "select count(*) from (select * from emp limit 0)";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 1);
+ expected.put(Project.class, 2);
+ expected.put(Aggregate.class, 1);
+ expected.put(Sort.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
+ @Test public void testNodeTypeCountFilterAggregateEmptyKey() {
+ final String sql = "select count(*) from emp where 1 = 0";
+ final Map<Class<? extends RelNode>, Integer> expected = new HashMap<>();
+ expected.put(TableScan.class, 1);
+ expected.put(Project.class, 1);
+ expected.put(Filter.class, 1);
+ expected.put(Aggregate.class, 1);
+ checkNodeTypeCount(sql, expected);
+ }
+
/**
* Matcher that succeeds for any collection that, when converted to strings
* and sorted on those strings, matches the given reference string.
http://git-wip-us.apache.org/repos/asf/calcite/blob/41b05d78/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 2314612..dd3861b 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -6593,7 +6593,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
<Resource name="planAfter">
<![CDATA[
LogicalProject(EMPNO=[10], ENAME=[$1], JOB=[$2], MGR=[null], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[7], SLACKER=[$8])
- LogicalFilter(condition=[AND(=($7, 7), =($0, 10), IS NULL($3))])
+ LogicalFilter(condition=[AND(=($7, 7), IS NULL($3), =($0, 10))])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
]]>
</Resource>