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 2016/07/27 07:07:47 UTC
calcite git commit: [CALCITE-1321] When converting IN-list to join,
make minimum list size configurable (Gautam Parai)
Repository: calcite
Updated Branches:
refs/heads/master a0c98837c -> c933c79f7
[CALCITE-1321] When converting IN-list to join, make minimum list size configurable (Gautam Parai)
Add SqlToRelConverter.Config, so that all configuration parameters
can be passed as a single immutable object.
Close apache/calcite#257
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/c933c79f
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/c933c79f
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/c933c79f
Branch: refs/heads/master
Commit: c933c79f7ba2ccedd109c4a3cb55e23cfbe90f2b
Parents: a0c9883
Author: Gautam Parai <gp...@maprtech.com>
Authored: Tue Jul 19 14:56:32 2016 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jul 26 21:42:51 2016 -0700
----------------------------------------------------------------------
.../calcite/prepare/CalciteMaterializer.java | 5 +-
.../calcite/prepare/CalcitePrepareImpl.java | 25 +-
.../org/apache/calcite/prepare/PlannerImpl.java | 13 +-
.../org/apache/calcite/prepare/Prepare.java | 25 +-
.../calcite/sql2rel/SqlToRelConverter.java | 304 ++++++++++++++-----
.../apache/calcite/test/RelOptRulesTest.java | 8 +-
.../calcite/test/SqlToRelConverterTest.java | 41 ++-
.../apache/calcite/test/SqlToRelTestBase.java | 43 ++-
.../calcite/test/SqlToRelConverterTest.xml | 22 ++
.../java/org/apache/calcite/test/CsvTest.java | 8 +-
10 files changed, 365 insertions(+), 129 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/c933c79f/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java b/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
index e5a5d57..ec986c8 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
@@ -76,9 +76,10 @@ class CalciteMaterializer extends CalcitePrepareImpl.CalcitePreparingStmt {
} catch (SqlParseException e) {
throw new RuntimeException("parse failed", e);
}
-
+ final SqlToRelConverter.Config config = SqlToRelConverter.configBuilder()
+ .withTrimUnusedFields(true).build();
SqlToRelConverter sqlToRelConverter2 =
- getSqlToRelConverter(getSqlValidator(), catalogReader);
+ getSqlToRelConverter(getSqlValidator(), catalogReader, config);
materialization.queryRel =
sqlToRelConverter2.convertQuery(node, true, true).rel;
http://git-wip-us.apache.org/repos/asf/calcite/blob/c933c79f/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
index bfc1ce2..46290fa 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -297,14 +297,20 @@ public class CalcitePrepareImpl implements CalcitePrepare {
: EnumerableConvention.INSTANCE;
final HepPlanner planner = new HepPlanner(new HepProgramBuilder().build());
planner.addRelTraitDef(ConventionTraitDef.INSTANCE);
+
+ final SqlToRelConverter.ConfigBuilder configBuilder =
+ SqlToRelConverter.configBuilder().withTrimUnusedFields(true);
+ if (analyze) {
+ configBuilder.withConvertTableAccess(false);
+ }
+
final CalcitePreparingStmt preparingStmt =
new CalcitePreparingStmt(this, context, catalogReader, typeFactory,
context.getRootSchema(), null, planner, resultConvention);
final SqlToRelConverter converter =
- preparingStmt.getSqlToRelConverter(validator, catalogReader);
- if (analyze) {
- converter.enableTableAccessConversion(false);
- }
+ preparingStmt.getSqlToRelConverter(validator, catalogReader,
+ configBuilder.build());
+
final RelRoot root = converter.convertQuery(sqlNode1, false, true);
if (analyze) {
return analyze_(validator, sql, sqlNode1, root, fail);
@@ -1095,12 +1101,12 @@ public class CalcitePrepareImpl implements CalcitePrepare {
@Override protected SqlToRelConverter getSqlToRelConverter(
SqlValidator validator,
- CatalogReader catalogReader) {
+ CatalogReader catalogReader,
+ SqlToRelConverter.Config config) {
final RelOptCluster cluster = prepare.createCluster(planner, rexBuilder);
SqlToRelConverter sqlToRelConverter =
new SqlToRelConverter(this, validator, catalogReader, cluster,
- StandardConvertletTable.INSTANCE);
- sqlToRelConverter.setTrimUnusedFields(true);
+ StandardConvertletTable.INSTANCE, config);
return sqlToRelConverter;
}
@@ -1135,9 +1141,10 @@ public class CalcitePrepareImpl implements CalcitePrepare {
this.catalogReader.withSchemaPath(schemaPath);
SqlValidator validator = createSqlValidator(catalogReader);
SqlNode sqlNode1 = validator.validate(sqlNode);
-
+ final SqlToRelConverter.Config config = SqlToRelConverter.configBuilder()
+ .withTrimUnusedFields(true).build();
SqlToRelConverter sqlToRelConverter =
- getSqlToRelConverter(validator, catalogReader);
+ getSqlToRelConverter(validator, catalogReader, config);
RelRoot root =
sqlToRelConverter.convertQuery(sqlNode1, true, false);
http://git-wip-us.apache.org/repos/asf/calcite/blob/c933c79f/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
index a472683..7fab355 100644
--- a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
@@ -218,11 +218,11 @@ public class PlannerImpl implements Planner {
assert validatedSqlNode != null;
final RexBuilder rexBuilder = createRexBuilder();
final RelOptCluster cluster = RelOptCluster.create(planner, rexBuilder);
+ final SqlToRelConverter.Config config = SqlToRelConverter.configBuilder()
+ .withTrimUnusedFields(false).withConvertTableAccess(false).build();
final SqlToRelConverter sqlToRelConverter =
new SqlToRelConverter(new ViewExpanderImpl(), validator,
- createCatalogReader(), cluster, convertletTable);
- sqlToRelConverter.setTrimUnusedFields(false);
- sqlToRelConverter.enableTableAccessConversion(false);
+ createCatalogReader(), cluster, convertletTable, config);
root =
sqlToRelConverter.convertQuery(validatedSqlNode, false, true);
root = root.withRel(sqlToRelConverter.flattenTypes(root.rel, true));
@@ -255,12 +255,11 @@ public class PlannerImpl implements Planner {
final RexBuilder rexBuilder = createRexBuilder();
final RelOptCluster cluster = RelOptCluster.create(planner, rexBuilder);
+ final SqlToRelConverter.Config config = SqlToRelConverter.configBuilder()
+ .withTrimUnusedFields(false).withConvertTableAccess(false).build();
final SqlToRelConverter sqlToRelConverter =
new SqlToRelConverter(new ViewExpanderImpl(), validator,
- catalogReader, cluster, convertletTable);
-
- sqlToRelConverter.setTrimUnusedFields(false);
- sqlToRelConverter.enableTableAccessConversion(false);
+ catalogReader, cluster, convertletTable, config);
root = sqlToRelConverter.convertQuery(validatedSqlNode, true, false);
root = root.withRel(sqlToRelConverter.flattenTypes(root.rel, true));
http://git-wip-us.apache.org/repos/asf/calcite/blob/c933c79f/core/src/main/java/org/apache/calcite/prepare/Prepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/Prepare.java b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
index e95495d..8af414d 100644
--- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java
+++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
@@ -208,16 +208,21 @@ public abstract class Prepare {
init(runtimeContextClass);
- SqlToRelConverter sqlToRelConverter =
- getSqlToRelConverter(validator, catalogReader);
- sqlToRelConverter.setExpand(THREAD_EXPAND.get());
+ final SqlToRelConverter.ConfigBuilder builder =
+ SqlToRelConverter.configBuilder()
+ .withTrimUnusedFields(true)
+ .withExpand(THREAD_EXPAND.get())
+ .withExplain(sqlQuery.getKind() == SqlKind.EXPLAIN);
+ final SqlToRelConverter sqlToRelConverter =
+ getSqlToRelConverter(validator, catalogReader, builder.build());
SqlExplain sqlExplain = null;
if (sqlQuery.getKind() == SqlKind.EXPLAIN) {
// dig out the underlying SQL statement
sqlExplain = (SqlExplain) sqlQuery;
sqlQuery = sqlExplain.getExplicandum();
- sqlToRelConverter.setIsExplain(sqlExplain.getDynamicParamCount());
+ sqlToRelConverter.setDynamicParamCountInExplain(
+ sqlExplain.getDynamicParamCount());
}
RelRoot root =
@@ -319,7 +324,8 @@ public abstract class Prepare {
*/
protected abstract SqlToRelConverter getSqlToRelConverter(
SqlValidator validator,
- CatalogReader catalogReader);
+ CatalogReader catalogReader,
+ SqlToRelConverter.Config config);
public abstract RelNode flattenTypes(
RelNode rootRel,
@@ -342,11 +348,12 @@ public abstract class Prepare {
* @return Trimmed relational expression
*/
protected RelRoot trimUnusedFields(RelRoot root) {
+ final SqlToRelConverter.Config config = SqlToRelConverter.configBuilder()
+ .withTrimUnusedFields(shouldTrim(root.rel))
+ .withExpand(THREAD_EXPAND.get())
+ .build();
final SqlToRelConverter converter =
- getSqlToRelConverter(
- getSqlValidator(), catalogReader);
- converter.setTrimUnusedFields(shouldTrim(root.rel));
- converter.setExpand(THREAD_EXPAND.get());
+ getSqlToRelConverter(getSqlValidator(), catalogReader, config);
final boolean ordered = !root.collation.getFieldCollations().isEmpty();
final boolean dml = SqlKind.DML.contains(root.kind);
return root.withRel(converter.trimUnusedFields(dml || ordered, root.rel));
http://git-wip-us.apache.org/repos/asf/calcite/blob/c933c79f/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index 898e402..d450a34 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -207,7 +207,7 @@ public class SqlToRelConverter {
/** Size of the smallest IN list that will be converted to a semijoin to a
* static table. */
- public static final int IN_SUBQUERY_THRESHOLD = 20;
+ public static final int DEFAULT_IN_SUBQUERY_THRESHOLD = 20;
//~ Instance fields --------------------------------------------------------
@@ -220,14 +220,10 @@ public class SqlToRelConverter {
protected final List<RelNode> leaves = new ArrayList<>();
private final List<SqlDynamicParam> dynamicParamSqlNodes = new ArrayList<>();
private final SqlOperatorTable opTab;
- private boolean shouldConvertTableAccess;
protected final RelDataTypeFactory typeFactory;
private final SqlNodeToRexConverter exprConverter;
- private boolean decorrelationEnabled;
- private boolean trimUnusedFields;
- private boolean shouldCreateValuesRel;
- private boolean isExplain;
- private int nDynamicParamsInExplain;
+ private int explainParamCount;
+ public final SqlToRelConverter.Config config;
/**
* Fields used in name resolution for correlated subqueries.
@@ -251,10 +247,6 @@ public class SqlToRelConverter {
public final RelOptTable.ViewExpander viewExpander;
- /** Whether to expand sub-queries. If false, each sub-query becomes a
- * {@link org.apache.calcite.rex.RexSubQuery}. */
- private boolean expand = true;
-
//~ Constructors -----------------------------------------------------------
/**
* Creates a converter.
@@ -266,7 +258,7 @@ public class SqlToRelConverter {
* @param rexBuilder Rex builder
* @param convertletTable Expression converter
*/
- @Deprecated // will be removed before 2.0
+ @Deprecated // to be removed before 2.0
public SqlToRelConverter(
RelOptTable.ViewExpander viewExpander,
SqlValidator validator,
@@ -275,16 +267,29 @@ public class SqlToRelConverter {
RexBuilder rexBuilder,
SqlRexConvertletTable convertletTable) {
this(viewExpander, validator, catalogReader,
- RelOptCluster.create(planner, rexBuilder), convertletTable);
+ RelOptCluster.create(planner, rexBuilder), convertletTable,
+ Config.DEFAULT);
}
- /* Creates a converter. */
+ @Deprecated // to be removed before 2.0
public SqlToRelConverter(
RelOptTable.ViewExpander viewExpander,
SqlValidator validator,
Prepare.CatalogReader catalogReader,
RelOptCluster cluster,
SqlRexConvertletTable convertletTable) {
+ this(viewExpander, validator, catalogReader, cluster, convertletTable,
+ Config.DEFAULT);
+ }
+
+ /* Creates a converter. */
+ public SqlToRelConverter(
+ RelOptTable.ViewExpander viewExpander,
+ SqlValidator validator,
+ Prepare.CatalogReader catalogReader,
+ RelOptCluster cluster,
+ SqlRexConvertletTable convertletTable,
+ Config config) {
this.viewExpander = viewExpander;
this.opTab =
(validator
@@ -297,14 +302,9 @@ public class SqlToRelConverter {
this.rexBuilder = cluster.getRexBuilder();
this.typeFactory = rexBuilder.getTypeFactory();
this.cluster = Preconditions.checkNotNull(cluster);
- this.shouldConvertTableAccess = true;
- this.exprConverter =
- new SqlNodeToRexConverterImpl(convertletTable);
- decorrelationEnabled = true;
- trimUnusedFields = false;
- shouldCreateValuesRel = true;
- isExplain = false;
- nDynamicParamsInExplain = 0;
+ this.exprConverter = new SqlNodeToRexConverterImpl(convertletTable);
+ this.explainParamCount = 0;
+ this.config = new ConfigBuilder().withConfig(config).build();
}
//~ Methods ----------------------------------------------------------------
@@ -355,9 +355,9 @@ public class SqlToRelConverter {
* @return the current count before the optional increment
*/
public int getDynamicParamCountInExplain(boolean increment) {
- int retVal = nDynamicParamsInExplain;
+ int retVal = explainParamCount;
if (increment) {
- ++nDynamicParamsInExplain;
+ ++explainParamCount;
}
return retVal;
}
@@ -403,41 +403,14 @@ public class SqlToRelConverter {
}
/**
- * Indicates that the current statement is part of an EXPLAIN PLAN statement
+ * Sets the number of dynamic parameters in the current EXPLAIN PLAN
+ * statement.
*
- * @param nDynamicParams number of dynamic parameters in the statement
+ * @param explainParamCount number of dynamic parameters in the statement
*/
- public void setIsExplain(int nDynamicParams) {
- isExplain = true;
- nDynamicParamsInExplain = nDynamicParams;
- }
-
- /**
- * Controls whether table access references are converted to physical rels
- * immediately. The optimizer doesn't like leaf rels to have
- * {@link Convention#NONE}. However, if we are doing further conversion
- * passes (e.g. {@link RelStructuredTypeFlattener}), then we may need to
- * defer conversion. To have any effect, this must be called before any
- * convert method.
- *
- * @param enabled true for immediate conversion (the default); false to
- * generate logical LogicalTableScan instances
- */
- public void enableTableAccessConversion(boolean enabled) {
- shouldConvertTableAccess = enabled;
- }
-
- /**
- * Controls whether instances of
- * {@link org.apache.calcite.rel.logical.LogicalValues} are generated. These
- * may not be supported by all physical implementations. To have any effect,
- * this must be called before any convert method.
- *
- * @param enabled true to allow LogicalValues to be generated (the default);
- * false to force substitution of Project+OneRow instead
- */
- public void enableValuesRelCreation(boolean enabled) {
- shouldCreateValuesRel = enabled;
+ public void setDynamicParamCountInExplain(int explainParamCount) {
+ assert config.isExplain();
+ this.explainParamCount = explainParamCount;
}
private void checkConvertedType(SqlNode query, RelNode result) {
@@ -1041,7 +1014,7 @@ public class SqlToRelConverter {
case IN:
call = (SqlBasicCall) subQuery.node;
query = call.operand(1);
- if (!expand && !(query instanceof SqlNodeList)) {
+ if (!config.isExpand() && !(query instanceof SqlNodeList)) {
return;
}
final SqlNode leftKeyNode = call.operand(0);
@@ -1153,7 +1126,7 @@ public class SqlToRelConverter {
// boolean indicating whether the subquery returned 0 or >= 1 row.
call = (SqlBasicCall) subQuery.node;
query = call.operand(0);
- if (!expand) {
+ if (!config.isExpand()) {
return;
}
converted = convertExists(query, RelOptUtil.SubqueryType.EXISTS,
@@ -1168,7 +1141,7 @@ public class SqlToRelConverter {
case SCALAR_QUERY:
// Convert the subquery. If it's non-correlated, convert it
// to a constant expression.
- if (!expand) {
+ if (!config.isExpand()) {
return;
}
call = (SqlBasicCall) subQuery.node;
@@ -1331,7 +1304,7 @@ public class SqlToRelConverter {
call,
this,
isExists,
- isExplain);
+ config.isExplain());
}
if (constExpr != null) {
subQuery.expr = constExpr;
@@ -1465,10 +1438,11 @@ public class SqlToRelConverter {
* predicate. A threshold of 0 forces usage of an inline table in all cases; a
* threshold of Integer.MAX_VALUE forces usage of OR in all cases
*
- * @return threshold, default {@link #IN_SUBQUERY_THRESHOLD}
+ * @return threshold, default {@link #DEFAULT_IN_SUBQUERY_THRESHOLD}
*/
+ @Deprecated // to be removed before 2.0
protected int getInSubqueryThreshold() {
- return IN_SUBQUERY_THRESHOLD;
+ return config.getInSubqueryThreshold();
}
/**
@@ -1568,7 +1542,7 @@ public class SqlToRelConverter {
if ((rexLiteral == null) && allowLiteralsOnly) {
return null;
}
- if ((rexLiteral == null) || !shouldCreateValuesRel) {
+ if ((rexLiteral == null) || !config.isCreateValuesRel()) {
// fallback to convertRowConstructor
tuple = null;
break;
@@ -1586,7 +1560,7 @@ public class SqlToRelConverter {
bb,
rowType,
0);
- if ((rexLiteral != null) && shouldCreateValuesRel) {
+ if ((rexLiteral != null) && config.isCreateValuesRel()) {
tupleList.add(ImmutableList.of(rexLiteral));
continue;
} else {
@@ -1977,7 +1951,7 @@ public class SqlToRelConverter {
datasetName,
usedDataset);
final RelNode tableRel;
- if (shouldConvertTableAccess) {
+ if (config.isConvertTableAccess()) {
tableRel = toRel(table);
} else {
tableRel = LogicalTableScan.create(cluster, table);
@@ -2840,10 +2814,11 @@ public class SqlToRelConverter {
}
}
+ @Deprecated // to be removed before 2.0
protected boolean enableDecorrelation() {
// disable subquery decorrelation when needed.
// e.g. if outer joins are not supported.
- return decorrelationEnabled;
+ return config.isDecorrelationEnabled();
}
protected RelNode decorrelateQuery(RelNode rootRel) {
@@ -2851,25 +2826,13 @@ public class SqlToRelConverter {
}
/**
- * Sets whether to trim unused fields as part of the conversion process.
- *
- * @param trim Whether to trim unused fields
- */
- public void setTrimUnusedFields(boolean trim) {
- this.trimUnusedFields = trim;
- }
-
- /**
* Returns whether to trim unused fields as part of the conversion process.
*
* @return Whether to trim unused fields
*/
+ @Deprecated // to be removed before 2.0
public boolean isTrimUnusedFields() {
- return trimUnusedFields;
- }
-
- public void setExpand(boolean expand) {
- this.expand = expand;
+ return config.isTrimUnusedFields();
}
/**
@@ -4092,7 +4055,7 @@ public class SqlToRelConverter {
// expressions.
final SqlKind kind = expr.getKind();
final SubQuery subQuery;
- if (!expand) {
+ if (!config.isExpand()) {
final SqlCall call;
final SqlNode query;
final RelRoot root;
@@ -5063,6 +5026,183 @@ public class SqlToRelConverter {
this.r = r;
}
}
+
+ /** Creates a builder for a {@link Config}. */
+ public static ConfigBuilder configBuilder() {
+ return new ConfigBuilder();
+ }
+
+ /**
+ * Interface to define the configuration for a SqlToRelConverter.
+ * Provides methods to set each configuration option.
+ *
+ * @see ConfigBuilder
+ * @see SqlToRelConverter#configBuilder()
+ */
+ public interface Config {
+ /** Default configuration. */
+ Config DEFAULT = configBuilder().build();
+
+ /** Returns the {@code convertTableAccess} option. Controls whether table
+ * access references are converted to physical rels immediately. The
+ * optimizer doesn't like leaf rels to have {@link Convention#NONE}.
+ * However, if we are doing further conversion passes (e.g.
+ * {@link RelStructuredTypeFlattener}), then we may need to defer
+ * conversion. */
+ boolean isConvertTableAccess();
+
+ /** Returns the {@code decorrelationEnabled} option. Controls whether to
+ * disable subquery decorrelation when needed. e.g. if outer joins are not
+ * supported. */
+ boolean isDecorrelationEnabled();
+
+ /** Returns the {@code trimUnusedFields} option. Controls whether to trim
+ * unused fields as part of the conversion process. */
+ boolean isTrimUnusedFields();
+
+ /** Returns the {@code createValuesRel} option. Controls whether instances
+ * of {@link org.apache.calcite.rel.logical.LogicalValues} are generated.
+ * These may not be supported by all physical implementations. */
+ boolean isCreateValuesRel();
+
+ /** Returns the {@code explain} option. Describes whether the current
+ * statement is part of an EXPLAIN PLAN statement. */
+ boolean isExplain();
+
+ /** Returns the {@code expand} option. Controls whether to expand
+ * sub-queries. If false, each sub-query becomes a
+ * {@link org.apache.calcite.rex.RexSubQuery}. */
+ boolean isExpand();
+
+ /** Returns the {@code inSubqueryThreshold} option,
+ * default {@link #DEFAULT_IN_SUBQUERY_THRESHOLD}. Controls the list size
+ * threshold under which {@link #convertInToOr} is used. Lists of this size
+ * or greater will instead be converted to use a join against an inline
+ * table ({@link org.apache.calcite.rel.logical.LogicalValues}) rather than
+ * a predicate. A threshold of 0 forces usage of an inline table in all
+ * cases; a threshold of {@link Integer#MAX_VALUE} forces usage of OR in all
+ * cases. */
+ int getInSubqueryThreshold();
+ }
+
+ /** Builder for a {@link Config}. */
+ public static class ConfigBuilder {
+ private boolean convertTableAccess = true;
+ private boolean decorrelationEnabled = true;
+ private boolean trimUnusedFields = false;
+ private boolean createValuesRel = true;
+ private boolean explain;
+ private boolean expand = true;
+ private int inSubqueryThreshold = DEFAULT_IN_SUBQUERY_THRESHOLD;
+
+ private ConfigBuilder() {}
+
+ /** Sets configuration identical to a given {@link Config}. */
+ public ConfigBuilder withConfig(Config config) {
+ this.convertTableAccess = config.isConvertTableAccess();
+ this.decorrelationEnabled = config.isDecorrelationEnabled();
+ this.trimUnusedFields = config.isTrimUnusedFields();
+ this.createValuesRel = config.isCreateValuesRel();
+ this.explain = config.isExplain();
+ this.expand = config.isExpand();
+ this.inSubqueryThreshold = config.getInSubqueryThreshold();
+ return this;
+ }
+
+ public ConfigBuilder withConvertTableAccess(boolean convertTableAccess) {
+ this.convertTableAccess = convertTableAccess;
+ return this;
+ }
+
+ public ConfigBuilder withDecorrelationEnabled(boolean enabled) {
+ this.decorrelationEnabled = enabled;
+ return this;
+ }
+
+ public ConfigBuilder withTrimUnusedFields(boolean trimUnusedFields) {
+ this.trimUnusedFields = trimUnusedFields;
+ return this;
+ }
+
+ public ConfigBuilder withCreateValuesRel(boolean createValuesRel) {
+ this.createValuesRel = createValuesRel;
+ return this;
+ }
+
+ public ConfigBuilder withExplain(boolean explain) {
+ this.explain = explain;
+ return this;
+ }
+
+ public ConfigBuilder withExpand(boolean expand) {
+ this.expand = expand;
+ return this;
+ }
+
+ public ConfigBuilder withInSubqueryThreshold(int inSubqueryThreshold) {
+ this.inSubqueryThreshold = inSubqueryThreshold;
+ return this;
+ }
+
+ /** Builds a {@link Config}. */
+ public Config build() {
+ return new ConfigImpl(convertTableAccess, decorrelationEnabled,
+ trimUnusedFields, createValuesRel, explain, expand,
+ inSubqueryThreshold);
+ }
+ }
+
+ /** Implementation of {@link Config}.
+ * Called by builder; all values are in private final fields. */
+ private static class ConfigImpl implements Config {
+ private final boolean convertTableAccess;
+ private final boolean decorrelationEnabled;
+ private final boolean trimUnusedFields;
+ private final boolean createValuesRel;
+ private final boolean explain;
+ private final int inSubqueryThreshold;
+ private final boolean expand;
+
+ private ConfigImpl(boolean convertTableAccess, boolean decorrelationEnabled,
+ boolean trimUnusedFields, boolean createValuesRel, boolean explain,
+ boolean expand, int inSubqueryThreshold) {
+ this.convertTableAccess = convertTableAccess;
+ this.decorrelationEnabled = decorrelationEnabled;
+ this.trimUnusedFields = trimUnusedFields;
+ this.createValuesRel = createValuesRel;
+ this.explain = explain;
+ this.expand = expand;
+ this.inSubqueryThreshold = inSubqueryThreshold;
+ }
+
+ public boolean isConvertTableAccess() {
+ return convertTableAccess;
+ }
+
+ public boolean isDecorrelationEnabled() {
+ return decorrelationEnabled;
+ }
+
+ public boolean isTrimUnusedFields() {
+ return trimUnusedFields;
+ }
+
+ public boolean isCreateValuesRel() {
+ return createValuesRel;
+ }
+
+ public boolean isExplain() {
+ return explain;
+ }
+
+ public boolean isExpand() {
+ return expand;
+ }
+
+ public int getInSubqueryThreshold() {
+ return inSubqueryThreshold;
+ }
+ }
}
// End SqlToRelConverter.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/c933c79f/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index d9340fb..b8de6ca 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -519,11 +519,12 @@ public class RelOptRulesTest extends RelOptTestBase {
final SqlValidator validator =
t.createValidator(
catalogReader, typeFactory);
- final SqlToRelConverter converter =
+ SqlToRelConverter converter =
t.createSqlToRelConverter(
validator,
catalogReader,
- typeFactory);
+ typeFactory,
+ SqlToRelConverter.Config.DEFAULT);
final SqlNode sqlQuery;
try {
@@ -551,7 +552,8 @@ public class RelOptRulesTest extends RelOptTestBase {
String planBefore = NL + RelOptUtil.toString(root.rel);
diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
- converter.setTrimUnusedFields(true);
+ converter = t.createSqlToRelConverter(validator, catalogReader, typeFactory,
+ SqlToRelConverter.configBuilder().withTrimUnusedFields(true).build());
root = root.withRel(converter.trimUnusedFields(false, root.rel));
String planAfter = NL + RelOptUtil.toString(root.rel);
diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
http://git-wip-us.apache.org/repos/asf/calcite/blob/c933c79f/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
index 5162577..e07c77b 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -24,6 +24,7 @@ import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.sql.SqlExplainLevel;
import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql2rel.SqlToRelConverter;
import org.apache.calcite.util.Bug;
import org.apache.calcite.util.Litmus;
import org.apache.calcite.util.TestUtil;
@@ -53,7 +54,8 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
/** Sets the SQL statement for a test. */
public final Sql sql(String sql) {
- return new Sql(sql, true, true, tester, false);
+ return new Sql(sql, true, true, tester, false,
+ SqlToRelConverter.Config.DEFAULT);
}
protected final void check(
@@ -1819,6 +1821,24 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
sql(sql).with(getTesterWithDynamicTable()).ok();
}
+ /** Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-1321">[CALCITE-1321]
+ * Configurable IN list size when converting IN clause to join</a>. */
+ @Test public void testInToSemiJoin() {
+ final String sql = "SELECT empno"
+ + " FROM emp AS e"
+ + " WHERE cast(e.empno as bigint) in (130, 131, 132, 133, 134)";
+ // No conversion to join since less than IN-list size threshold 10
+ SqlToRelConverter.Config noConvertConfig = SqlToRelConverter.configBuilder().
+
+ withInSubqueryThreshold(10).build();
+ sql(sql).withConfig(noConvertConfig).convertsTo("${planNotConverted}");
+ // Conversion to join since greater than IN-list size threshold 2
+ SqlToRelConverter.Config convertConfig = SqlToRelConverter.configBuilder().
+ withInSubqueryThreshold(2).build();
+ sql(sql).withConfig(convertConfig).convertsTo("${planConverted}");
+ }
+
private Tester getTesterWithDynamicTable() {
return tester.withCatalogReaderFactory(
new Function<RelDataTypeFactory, Prepare.CatalogReader>() {
@@ -1881,15 +1901,17 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
private final boolean expand;
private final boolean decorrelate;
private final Tester tester;
- private boolean trim;
+ private final boolean trim;
+ private final SqlToRelConverter.Config config;
Sql(String sql, boolean expand, boolean decorrelate, Tester tester,
- boolean trim) {
+ boolean trim, SqlToRelConverter.Config config) {
this.sql = sql;
this.expand = expand;
this.decorrelate = decorrelate;
this.tester = tester;
this.trim = trim;
+ this.config = config;
}
public void ok() {
@@ -1899,23 +1921,28 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
public void convertsTo(String plan) {
tester.withExpand(expand)
.withDecorrelation(decorrelate)
+ .withConfig(config)
.assertConvertsTo(sql, plan, trim);
}
+ public Sql withConfig(SqlToRelConverter.Config config) {
+ return new Sql(sql, expand, decorrelate, tester, trim, config);
+ }
+
public Sql expand(boolean expand) {
- return new Sql(sql, expand, decorrelate, tester, trim);
+ return new Sql(sql, expand, decorrelate, tester, trim, config);
}
public Sql decorrelate(boolean decorrelate) {
- return new Sql(sql, expand, decorrelate, tester, trim);
+ return new Sql(sql, expand, decorrelate, tester, trim, config);
}
public Sql with(Tester tester) {
- return new Sql(sql, expand, decorrelate, tester, trim);
+ return new Sql(sql, expand, decorrelate, tester, trim, config);
}
public Sql trim(boolean trim) {
- return new Sql(sql, expand, decorrelate, tester, trim);
+ return new Sql(sql, expand, decorrelate, tester, trim, config);
}
}
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/c933c79f/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
index 40c6d47..d8e0ff0 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
@@ -216,6 +216,10 @@ public abstract class SqlToRelTestBase {
* @see Prepare#THREAD_EXPAND */
Tester withExpand(boolean expand);
+ /** Returns a tester that optionally uses a
+ * {@code SqlToRelConverter.Config}. */
+ Tester withConfig(SqlToRelConverter.Config config);
+
Tester withCatalogReaderFactory(
Function<RelDataTypeFactory, Prepare.CatalogReader> factory);
@@ -467,6 +471,7 @@ public abstract class SqlToRelTestBase {
catalogReaderFactory;
private final Function<RelOptCluster, RelOptCluster> clusterFactory;
private RelDataTypeFactory typeFactory;
+ public final SqlToRelConverter.Config config;
/**
* Creates a TesterImpl.
@@ -483,17 +488,29 @@ public abstract class SqlToRelTestBase {
Function<RelDataTypeFactory, Prepare.CatalogReader>
catalogReaderFactory,
Function<RelOptCluster, RelOptCluster> clusterFactory) {
+ this(diffRepos, enableDecorrelate, enableTrim, enableExpand,
+ catalogReaderFactory, clusterFactory, SqlToRelConverter.Config.DEFAULT);
+ }
+
+ protected TesterImpl(DiffRepository diffRepos, boolean enableDecorrelate,
+ boolean enableTrim, boolean enableExpand,
+ Function<RelDataTypeFactory, Prepare.CatalogReader>
+ catalogReaderFactory,
+ Function<RelOptCluster, RelOptCluster> clusterFactory,
+ SqlToRelConverter.Config config) {
this.diffRepos = diffRepos;
this.enableDecorrelate = enableDecorrelate;
this.enableTrim = enableTrim;
this.enableExpand = enableExpand;
this.catalogReaderFactory = catalogReaderFactory;
this.clusterFactory = clusterFactory;
+ this.config = config;
}
public RelRoot convertSqlToRel(String sql) {
Util.pre(sql != null, "sql != null");
final SqlNode sqlQuery;
+ final SqlToRelConverter.Config localConfig;
try {
sqlQuery = parseQuery(sql);
} catch (Exception e) {
@@ -505,13 +522,20 @@ public abstract class SqlToRelTestBase {
final SqlValidator validator =
createValidator(
catalogReader, typeFactory);
+ if (config == SqlToRelConverter.Config.DEFAULT) {
+ localConfig = SqlToRelConverter.configBuilder()
+ .withTrimUnusedFields(true).withExpand(enableExpand).build();
+ } else {
+ localConfig = config;
+ }
+
final SqlToRelConverter converter =
createSqlToRelConverter(
validator,
catalogReader,
- typeFactory);
- converter.setTrimUnusedFields(true);
- converter.setExpand(enableExpand);
+ typeFactory,
+ localConfig);
+
final SqlNode validatedQuery = validator.validate(sqlQuery);
RelRoot root =
converter.convertQuery(validatedQuery, false, true);
@@ -523,7 +547,6 @@ public abstract class SqlToRelTestBase {
root = root.withRel(converter.decorrelate(sqlQuery, root.rel));
}
if (enableTrim) {
- converter.setTrimUnusedFields(true);
root = root.withRel(converter.trimUnusedFields(true, root.rel));
}
return root;
@@ -532,7 +555,8 @@ public abstract class SqlToRelTestBase {
protected SqlToRelConverter createSqlToRelConverter(
final SqlValidator validator,
final Prepare.CatalogReader catalogReader,
- final RelDataTypeFactory typeFactory) {
+ final RelDataTypeFactory typeFactory,
+ final SqlToRelConverter.Config config) {
final RexBuilder rexBuilder = new RexBuilder(typeFactory);
RelOptCluster cluster =
RelOptCluster.create(getPlanner(), rexBuilder);
@@ -540,7 +564,7 @@ public abstract class SqlToRelTestBase {
cluster = clusterFactory.apply(cluster);
}
return new SqlToRelConverter(null, validator, catalogReader, cluster,
- StandardConvertletTable.INSTANCE);
+ StandardConvertletTable.INSTANCE, config);
}
protected final RelDataTypeFactory getTypeFactory() {
@@ -671,6 +695,13 @@ public abstract class SqlToRelTestBase {
catalogReaderFactory, clusterFactory);
}
+ public TesterImpl withConfig(SqlToRelConverter.Config config) {
+ return this.config == config
+ ? this
+ : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
+ enableExpand, catalogReaderFactory, clusterFactory, config);
+ }
+
public Tester withTrim(boolean enable) {
return this.enableTrim == enable
? this
http://git-wip-us.apache.org/repos/asf/calcite/blob/c933c79f/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index 0241f7e..b3f8a84 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -3456,4 +3456,26 @@ LogicalProject(**=[$0])
]]>
</Resource>
</TestCase>
+ <TestCase name="testInToSemiJoin">
+ <Resource name="sql">
+ <![CDATA[SELECT * from SALES.NATION order by n_nationkey]]>
+ </Resource>
+ <Resource name="planNotConverted">
+ <![CDATA[
+LogicalProject(EMPNO=[$0])
+ LogicalFilter(condition=[OR(=(CAST($0):BIGINT NOT NULL, 130), =(CAST($0):BIGINT NOT NULL, 131), =(CAST($0):BIGINT NOT NULL, 132), =(CAST($0):BIGINT NOT NULL, 133), =(CAST($0):BIGINT NOT NULL, 134))])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ <Resource name="planConverted">
+ <![CDATA[
+LogicalProject(EMPNO=[$0])
+ LogicalJoin(condition=[=($9, $10)], joinType=[inner])
+ LogicalProject($f0=[$0], $f1=[$1], $f2=[$2], $f3=[$3], $f4=[$4], $f5=[$5], $f6=[$6], $f7=[$7], $f8=[$8], $f9=[CAST($0):BIGINT NOT NULL])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0}])
+ LogicalValues(tuples=[[{ 130 }, { 131 }, { 132 }, { 133 }, { 134 }]])
+]]>
+ </Resource>
+ </TestCase>
</Root>
http://git-wip-us.apache.org/repos/asf/calcite/blob/c933c79f/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
----------------------------------------------------------------------
diff --git a/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java b/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
index dbb52d5..1d35ec5 100644
--- a/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
+++ b/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
@@ -371,11 +371,11 @@ public class CsvTest {
final String sql = "SELECT e.name\n"
+ "FROM emps AS e\n"
+ "WHERE cast(e.empno as bigint) in ";
- checkSql(sql + range(130, SqlToRelConverter.IN_SUBQUERY_THRESHOLD - 5),
+ checkSql(sql + range(130, SqlToRelConverter.DEFAULT_IN_SUBQUERY_THRESHOLD - 5),
"smart", expect("NAME=Alice"));
- checkSql(sql + range(130, SqlToRelConverter.IN_SUBQUERY_THRESHOLD),
+ checkSql(sql + range(130, SqlToRelConverter.DEFAULT_IN_SUBQUERY_THRESHOLD),
"smart", expect("NAME=Alice"));
- checkSql(sql + range(130, SqlToRelConverter.IN_SUBQUERY_THRESHOLD + 1000),
+ checkSql(sql + range(130, SqlToRelConverter.DEFAULT_IN_SUBQUERY_THRESHOLD + 1000),
"smart", expect("NAME=Alice"));
}
@@ -386,7 +386,7 @@ public class CsvTest {
final String sql = "SELECT e.name\n"
+ "FROM emps AS e\n"
+ "WHERE e.empno in "
- + range(130, SqlToRelConverter.IN_SUBQUERY_THRESHOLD);
+ + range(130, SqlToRelConverter.DEFAULT_IN_SUBQUERY_THRESHOLD);
checkSql(sql, "smart", expect("NAME=Alice"));
}