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: {

Reply via email to