You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by vl...@apache.org on 2018/08/16 07:59:22 UTC
calcite git commit: [CALCITE-2462] RexProgramTest: move "rex
building" methods to base class
Repository: calcite
Updated Branches:
refs/heads/master 62a0de58d -> 45782ed3e
[CALCITE-2462] RexProgramTest: move "rex building" methods to base class
This simplifies creating Rex-based input data for tests
fixes #788
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/45782ed3
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/45782ed3
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/45782ed3
Branch: refs/heads/master
Commit: 45782ed3e071695a6f8dd6947b323906cdd5c300
Parents: 62a0de5
Author: Vladimir Sitnikov <si...@gmail.com>
Authored: Thu Aug 16 10:58:47 2018 +0300
Committer: Vladimir Sitnikov <si...@gmail.com>
Committed: Thu Aug 16 10:59:12 2018 +0300
----------------------------------------------------------------------
.../calcite/test/RexProgramBuilderBase.java | 555 +++++++++++++++++++
.../org/apache/calcite/test/RexProgramTest.java | 228 +++-----
2 files changed, 626 insertions(+), 157 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/45782ed3/core/src/test/java/org/apache/calcite/test/RexProgramBuilderBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RexProgramBuilderBase.java b/core/src/test/java/org/apache/calcite/test/RexProgramBuilderBase.java
new file mode 100644
index 0000000..e1f84fb
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/test/RexProgramBuilderBase.java
@@ -0,0 +1,555 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.test;
+
+import org.apache.calcite.DataContext;
+import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
+import org.apache.calcite.linq4j.QueryProvider;
+import org.apache.calcite.plan.RelOptPredicateList;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeSystem;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexDynamicParam;
+import org.apache.calcite.rex.RexExecutor;
+import org.apache.calcite.rex.RexExecutorImpl;
+import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexSimplify;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.type.SqlTypeName;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+/**
+ * This class provides helper methods to build rex expressions.
+ */
+public abstract class RexProgramBuilderBase {
+ /**
+ * Input variables for tests should come from a struct type, so
+ * a struct is created where the first {@code MAX_FIELDS} are nullable,
+ * and the next {@code MAX_FIELDS} are not nullable.
+ */
+ protected static final int MAX_FIELDS = 10;
+
+ protected JavaTypeFactory typeFactory;
+ protected RexBuilder rexBuilder;
+ protected RexExecutor executor;
+ protected RexSimplify simplify;
+
+ protected RexLiteral trueLiteral;
+ protected RexLiteral falseLiteral;
+ /**
+ * Nullable int literal.
+ * @deprecated since its name does not give a clue on type. Prefer {@code null_(tInt())}
+ */
+ @Deprecated
+ protected RexNode nullLiteral;
+ /**
+ * Nullable boolean literal.
+ * @deprecated prefer {@code null_(tBoolean())} or {@code nullBool}
+ */
+ @Deprecated
+ protected RexNode unknownLiteral;
+ protected RexLiteral nullBool;
+ protected RexLiteral nullInt;
+ protected RexLiteral nullVarchar;
+
+ private RelDataType nullableBool;
+ private RelDataType nonNullableBool;
+
+ private RelDataType nullableInt;
+ private RelDataType nonNullableInt;
+
+ private RelDataType nullableVarchar;
+ private RelDataType nonNullableVarchar;
+
+ // Note: JUnit 4 creates new instance for each test method,
+ // so we initialize these structures on demand
+ // It maps non-nullable type to struct of (10 nullable, 10 non-nullable) fields
+ private Map<RelDataType, RexDynamicParam> dynamicParams;
+
+ /**
+ * Dummy data context for test.
+ */
+ private static class DummyTestDataContext implements DataContext {
+ private final ImmutableMap<String, Object> map;
+
+ DummyTestDataContext() {
+ this.map =
+ ImmutableMap.of(
+ Variable.TIME_ZONE.camelName, TimeZone.getTimeZone("America/Los_Angeles"),
+ Variable.CURRENT_TIMESTAMP.camelName, 1311120000000L);
+ }
+
+ public SchemaPlus getRootSchema() {
+ return null;
+ }
+
+ public JavaTypeFactory getTypeFactory() {
+ return null;
+ }
+
+ public QueryProvider getQueryProvider() {
+ return null;
+ }
+
+ public Object get(String name) {
+ return map.get(name);
+ }
+ }
+
+ public void setUp() {
+ typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
+ rexBuilder = new RexBuilder(typeFactory);
+ executor =
+ new RexExecutorImpl(new DummyTestDataContext());
+ simplify =
+ new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false, executor)
+ .withParanoid(true);
+ trueLiteral = rexBuilder.makeLiteral(true);
+ falseLiteral = rexBuilder.makeLiteral(false);
+
+ nonNullableInt = typeFactory.createSqlType(SqlTypeName.INTEGER);
+ nullableInt = typeFactory.createTypeWithNullability(nonNullableInt, true);
+ nullInt = rexBuilder.makeNullLiteral(nullableInt);
+
+ nullLiteral = rexBuilder.makeNullLiteral(nonNullableInt);
+ unknownLiteral = rexBuilder.makeNullLiteral(trueLiteral.getType());
+
+ nonNullableBool = typeFactory.createSqlType(SqlTypeName.BOOLEAN);
+ nullableBool = typeFactory.createTypeWithNullability(nonNullableBool, true);
+ nullBool = rexBuilder.makeNullLiteral(nullableBool);
+
+ nonNullableVarchar = typeFactory.createSqlType(SqlTypeName.VARCHAR);
+ nullableVarchar = typeFactory.createTypeWithNullability(nonNullableVarchar, true);
+ nullVarchar = rexBuilder.makeNullLiteral(nullableVarchar);
+ }
+
+ private RexDynamicParam getDynamicParam(RelDataType type, String fieldNamePrefix) {
+ if (dynamicParams == null) {
+ dynamicParams = new HashMap<>();
+ }
+ return dynamicParams.computeIfAbsent(type, k -> {
+ RelDataType nullableType = typeFactory.createTypeWithNullability(k, true);
+ RelDataTypeFactory.Builder builder = typeFactory.builder();
+ for (int i = 0; i < MAX_FIELDS; i++) {
+ builder.add(fieldNamePrefix + i, nullableType);
+ }
+ String notNullPrefix = "notNull"
+ + Character.toUpperCase(fieldNamePrefix.charAt(0))
+ + fieldNamePrefix.substring(1);
+
+ for (int i = 0; i < MAX_FIELDS; i++) {
+ builder.add(notNullPrefix + i, k);
+ }
+ return rexBuilder.makeDynamicParam(builder.build(), 0);
+ });
+ }
+
+ protected RexNode isNull(RexNode node) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, node);
+ }
+
+ protected RexNode isNotNull(RexNode node) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, node);
+ }
+
+ protected RexNode isFalse(RexNode node) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.IS_FALSE, node);
+ }
+
+ protected RexNode isNotFalse(RexNode node) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_FALSE, node);
+ }
+
+ protected RexNode isTrue(RexNode node) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.IS_TRUE, node);
+ }
+
+ protected RexNode isNotTrue(RexNode node) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_TRUE, node);
+ }
+
+ protected RexNode nullIf(RexNode node1, RexNode node2) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.NULLIF, node1, node2);
+ }
+
+ protected RexNode not(RexNode node) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.NOT, node);
+ }
+
+ protected RexNode and(RexNode... nodes) {
+ return and(ImmutableList.copyOf(nodes));
+ }
+
+ protected 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));
+ }
+
+ protected RexNode or(RexNode... nodes) {
+ return or(ImmutableList.copyOf(nodes));
+ }
+
+ protected 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));
+ }
+
+ protected RexNode case_(RexNode... nodes) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.CASE, nodes);
+ }
+
+ /**
+ * Creates a call to the CAST operator.
+ *
+ * <p>This method enables to create {@code CAST(42 nullable int)} expressions.</p>
+ *
+ * @param e input node
+ * @param type type to cast to
+ * @return call to CAST operator
+ */
+ protected RexNode abstractCast(RexNode e, RelDataType type) {
+ return rexBuilder.makeAbstractCast(type, e);
+ }
+
+ /**
+ * Creates a call to the CAST operator, expanding if possible, and not
+ * preserving nullability.
+ *
+ * <p>Tries to expand the cast, and therefore the result may be something
+ * other than a {@link RexCall} to the CAST operator, such as a
+ * {@link RexLiteral}.</p>
+
+ * @param e input node
+ * @param type type to cast to
+ * @return input node converted to given type
+ */
+ protected RexNode cast(RexNode e, RelDataType type) {
+ return rexBuilder.makeCast(type, e);
+ }
+
+ protected RexNode eq(RexNode n1, RexNode n2) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, n1, n2);
+ }
+
+ protected RexNode ne(RexNode n1, RexNode n2) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.NOT_EQUALS, n1, n2);
+ }
+
+ protected RexNode le(RexNode n1, RexNode n2) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN_OR_EQUAL, n1, n2);
+ }
+
+ protected RexNode lt(RexNode n1, RexNode n2) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, n1, n2);
+ }
+
+ protected RexNode ge(RexNode n1, RexNode n2) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN_OR_EQUAL, n1, n2);
+ }
+
+ protected RexNode gt(RexNode n1, RexNode n2) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN, n1, n2);
+ }
+
+ protected RexNode plus(RexNode n1, RexNode n2) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.PLUS, n1, n2);
+ }
+
+ protected RexNode coalesce(RexNode... nodes) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.COALESCE, nodes);
+ }
+
+ protected RexNode divInt(RexNode n1, RexNode n2) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE_INTEGER, n1, n2);
+ }
+
+ protected RexNode sub(RexNode n1, RexNode n2) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.MINUS, n1, n2);
+ }
+
+ protected RexNode add(RexNode n1, RexNode n2) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.PLUS, n1, n2);
+ }
+
+ /**
+ * Generates {@code x IN (y, z)} expression when called as {@code in(x, y, z)}.
+ * @param node left side of the IN expression
+ * @param nodes nodes in the right side of IN expression
+ * @return IN expression
+ */
+ protected RexNode in(RexNode node, RexNode... nodes) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.IN,
+ ImmutableList.<RexNode>builder().add(node).add(nodes).build());
+ }
+
+ // Types
+ protected RelDataType nullable(RelDataType type) {
+ if (type.isNullable()) {
+ return type;
+ }
+ return typeFactory.createTypeWithNullability(type, true);
+ }
+
+ protected RelDataType tVarchar() {
+ return nonNullableVarchar;
+ }
+
+ protected RelDataType tVarchar(boolean nullable) {
+ return nullable ? nullableVarchar : nonNullableVarchar;
+ }
+
+ protected RelDataType tBoolean() {
+ return nonNullableBool;
+ }
+
+ protected RelDataType tBoolean(boolean nullable) {
+ return nullable ? nullableBool : nonNullableBool;
+ }
+
+ protected RelDataType tInt() {
+ return nonNullableInt;
+ }
+
+ protected RelDataType tInt(boolean nullable) {
+ return nullable ? nullableInt : nonNullableInt;
+ }
+
+ // Literals
+
+ /**
+ * Creates null literal with given type.
+ * For instance: {@code null_(tInt())}
+ *
+ * @param type type of required null
+ * @return null literal of a given type
+ */
+ protected RexLiteral null_(RelDataType type) {
+ return rexBuilder.makeNullLiteral(nullable(type));
+ }
+
+ protected RexNode literal(boolean value) {
+ return rexBuilder.makeLiteral(value, nonNullableBool, false);
+ }
+
+ protected RexNode literal(Boolean value) {
+ if (value == null) {
+ return rexBuilder.makeNullLiteral(nullableBool);
+ }
+ return literal(value.booleanValue());
+ }
+
+ protected RexNode literal(int value) {
+ return rexBuilder.makeLiteral(value, nonNullableInt, false);
+ }
+
+ protected RexNode literal(BigDecimal value) {
+ return rexBuilder.makeExactLiteral(value);
+ }
+
+ protected RexNode literal(BigDecimal value, RelDataType type) {
+ return rexBuilder.makeExactLiteral(value, type);
+ }
+
+ protected RexNode literal(Integer value) {
+ if (value == null) {
+ return rexBuilder.makeNullLiteral(nullableInt);
+ }
+ return literal(value.intValue());
+ }
+
+ protected RexNode literal(String value) {
+ if (value == null) {
+ return rexBuilder.makeNullLiteral(nullableVarchar);
+ }
+ return rexBuilder.makeLiteral(value, nonNullableVarchar, false);
+ }
+
+ // Variables
+
+ /**
+ * Generates input ref with given type and index.
+ *
+ * Prefer {@link #vBool()}, {@link #vInt()} and so on.
+ *
+ * The problem with "input refs" is {@code input(tInt(), 0).toString()} yields {@code $0},
+ * so the type of the expression is not printed, and it makes it hard to analyze the expressions.
+ * @param type desired type of the node
+ * @param arg argument index (0-based)
+ * @return input ref with given type and index
+ */
+ protected RexNode input(RelDataType type, int arg) {
+ return rexBuilder.makeInputRef(type, arg);
+ }
+
+ private void assertArgValue(int arg) {
+ assert arg >= 0 && arg < MAX_FIELDS
+ : "arg should be in 0.." + (MAX_FIELDS - 1) + " range. Actual value was " + arg;
+ }
+
+ /**
+ * Creates {@code nullable boolean variable} with index of 0.
+ * If you need several distinct variables, use {@link #vBool(int)}
+ * @return nullable boolean variable with index of 0
+ */
+ protected RexNode vBool() {
+ return vBool(0);
+ }
+
+ /**
+ * Creates {@code nullable boolean variable} with index of {@code arg} (0-based).
+ * The resulting node would look like {@code ?0.bool3} if {@code arg} is {@code 3}.
+ *
+ * @return nullable boolean variable with given index (0-based)
+ */
+ protected RexNode vBool(int arg) {
+ assertArgValue(arg);
+ return rexBuilder.makeFieldAccess(getDynamicParam(nonNullableBool, "bool"), arg);
+ }
+
+ /**
+ * Creates {@code non-nullable boolean variable} with index of 0.
+ * If you need several distinct variables, use {@link #vBoolNotNull(int)}.
+ * The resulting node would look like {@code ?0.notNullBool0}
+ *
+ * @return non-nullable boolean variable with index of 0
+ */
+ protected RexNode vBoolNotNull() {
+ return vBoolNotNull(0);
+ }
+
+ /**
+ * Creates {@code non-nullable boolean variable} with index of {@code arg} (0-based).
+ * The resulting node would look like {@code ?0.notNullBool3} if {@code arg} is {@code 3}.
+ *
+ * @return non-nullable boolean variable with given index (0-based)
+ */
+ protected RexNode vBoolNotNull(int arg) {
+ assertArgValue(arg);
+ return rexBuilder.makeFieldAccess(
+ getDynamicParam(nonNullableBool, "bool"),
+ arg + MAX_FIELDS);
+ }
+
+ /**
+ * Creates {@code nullable int variable} with index of 0.
+ * If you need several distinct variables, use {@link #vInt(int)}.
+ * The resulting node would look like {@code ?0.notNullInt0}
+ *
+ * @return nullable int variable with index of 0
+ */
+ protected RexNode vInt() {
+ return vInt(0);
+ }
+
+ /**
+ * Creates {@code nullable int variable} with index of {@code arg} (0-based).
+ * The resulting node would look like {@code ?0.int3} if {@code arg} is {@code 3}.
+ *
+ * @return nullable int variable with given index (0-based)
+ */
+ protected RexNode vInt(int arg) {
+ assertArgValue(arg);
+ return rexBuilder.makeFieldAccess(getDynamicParam(nonNullableInt, "int"), arg);
+ }
+
+ /**
+ * Creates {@code non-nullable int variable} with index of 0.
+ * If you need several distinct variables, use {@link #vIntNotNull(int)}.
+ * The resulting node would look like {@code ?0.notNullInt0}
+ *
+ * @return non-nullable int variable with index of 0
+ */
+ protected RexNode vIntNotNull() {
+ return vIntNotNull(0);
+ }
+
+ /**
+ * Creates {@code non-nullable int variable} with index of {@code arg} (0-based).
+ * The resulting node would look like {@code ?0.notNullInt3} if {@code arg} is {@code 3}.
+ *
+ * @return non-nullable int variable with given index (0-based)
+ */
+ protected RexNode vIntNotNull(int arg) {
+ assertArgValue(arg);
+ return rexBuilder.makeFieldAccess(
+ getDynamicParam(nonNullableInt, "int"),
+ arg + MAX_FIELDS);
+ }
+
+ /**
+ * Creates {@code nullable varchar variable} with index of 0.
+ * If you need several distinct variables, use {@link #vVarchar(int)}.
+ * The resulting node would look like {@code ?0.notNullVarchar0}
+ *
+ * @return nullable varchar variable with index of 0
+ */
+ protected RexNode vVarchar() {
+ return vVarchar(0);
+ }
+
+ /**
+ * Creates {@code nullable varchar variable} with index of {@code arg} (0-based).
+ * The resulting node would look like {@code ?0.varchar3} if {@code arg} is {@code 3}.
+ *
+ * @return nullable varchar variable with given index (0-based)
+ */
+ protected RexNode vVarchar(int arg) {
+ assertArgValue(arg);
+ return rexBuilder.makeFieldAccess(
+ getDynamicParam(nonNullableVarchar, "varchar"), arg);
+ }
+
+ /**
+ * Creates {@code non-nullable varchar variable} with index of 0.
+ * If you need several distinct variables, use {@link #vVarcharNotNull(int)}.
+ * The resulting node would look like {@code ?0.notNullVarchar0}
+ *
+ * @return non-nullable varchar variable with index of 0
+ */
+ protected RexNode vVarcharNotNull() {
+ return vVarcharNotNull(0);
+ }
+
+ /**
+ * Creates {@code non-nullable varchar variable} with index of {@code arg} (0-based).
+ * The resulting node would look like {@code ?0.notNullVarchar3} if {@code arg} is {@code 3}.
+ *
+ * @return non-nullable varchar variable with given index (0-based)
+ */
+ protected RexNode vVarcharNotNull(int arg) {
+ assertArgValue(arg);
+ return rexBuilder.makeFieldAccess(
+ getDynamicParam(nonNullableVarchar, "varchar"),
+ arg + MAX_FIELDS);
+ }
+}
+
+// End RexProgramBuilderBase.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/45782ed3/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
index 733579d..eb7988f 100644
--- a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
@@ -16,23 +16,15 @@
*/
package org.apache.calcite.test;
-import org.apache.calcite.DataContext;
-import org.apache.calcite.adapter.java.JavaTypeFactory;
import org.apache.calcite.avatica.util.ByteString;
-import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
-import org.apache.calcite.linq4j.QueryProvider;
import org.apache.calcite.plan.RelOptPredicateList;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.plan.Strong;
import org.apache.calcite.rel.metadata.NullSentinel;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.rel.type.RelDataTypeSystem;
-import org.apache.calcite.rex.RexBuilder;
import org.apache.calcite.rex.RexCall;
import org.apache.calcite.rex.RexDynamicParam;
-import org.apache.calcite.rex.RexExecutor;
-import org.apache.calcite.rex.RexExecutorImpl;
import org.apache.calcite.rex.RexInputRef;
import org.apache.calcite.rex.RexInterpreter;
import org.apache.calcite.rex.RexLiteral;
@@ -42,7 +34,6 @@ import org.apache.calcite.rex.RexProgram;
import org.apache.calcite.rex.RexProgramBuilder;
import org.apache.calcite.rex.RexSimplify;
import org.apache.calcite.rex.RexUtil;
-import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.SqlSpecialOperator;
@@ -73,7 +64,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import java.util.TimeZone;
import java.util.TreeMap;
import static org.hamcrest.CoreMatchers.equalTo;
@@ -87,18 +77,7 @@ import static org.junit.Assert.assertThat;
* Unit tests for {@link RexProgram} and
* {@link org.apache.calcite.rex.RexProgramBuilder}.
*/
-public class RexProgramTest {
- //~ Instance fields --------------------------------------------------------
- private JavaTypeFactory typeFactory;
- private RexBuilder rexBuilder;
- private RexLiteral trueLiteral;
- private RexLiteral falseLiteral;
- private RexNode nullLiteral;
- private RexNode unknownLiteral;
- private RexSimplify simplify;
-
- //~ Methods ----------------------------------------------------------------
-
+public class RexProgramTest extends RexProgramBuilderBase {
/**
* Creates a RexProgramTest.
*/
@@ -106,48 +85,8 @@ public class RexProgramTest {
super();
}
- @Before
- public void setUp() {
- typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
- rexBuilder = new RexBuilder(typeFactory);
- RexExecutor executor =
- new RexExecutorImpl(new DummyTestDataContext());
- simplify =
- new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false, executor)
- .withParanoid(true);
- trueLiteral = rexBuilder.makeLiteral(true);
- falseLiteral = rexBuilder.makeLiteral(false);
- final RelDataType intType = typeFactory.createSqlType(SqlTypeName.INTEGER);
- nullLiteral = rexBuilder.makeNullLiteral(intType);
- unknownLiteral = rexBuilder.makeNullLiteral(trueLiteral.getType());
- }
-
- /** Dummy data context for test. */
- private static class DummyTestDataContext implements DataContext {
- private final ImmutableMap<String, Object> map;
-
- DummyTestDataContext() {
- this.map =
- ImmutableMap.of(
- Variable.TIME_ZONE.camelName, TimeZone.getTimeZone("America/Los_Angeles"),
- Variable.CURRENT_TIMESTAMP.camelName, 1311120000000L);
- }
-
- public SchemaPlus getRootSchema() {
- return null;
- }
-
- public JavaTypeFactory getTypeFactory() {
- return null;
- }
-
- public QueryProvider getQueryProvider() {
- return null;
- }
-
- public Object get(String name) {
- return map.get(name);
- }
+ @Before public void setUp() {
+ super.setUp();
}
private void checkCnf(RexNode node, String expected) {
@@ -168,6 +107,23 @@ public class RexProgramTest {
equalTo(expected));
}
+ /**
+ * Asserts that given node has expected string representation with account of node type
+ * @param message extra message that clarifies where the node came from
+ * @param expected expected string representation of the node
+ * @param node node to check
+ */
+ private void assertNode(String message, String expected, RexNode node) {
+ String actual;
+ if (node.isA(SqlKind.CAST) || node.isA(SqlKind.NEW_SPECIFICATION)) {
+ // toString contains type (see RexCall.toString)
+ actual = node.toString();
+ } else {
+ actual = node + ":" + node.getType() + (node.getType().isNullable() ? "" : " NOT NULL");
+ }
+ assertEquals(message, expected, actual);
+ }
+
/** Simplifies an expression and checks that the result is as expected. */
private void checkSimplify(RexNode node, String expected) {
checkSimplify2(node, expected, expected);
@@ -220,82 +176,6 @@ public class RexProgramTest {
return n;
}
- private RexNode isNull(RexNode node) {
- return rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, node);
- }
-
- private RexNode isNotNull(RexNode node) {
- return rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, node);
- }
-
- private RexNode nullIf(RexNode node1, RexNode node2) {
- return rexBuilder.makeCall(SqlStdOperatorTable.NULLIF, node1, node2);
- }
-
- 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 case_(RexNode... nodes) {
- return rexBuilder.makeCall(SqlStdOperatorTable.CASE, nodes);
- }
-
- private RexNode cast(RexNode e, RelDataType type) {
- return rexBuilder.makeCast(type, e);
- }
-
- private RexNode eq(RexNode n1, RexNode n2) {
- return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, n1, n2);
- }
-
- private RexNode ne(RexNode n1, RexNode n2) {
- return rexBuilder.makeCall(SqlStdOperatorTable.NOT_EQUALS, n1, n2);
- }
-
- private RexNode le(RexNode n1, RexNode n2) {
- return rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN_OR_EQUAL, n1, n2);
- }
-
- private RexNode lt(RexNode n1, RexNode n2) {
- return rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, n1, n2);
- }
-
- private RexNode ge(RexNode n1, RexNode n2) {
- return rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN_OR_EQUAL, n1, n2);
- }
-
- private RexNode gt(RexNode n1, RexNode n2) {
- return rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN, n1, n2);
- }
-
- private RexNode plus(RexNode n1, RexNode n2) {
- return rexBuilder.makeCall(SqlStdOperatorTable.PLUS, n1, n2);
- }
-
- private RexNode coalesce(RexNode... nodes) {
- return rexBuilder.makeCall(SqlStdOperatorTable.COALESCE, nodes);
- }
-
/**
* Tests construction of a RexProgram.
*/
@@ -1704,13 +1584,8 @@ public class RexProgramTest {
}
@Test public void testSimplifyCaseNullableBoolean() {
- RexNode condition = eq(
- rexBuilder.makeInputRef(
- typeFactory.createTypeWithNullability(
- typeFactory.createSqlType(SqlTypeName.VARCHAR), false),
- 0),
- rexBuilder.makeLiteral("S"));
- RexCall caseNode = (RexCall) case_(condition, trueLiteral, falseLiteral);
+ RexNode condition = eq(input(tVarchar(), 0), literal("S"));
+ RexNode caseNode = case_(condition, trueLiteral, falseLiteral);
RexCall result = (RexCall) simplify.simplify(caseNode);
assertThat(result.getType().isNullable(), is(false));
@@ -1719,16 +1594,8 @@ public class RexProgramTest {
}
@Test public void testSimplifyCaseNullableVarChar() {
- RexNode condition = eq(
- rexBuilder.makeInputRef(
- typeFactory.createTypeWithNullability(
- typeFactory.createSqlType(SqlTypeName.VARCHAR), false),
- 0),
- rexBuilder.makeLiteral("S"));
- RexLiteral aLiteral = rexBuilder.makeLiteral("A");
- RexLiteral bLiteral = rexBuilder.makeLiteral("B");
- RexCall caseNode = (RexCall) case_(condition, aLiteral, bLiteral);
-
+ RexNode condition = eq(input(tVarchar(), 0), literal("S"));
+ RexNode caseNode = case_(condition, literal("A"), literal("B"));
RexCall result = (RexCall) simplify.simplify(caseNode);
assertThat(result.getType().isNullable(), is(false));
@@ -1773,6 +1640,17 @@ public class RexProgramTest {
checkSimplify(isNotNull(lt(i0, null_)), "false");
}
+ @Test public void checkSimplifyDynamicParam() {
+ checkSimplify(isNotNull(lt(vInt(0), vInt(1))),
+ "AND(IS NOT NULL(?0.int0), IS NOT NULL(?0.int1))");
+ checkSimplify(isNotNull(lt(vInt(0), vIntNotNull(2))),
+ "IS NOT NULL(?0.int0)");
+ checkSimplify(isNotNull(lt(vIntNotNull(2), vIntNotNull(3))), "true");
+ checkSimplify(isNotNull(lt(vInt(0), literal(BigDecimal.ONE))),
+ "IS NOT NULL(?0.int0)");
+ checkSimplify(isNotNull(lt(vInt(0), null_(tInt()))), "false");
+ }
+
@Test public void testSimplifyCastLiteral() {
final List<RexLiteral> literals = new ArrayList<>();
literals.add(
@@ -1870,6 +1748,18 @@ public class RexProgramTest {
}
}
+ @Test public void testCastLiteral() {
+ assertNode("cast(literal int not null)",
+ "42:INTEGER NOT NULL", cast(literal(42), tInt()));
+ assertNode("cast(literal int)",
+ "42:INTEGER NOT NULL", cast(literal(42), nullable(tInt())));
+
+ assertNode("abstractCast(literal int not null)",
+ "CAST(42):INTEGER NOT NULL", abstractCast(literal(42), tInt()));
+ assertNode("abstractCast(literal int)",
+ "CAST(42):INTEGER", abstractCast(literal(42), nullable(tInt())));
+ }
+
@Test public void testSimplifyCastLiteral2() {
final RexLiteral literalAbc = rexBuilder.makeLiteral("abc");
final RexLiteral literalOne = rexBuilder.makeExactLiteral(BigDecimal.ONE);
@@ -2050,6 +1940,30 @@ public class RexProgramTest {
checkSimplifyUnchanged(le(literalAbc, literalZero));
}
+ @Test public void testSimpleDynamicVars() {
+ assertTypeAndToString(
+ vBool(2), "?0.bool2", "BOOLEAN");
+ assertTypeAndToString(
+ vBoolNotNull(0), "?0.notNullBool0", "BOOLEAN NOT NULL");
+
+ assertTypeAndToString(
+ vInt(2), "?0.int2", "INTEGER");
+ assertTypeAndToString(
+ vIntNotNull(0), "?0.notNullInt0", "INTEGER NOT NULL");
+
+ assertTypeAndToString(
+ vVarchar(), "?0.varchar0", "VARCHAR");
+ assertTypeAndToString(
+ vVarcharNotNull(9), "?0.notNullVarchar9", "VARCHAR NOT NULL");
+ }
+
+ private void assertTypeAndToString(
+ RexNode rexNode, String representation, String type) {
+ assertEquals(representation, rexNode.toString());
+ assertEquals("type of " + rexNode, type, rexNode.getType().toString()
+ + (rexNode.getType().isNullable() ? "" : " NOT NULL"));
+ }
+
@Test public void testIsDeterministic() {
SqlOperator ndc = new SqlSpecialOperator(
"NDC",