This is an automated email from the ASF dual-hosted git repository.
luoc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/drill.git
The following commit(s) were added to refs/heads/master by this push:
new cbfdfff DRILL-7972: ClassCastException when joining RDBMS and
Elasticsearch tables (#2275)
cbfdfff is described below
commit cbfdfff3e2eefcb147d5509cdf369679675827c8
Author: Volodymyr Vysotskyi <[email protected]>
AuthorDate: Sun Jul 25 03:51:16 2021 +0300
DRILL-7972: ClassCastException when joining RDBMS and Elasticsearch tables
(#2275)
---
.../calcite/adapter/cassandra/CalciteUtils.java | 5 +-
.../adapter/elasticsearch/CalciteUtils.java | 4 +-
.../drill/exec/store/jdbc/DrillJdbcConvention.java | 2 +-
.../jdbc/JdbcIntermediatePrelConverterRule.java | 37 +++++--
.../exec/store/jdbc/TestJdbcPluginWithH2IT.java | 17 ++++
.../apache/drill/exec/ops/FragmentContextImpl.java | 66 ++++++++++--
.../EnumerableIntermediatePrelConverterRule.java | 36 +++++--
.../exec/store/enumerable/EnumPluginTest.java | 47 +++++++++
.../exec/store/enumerable/plan/EnumMockPlugin.java | 112 +++++++++++++++++++++
.../exec/store/enumerable/plan/EnumMockRel.java | 86 ++++++++++++++++
.../exec/store/enumerable/plan/EnumMockSchema.java | 53 ++++++++++
.../exec/store/enumerable/plan/EnumMockTable.java | 38 +++++++
.../java-exec/src/test/resources/drill-module.conf | 1 +
13 files changed, 470 insertions(+), 34 deletions(-)
diff --git
a/contrib/storage-cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CalciteUtils.java
b/contrib/storage-cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CalciteUtils.java
index e996522..b952eee 100644
---
a/contrib/storage-cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CalciteUtils.java
+++
b/contrib/storage-cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CalciteUtils.java
@@ -22,7 +22,6 @@ import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptTable;
import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.convert.ConverterRule;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.drill.exec.store.cassandra.CassandraStorageConfig;
@@ -40,9 +39,9 @@ public class CalciteUtils {
private static final VertexDrelConverterRule VERTEX_DREL_CONVERTER_RULE =
new VertexDrelConverterRule(CassandraRel.CONVENTION);
- private static final ConverterRule
ENUMERABLE_INTERMEDIATE_PREL_CONVERTER_RULE =
+ private static final RelOptRule ENUMERABLE_INTERMEDIATE_PREL_CONVERTER_RULE =
new EnumerableIntermediatePrelConverterRule(
- new CassandraEnumerablePrelContext(CassandraStorageConfig.NAME));
+ new CassandraEnumerablePrelContext(CassandraStorageConfig.NAME),
CassandraRel.CONVENTION);
public static CassandraTableScan tableScanCreator(RelOptCluster cluster,
RelTraitSet traitSet,
RelOptTable table, CassandraTable cassandraTable,
diff --git
a/contrib/storage-elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/CalciteUtils.java
b/contrib/storage-elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/CalciteUtils.java
index 4c3d6ec..e7b5fdc 100644
---
a/contrib/storage-elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/CalciteUtils.java
+++
b/contrib/storage-elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/CalciteUtils.java
@@ -48,9 +48,9 @@ public class CalciteUtils {
public static final VertexDrelConverterRule ELASTIC_DREL_CONVERTER_RULE =
new VertexDrelConverterRule(ElasticsearchRel.CONVENTION);
- public static final EnumerableIntermediatePrelConverterRule
ENUMERABLE_INTERMEDIATE_PREL_CONVERTER_RULE =
+ public static final RelOptRule ENUMERABLE_INTERMEDIATE_PREL_CONVERTER_RULE =
new EnumerableIntermediatePrelConverterRule(
- new
ElasticSearchEnumerablePrelContext(ElasticsearchStorageConfig.NAME));
+ new
ElasticSearchEnumerablePrelContext(ElasticsearchStorageConfig.NAME),
ElasticsearchRel.CONVENTION);
public static Set<RelOptRule> elasticSearchRules() {
// filters Calcite implementations of some rules and adds alternative
versions specific for Drill
diff --git
a/contrib/storage-jdbc/src/main/java/org/apache/drill/exec/store/jdbc/DrillJdbcConvention.java
b/contrib/storage-jdbc/src/main/java/org/apache/drill/exec/store/jdbc/DrillJdbcConvention.java
index 401cf51..a47a4f2 100644
---
a/contrib/storage-jdbc/src/main/java/org/apache/drill/exec/store/jdbc/DrillJdbcConvention.java
+++
b/contrib/storage-jdbc/src/main/java/org/apache/drill/exec/store/jdbc/DrillJdbcConvention.java
@@ -60,7 +60,7 @@ class DrillJdbcConvention extends JdbcConvention {
.collect(Collectors.toList());
this.rules = ImmutableSet.<RelOptRule>builder()
.addAll(calciteJdbcRules)
- .add(JdbcIntermediatePrelConverterRule.INSTANCE)
+ .add(new JdbcIntermediatePrelConverterRule(this))
.add(new VertexDrelConverterRule(this))
.add(new DrillJdbcRuleBase.DrillJdbcProjectRule(Convention.NONE, this))
.add(new
DrillJdbcRuleBase.DrillJdbcProjectRule(DrillRel.DRILL_LOGICAL, this))
diff --git
a/contrib/storage-jdbc/src/main/java/org/apache/drill/exec/store/jdbc/JdbcIntermediatePrelConverterRule.java
b/contrib/storage-jdbc/src/main/java/org/apache/drill/exec/store/jdbc/JdbcIntermediatePrelConverterRule.java
index 5147cfe..a66888f 100644
---
a/contrib/storage-jdbc/src/main/java/org/apache/drill/exec/store/jdbc/JdbcIntermediatePrelConverterRule.java
+++
b/contrib/storage-jdbc/src/main/java/org/apache/drill/exec/store/jdbc/JdbcIntermediatePrelConverterRule.java
@@ -17,29 +17,44 @@
*/
package org.apache.drill.exec.store.jdbc;
-import java.util.function.Predicate;
-
+import org.apache.calcite.adapter.jdbc.JdbcConvention;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelTrait;
import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.convert.ConverterRule;
import org.apache.drill.exec.planner.logical.DrillRel;
import org.apache.drill.exec.planner.logical.DrillRelFactories;
+import org.apache.drill.exec.planner.logical.RelOptHelper;
import org.apache.drill.exec.planner.physical.Prel;
import org.apache.drill.exec.store.enumerable.plan.VertexDrel;
-final class JdbcIntermediatePrelConverterRule extends ConverterRule {
+class JdbcIntermediatePrelConverterRule extends RelOptRule {
+
+ private final RelTrait inTrait;
+ private final RelTrait outTrait;
- static final JdbcIntermediatePrelConverterRule INSTANCE = new
JdbcIntermediatePrelConverterRule();
+ public JdbcIntermediatePrelConverterRule(JdbcConvention jdbcConvention) {
+ super(
+ RelOptHelper.some(VertexDrel.class, DrillRel.DRILL_LOGICAL,
+ RelOptHelper.any(RelNode.class, jdbcConvention)),
+ DrillRelFactories.LOGICAL_BUILDER, "JDBC_PREL_Converter" +
jdbcConvention);
- private JdbcIntermediatePrelConverterRule() {
- super(VertexDrel.class, (Predicate<RelNode>) input -> true,
DrillRel.DRILL_LOGICAL,
- Prel.DRILL_PHYSICAL, DrillRelFactories.LOGICAL_BUILDER,
"JDBC_PREL_Converter");
+ this.inTrait = DrillRel.DRILL_LOGICAL;
+ this.outTrait = Prel.DRILL_PHYSICAL;
}
@Override
- public RelNode convert(RelNode in) {
- return new JdbcIntermediatePrel(
+ public void onMatch(RelOptRuleCall call) {
+ VertexDrel in = call.rel(0);
+ RelNode jdbcIntermediatePrel = new JdbcIntermediatePrel(
in.getCluster(),
- in.getTraitSet().replace(getOutTrait()),
+ in.getTraitSet().replace(outTrait),
in.getInput(0));
+ call.transformTo(jdbcIntermediatePrel);
+ }
+
+ @Override
+ public boolean matches(RelOptRuleCall call) {
+ return super.matches(call) && call.rel(0).getTraitSet().contains(inTrait);
}
}
diff --git
a/contrib/storage-jdbc/src/test/java/org/apache/drill/exec/store/jdbc/TestJdbcPluginWithH2IT.java
b/contrib/storage-jdbc/src/test/java/org/apache/drill/exec/store/jdbc/TestJdbcPluginWithH2IT.java
index 94b60cf..9a24819 100644
---
a/contrib/storage-jdbc/src/test/java/org/apache/drill/exec/store/jdbc/TestJdbcPluginWithH2IT.java
+++
b/contrib/storage-jdbc/src/test/java/org/apache/drill/exec/store/jdbc/TestJdbcPluginWithH2IT.java
@@ -23,6 +23,7 @@ import org.apache.drill.categories.JdbcStorageTest;
import org.apache.drill.exec.ExecConstants;
import org.apache.drill.exec.expr.fn.impl.DateUtility;
+import org.apache.drill.exec.store.enumerable.plan.EnumMockPlugin;
import org.apache.drill.exec.util.StoragePluginTestUtils;
import org.apache.drill.test.ClusterFixture;
import org.apache.drill.test.ClusterTest;
@@ -76,6 +77,10 @@ public class TestJdbcPluginWithH2IT extends ClusterTest {
jdbcStorageConfig.setEnabled(true);
cluster.defineStoragePlugin("h2", jdbcStorageConfig);
cluster.defineStoragePlugin("h2o", jdbcStorageConfig);
+
+ EnumMockPlugin.EnumMockStoragePluginConfig config = new
EnumMockPlugin.EnumMockStoragePluginConfig();
+ config.setEnabled(true);
+ cluster.defineStoragePlugin("mocked_enum", config);
}
@AfterClass
@@ -286,4 +291,16 @@ public class TestJdbcPluginWithH2IT extends ClusterTest {
.baselineValuesForSingleColumn("SYSTEM TABLE", "TABLE")
.go();
}
+
+ @Test // DRILL-7972
+ public void testJdbcIntermConvRuleConvention() throws Exception {
+ String query = "select t1.person_ID from h2.tmp.drill_h2_test.person t1 " +
+ "join mocked_enum.mock_enum_table t2 on t1.person_ID = t2.a";
+
+ queryBuilder()
+ .sql(query)
+ .planMatcher()
+ .include("mocked_enum")
+ .match();
+ }
}
diff --git
a/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContextImpl.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContextImpl.java
index 42265e8..aec989e 100644
---
a/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContextImpl.java
+++
b/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContextImpl.java
@@ -67,8 +67,10 @@ import org.apache.drill.exec.server.QueryProfileStoreContext;
import org.apache.drill.exec.server.options.FragmentOptionManager;
import org.apache.drill.exec.server.options.OptionList;
import org.apache.drill.exec.server.options.OptionManager;
+import org.apache.drill.exec.server.options.OptionValue;
import org.apache.drill.exec.store.PartitionExplorer;
import org.apache.drill.exec.store.SchemaConfig;
+import org.apache.drill.exec.store.SchemaTreeProvider;
import org.apache.drill.exec.testing.ExecutionControls;
import org.apache.drill.exec.util.ImpersonationUtil;
import org.apache.drill.exec.work.batch.IncomingBuffers;
@@ -123,6 +125,7 @@ public class FragmentContextImpl extends
BaseFragmentContext implements Executor
private final DrillbitContext context;
private final UserClientConnection connection; // is null if this context is
for non-root fragment
private final QueryContext queryContext; // is null if this context is for
non-root fragment
+ private final SchemaTreeProvider schemaTreeProvider; // is null if this
context is for root fragment
private final FragmentStats stats;
private final BufferAllocator allocator;
private final PlanFragment fragment;
@@ -190,6 +193,7 @@ public class FragmentContextImpl extends
BaseFragmentContext implements Executor
super(funcRegistry);
this.context = dbContext;
this.queryContext = queryContext;
+ this.schemaTreeProvider = queryContext == null ? new
SchemaTreeProvider(context) : null;
this.connection = connection;
this.accountingUserConnection = new AccountingUserConnection(connection,
sendingAccountor, statusHandler);
this.fragment = fragment;
@@ -291,13 +295,11 @@ public class FragmentContextImpl extends
BaseFragmentContext implements Executor
@Override
public SchemaPlus getFullRootSchema() {
- if (queryContext == null) {
- fail(new UnsupportedOperationException("Schema tree can only be created
in root fragment. " +
- "This is a non-root fragment."));
- return null;
- }
+ return queryContext != null ? getQueryContextRootSchema() :
getFragmentContextRootSchema();
+ }
- final boolean isImpersonationEnabled = isImpersonationEnabled();
+ private SchemaPlus getQueryContextRootSchema() {
+ boolean isImpersonationEnabled = isImpersonationEnabled();
// If impersonation is enabled, we want to view the schema as query user
and suppress authorization errors. As for
// InfoSchema purpose we want to show tables the user has permissions to
list or query. If impersonation is
// disabled view the schema as Drillbit process user and throw
authorization errors to client.
@@ -311,6 +313,18 @@ public class FragmentContextImpl extends
BaseFragmentContext implements Executor
return queryContext.getFullRootSchema(schemaConfig);
}
+ private SchemaPlus getFragmentContextRootSchema() {
+ boolean isImpersonationEnabled = isImpersonationEnabled();
+ SchemaConfig schemaConfig = SchemaConfig
+ .newBuilder(
+ isImpersonationEnabled ? contextInformation.getQueryUser() :
ImpersonationUtil.getProcessUserName(),
+ new FragmentSchemaConfigInfoProvider(fragmentOptions,
contextInformation.getQueryUser(), context))
+ .setIgnoreAuthErrors(isImpersonationEnabled)
+ .build();
+
+ return schemaTreeProvider.createFullRootSchema(schemaConfig);
+ }
+
@Override
public FragmentStats getStats() {
return stats;
@@ -557,6 +571,7 @@ public class FragmentContextImpl extends
BaseFragmentContext implements Executor
}
suppressingClose(bufferManager);
suppressingClose(allocator);
+ suppressingClose(schemaTreeProvider);
}
private void suppressingClose(final AutoCloseable closeable) {
@@ -649,4 +664,43 @@ public class FragmentContextImpl extends
BaseFragmentContext implements Executor
// it as a stub for now. (No operator ever actually used the
// old OUT_OF_MEMORY iterator status that this method replaces.)
}
+
+ private static class FragmentSchemaConfigInfoProvider implements
SchemaConfig.SchemaConfigInfoProvider {
+
+ private final OptionManager optionManager;
+
+ private final String queryUser;
+
+ private final SchemaTreeProvider schemaTreeProvider;
+
+ private final ViewExpansionContext viewExpansionContext;
+
+ private FragmentSchemaConfigInfoProvider(OptionManager optionManager,
+ String queryUser, DrillbitContext context) {
+ this.optionManager = optionManager;
+ this.queryUser = queryUser;
+ this.schemaTreeProvider = new SchemaTreeProvider(context);
+ viewExpansionContext = new ViewExpansionContext(context.getConfig(),
this);
+ }
+
+ @Override
+ public ViewExpansionContext getViewExpansionContext() {
+ return viewExpansionContext;
+ }
+
+ @Override
+ public SchemaPlus getRootSchema(String userName) {
+ return schemaTreeProvider.createFullRootSchema(userName, this);
+ }
+
+ @Override
+ public String getQueryUserName() {
+ return queryUser;
+ }
+
+ @Override
+ public OptionValue getOption(String optionKey) {
+ return optionManager.getOption(optionKey);
+ }
+ }
}
diff --git
a/exec/java-exec/src/main/java/org/apache/drill/exec/store/enumerable/plan/EnumerableIntermediatePrelConverterRule.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/store/enumerable/plan/EnumerableIntermediatePrelConverterRule.java
index 615ec61..7272a36 100644
---
a/exec/java-exec/src/main/java/org/apache/drill/exec/store/enumerable/plan/EnumerableIntermediatePrelConverterRule.java
+++
b/exec/java-exec/src/main/java/org/apache/drill/exec/store/enumerable/plan/EnumerableIntermediatePrelConverterRule.java
@@ -17,31 +17,45 @@
*/
package org.apache.drill.exec.store.enumerable.plan;
+import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelTrait;
import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.convert.ConverterRule;
import org.apache.drill.exec.planner.logical.DrillRel;
import org.apache.drill.exec.planner.logical.DrillRelFactories;
+import org.apache.drill.exec.planner.logical.RelOptHelper;
import org.apache.drill.exec.planner.physical.Prel;
-import java.util.function.Predicate;
-
-public class EnumerableIntermediatePrelConverterRule extends ConverterRule {
+public class EnumerableIntermediatePrelConverterRule extends RelOptRule {
private final EnumerablePrelContext context;
+ private final RelTrait inTrait;
+ private final RelTrait outTrait;
- public EnumerableIntermediatePrelConverterRule(EnumerablePrelContext
context) {
- super(VertexDrel.class, (Predicate<RelNode>) input -> true,
DrillRel.DRILL_LOGICAL,
- Prel.DRILL_PHYSICAL, DrillRelFactories.LOGICAL_BUILDER,
- "EnumerableIntermediatePrelConverterRule:" + context.getPlanPrefix());
+ public EnumerableIntermediatePrelConverterRule(EnumerablePrelContext
context, Convention convention) {
+ super(
+ RelOptHelper.some(VertexDrel.class, DrillRel.DRILL_LOGICAL,
+ RelOptHelper.any(RelNode.class, convention)),
+ DrillRelFactories.LOGICAL_BUILDER,
"EnumerableIntermediatePrelConverterRule" + convention);
this.context = context;
+ this.inTrait = DrillRel.DRILL_LOGICAL;
+ this.outTrait = Prel.DRILL_PHYSICAL;
}
@Override
- public RelNode convert(RelNode in) {
- return new EnumerableIntermediatePrel(
+ public void onMatch(RelOptRuleCall call) {
+ VertexDrel in = call.rel(0);
+ RelNode intermediatePrel = new EnumerableIntermediatePrel(
in.getCluster(),
- in.getTraitSet().replace(getOutTrait()),
+ in.getTraitSet().replace(outTrait),
in.getInput(0),
context);
+ call.transformTo(intermediatePrel);
+ }
+
+ @Override
+ public boolean matches(RelOptRuleCall call) {
+ return super.matches(call) && call.rel(0).getTraitSet().contains(inTrait);
}
}
diff --git
a/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/EnumPluginTest.java
b/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/EnumPluginTest.java
new file mode 100644
index 0000000..2f090b0
--- /dev/null
+++
b/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/EnumPluginTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.drill.exec.store.enumerable;
+
+import org.apache.drill.exec.store.enumerable.plan.EnumMockPlugin;
+import org.apache.drill.test.ClusterFixture;
+import org.apache.drill.test.ClusterTest;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class EnumPluginTest extends ClusterTest {
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ startCluster(ClusterFixture.builder(dirTestWatcher));
+
+ EnumMockPlugin.EnumMockStoragePluginConfig config = new
EnumMockPlugin.EnumMockStoragePluginConfig();
+ config.setEnabled(true);
+ cluster.defineStoragePlugin("mocked_enum", config);
+ cluster.defineStoragePlugin("mocked_enum2", config);
+ }
+
+ @Test // DRILL-7972
+ public void testIntermConvRuleConvention() throws Exception {
+ queryBuilder()
+ .sql("select t1.a, t2.a from mocked_enum.mock_enum_table t1 " +
+ "join mocked_enum2.mock_enum_table t2 on t1.a=t2.a")
+ .planMatcher()
+ .include("mocked_enum", "mocked_enum2")
+ .match();
+ }
+}
diff --git
a/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/plan/EnumMockPlugin.java
b/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/plan/EnumMockPlugin.java
new file mode 100644
index 0000000..e2e65f4
--- /dev/null
+++
b/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/plan/EnumMockPlugin.java
@@ -0,0 +1,112 @@
+/*
+ * 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.drill.exec.store.enumerable.plan;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.drill.common.logical.StoragePluginConfig;
+import org.apache.drill.exec.ops.OptimizerRulesContext;
+import org.apache.drill.exec.planner.PlannerPhase;
+import org.apache.drill.exec.server.DrillbitContext;
+import org.apache.drill.exec.store.AbstractStoragePlugin;
+import org.apache.drill.exec.store.SchemaConfig;
+import org.apache.drill.exec.store.SchemaFactory;
+import org.apache.drill.shaded.guava.com.google.common.collect.ImmutableSet;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Mock plugin implementation for testing "enumerable" rel nodes
transformation.
+ */
+public class EnumMockPlugin extends AbstractStoragePlugin {
+
+ private final SchemaFactory schemaFactory;
+
+ private final EnumMockStoragePluginConfig config;
+
+ private final Convention convention;
+
+ public EnumMockPlugin(EnumMockStoragePluginConfig config, DrillbitContext
inContext, String inName) {
+ super(inContext, inName);
+ this.config = config;
+ EnumMockSchema schema = new EnumMockSchema(inName, this);
+ this.schemaFactory = (SchemaConfig schemaConfig, SchemaPlus parent) ->
parent.add(inName, schema);
+ this.convention = new Convention.Impl(inName, EnumMockRel.class);
+ }
+
+ @Override
+ public void registerSchemas(SchemaConfig schemaConfig, SchemaPlus parent)
throws IOException {
+ schemaFactory.registerSchemas(schemaConfig, parent);
+ }
+
+ @Override
+ public boolean supportsRead() {
+ return true;
+ }
+
+ @Override
+ public StoragePluginConfig getConfig() {
+ return config;
+ }
+
+ @Override
+ public Set<? extends RelOptRule> getOptimizerRules(OptimizerRulesContext
optimizerContext, PlannerPhase phase) {
+ switch (phase) {
+ case PHYSICAL:
+ case LOGICAL:
+ return ImmutableSet.of(
+ new EnumerableIntermediatePrelConverterRule(
+ new EnumMockRel.MockEnumerablePrelContext(convention),
convention),
+ new VertexDrelConverterRule(convention));
+ case LOGICAL_PRUNE_AND_JOIN:
+ case LOGICAL_PRUNE:
+ case PARTITION_PRUNING:
+ case JOIN_PLANNING:
+ default:
+ return Collections.emptySet();
+ }
+ }
+
+ public Convention getConvention() {
+ return convention;
+ }
+
+ @JsonTypeName(EnumMockStoragePluginConfig.NAME)
+ public static class EnumMockStoragePluginConfig extends StoragePluginConfig {
+ public static final String NAME = "enum_mock";
+
+ @JsonCreator
+ public EnumMockStoragePluginConfig() {
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof EnumMockStoragePluginConfig;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+ }
+}
diff --git
a/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/plan/EnumMockRel.java
b/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/plan/EnumMockRel.java
new file mode 100644
index 0000000..6faf7a5
--- /dev/null
+++
b/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/plan/EnumMockRel.java
@@ -0,0 +1,86 @@
+/*
+ * 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.drill.exec.store.enumerable.plan;
+
+import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.TableScan;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public interface EnumMockRel extends RelNode {
+
+ class MockEnumerablePrelContext implements EnumerablePrelContext {
+
+ private final Convention convention;
+
+ public MockEnumerablePrelContext(Convention convention) {
+ this.convention = convention;
+ }
+
+ @Override
+ public String generateCode(RelOptCluster cluster, RelNode relNode) {
+ return null;
+ }
+
+ @Override
+ public RelNode transformNode(RelNode input) {
+ assert input.getTraitSet().getTrait(0).equals(convention) : "Conventions
should match";
+ return input;
+ }
+
+ @Override
+ public Map<String, Integer> getFieldsMap(RelNode transformedNode) {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public String getPlanPrefix() {
+ return "mock_prel";
+ }
+
+ @Override
+ public String getTablePath(RelNode input) {
+ return null;
+ }
+ }
+
+ class EnumMockTableScan extends TableScan implements EnumMockRel {
+
+ protected EnumMockTableScan(RelOptCluster cluster, RelTraitSet traitSet,
RelOptTable table) {
+ super(cluster, traitSet, table);
+ }
+
+ @Override
+ public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
+ assert inputs.isEmpty();
+ return new EnumMockTableScan(getCluster(), traitSet, table);
+ }
+
+ @Override
+ public double estimateRowCount(RelMetadataQuery mq) {
+ return 5;
+ }
+ }
+}
diff --git
a/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/plan/EnumMockSchema.java
b/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/plan/EnumMockSchema.java
new file mode 100644
index 0000000..c10f79f
--- /dev/null
+++
b/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/plan/EnumMockSchema.java
@@ -0,0 +1,53 @@
+/*
+ * 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.drill.exec.store.enumerable.plan;
+
+import org.apache.calcite.schema.Table;
+import org.apache.drill.exec.store.AbstractSchema;
+import org.apache.drill.exec.store.StoragePlugin;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class EnumMockSchema extends AbstractSchema {
+ private final StoragePlugin plugin;
+ private final Map<String, EnumMockTable> tables;
+
+ public EnumMockSchema(String name, StoragePlugin plugin) {
+ super(Collections.emptyList(), name);
+ this.plugin = plugin;
+ this.tables = new HashMap<>();
+ }
+
+ @Override
+ public String getTypeName() {
+ return EnumMockPlugin.EnumMockStoragePluginConfig.NAME;
+ }
+
+ @Override
+ public Table getTable(String name) {
+ return tables.computeIfAbsent(name, key -> new EnumMockTable(plugin, key,
null, null));
+ }
+
+ @Override
+ public Set<String> getTableNames() {
+ return Collections.singleton("mock_enum_table");
+ }
+}
diff --git
a/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/plan/EnumMockTable.java
b/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/plan/EnumMockTable.java
new file mode 100644
index 0000000..6628069
--- /dev/null
+++
b/exec/java-exec/src/test/java/org/apache/drill/exec/store/enumerable/plan/EnumMockTable.java
@@ -0,0 +1,38 @@
+/*
+ * 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.drill.exec.store.enumerable.plan;
+
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.schema.TranslatableTable;
+import org.apache.drill.exec.planner.logical.DynamicDrillTable;
+import org.apache.drill.exec.store.StoragePlugin;
+
+public class EnumMockTable extends DynamicDrillTable implements
TranslatableTable {
+
+ public EnumMockTable(StoragePlugin plugin, String storageEngineName, String
userName, Object selection) {
+ super(plugin, storageEngineName, userName, selection);
+ }
+
+ @Override
+ public RelNode toRel(RelOptTable.ToRelContext context, RelOptTable
relOptTable) {
+ EnumMockPlugin plugin = (EnumMockPlugin) getPlugin();
+ return new EnumMockRel.EnumMockTableScan(context.getCluster(),
+ context.getCluster().traitSetOf(plugin.getConvention()), relOptTable);
+ }
+}
diff --git a/exec/java-exec/src/test/resources/drill-module.conf
b/exec/java-exec/src/test/resources/drill-module.conf
index d1b5bb2..8a85334 100644
--- a/exec/java-exec/src/test/resources/drill-module.conf
+++ b/exec/java-exec/src/test/resources/drill-module.conf
@@ -27,6 +27,7 @@ drill: {
packages += "org.apache.drill.exec.store",
packages += "org.apache.drill.exec.testing",
packages += "org.apache.drill.exec.rpc.user.security.testing"
+ packages += "org.apache.drill.exec.store.enumerable.plan"
}
test.query.printing.silent : false,
exec: {