This is an automated email from the ASF dual-hosted git repository. morningman pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new 76e539dbda [Improvement](multi catalog)(nereids)Support JDBC external table for new planner. (#17063) 76e539dbda is described below commit 76e539dbdac0d4a7d9108e3138453595563c8315 Author: Jibing-Li <64681310+jibing...@users.noreply.github.com> AuthorDate: Tue Feb 28 09:43:04 2023 +0800 [Improvement](multi catalog)(nereids)Support JDBC external table for new planner. (#17063) Support JDBC external table for Nereids planner. JDBC table is another type of table, like olap table, hms table and so on. --- .../apache/doris/nereids/cost/CostCalculator.java | 7 + .../glue/translator/PhysicalPlanTranslator.java | 23 +++ .../properties/ChildOutputPropertyDeriver.java | 6 + .../org/apache/doris/nereids/rules/RuleSet.java | 2 + .../org/apache/doris/nereids/rules/RuleType.java | 1 + .../doris/nereids/rules/analysis/BindRelation.java | 10 +- .../LogicalJdbcScanToPhysicalJdbcScan.java | 43 +++++ .../doris/nereids/stats/StatsCalculator.java | 13 ++ .../apache/doris/nereids/trees/plans/PlanType.java | 2 + .../trees/plans/logical/LogicalJdbcScan.java | 83 ++++++++++ .../trees/plans/physical/PhysicalJdbcScan.java | 119 ++++++++++++++ .../nereids/trees/plans/visitor/PlanVisitor.java | 10 ++ .../org/apache/doris/planner/JdbcScanNode.java | 22 ++- .../test_mysql_jdbc_catalog_nereids.out | 177 +++++++++++++++++++++ .../test_mysql_jdbc_catalog_nereids.groovy | 141 ++++++++++++++++ 15 files changed, 652 insertions(+), 7 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/CostCalculator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/CostCalculator.java index b0ac15b93f..eb2460122f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/CostCalculator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/CostCalculator.java @@ -31,6 +31,7 @@ import org.apache.doris.nereids.trees.plans.physical.PhysicalFileScan; import org.apache.doris.nereids.trees.plans.physical.PhysicalGenerate; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashAggregate; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin; +import org.apache.doris.nereids.trees.plans.physical.PhysicalJdbcScan; import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan; import org.apache.doris.nereids.trees.plans.physical.PhysicalProject; @@ -134,6 +135,12 @@ public class CostCalculator { return CostEstimate.ofCpu(1); } + @Override + public CostEstimate visitPhysicalJdbcScan(PhysicalJdbcScan physicalJdbcScan, PlanContext context) { + StatsDeriveResult statistics = context.getStatisticsWithCheck(); + return CostEstimate.ofCpu(statistics.getRowCount()); + } + @Override public CostEstimate visitPhysicalQuickSort( PhysicalQuickSort<? extends Plan> physicalQuickSort, PlanContext context) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java index 2ef9bb171a..26fa010312 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java @@ -86,6 +86,7 @@ import org.apache.doris.nereids.trees.plans.physical.PhysicalGenerate; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashAggregate; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalIntersect; +import org.apache.doris.nereids.trees.plans.physical.PhysicalJdbcScan; import org.apache.doris.nereids.trees.plans.physical.PhysicalLimit; import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan; @@ -117,6 +118,7 @@ import org.apache.doris.planner.ExchangeNode; import org.apache.doris.planner.HashJoinNode; import org.apache.doris.planner.HashJoinNode.DistributionMode; import org.apache.doris.planner.IntersectNode; +import org.apache.doris.planner.JdbcScanNode; import org.apache.doris.planner.JoinNodeBase; import org.apache.doris.planner.NestedLoopJoinNode; import org.apache.doris.planner.OlapScanNode; @@ -600,6 +602,27 @@ public class PhysicalPlanTranslator extends DefaultPlanVisitor<PlanFragment, Pla return planFragment; } + @Override + public PlanFragment visitPhysicalJdbcScan(PhysicalJdbcScan jdbcScan, PlanTranslatorContext context) { + List<Slot> slotList = jdbcScan.getOutput(); + ExternalTable table = jdbcScan.getTable(); + TupleDescriptor tupleDescriptor = generateTupleDesc(slotList, table, context); + tupleDescriptor.setTable(table); + JdbcScanNode jdbcScanNode = new JdbcScanNode(context.nextPlanNodeId(), tupleDescriptor, true); + Utils.execWithUncheckedException(jdbcScanNode::init); + context.addScanNode(jdbcScanNode); + context.getRuntimeTranslator().ifPresent( + runtimeFilterGenerator -> runtimeFilterGenerator.getTargetOnScanNode(jdbcScan.getId()).forEach( + expr -> runtimeFilterGenerator.translateRuntimeFilterTarget(expr, jdbcScanNode, context) + ) + ); + Utils.execWithUncheckedException(jdbcScanNode::finalizeForNerieds); + DataPartition dataPartition = DataPartition.RANDOM; + PlanFragment planFragment = new PlanFragment(context.nextFragmentId(), jdbcScanNode, dataPartition); + context.addPlanFragment(planFragment); + return planFragment; + } + /*- * Physical sort: * 1. Build sortInfo diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriver.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriver.java index 35c6261e99..5783b366ae 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriver.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriver.java @@ -33,6 +33,7 @@ import org.apache.doris.nereids.trees.plans.physical.PhysicalFilter; import org.apache.doris.nereids.trees.plans.physical.PhysicalGenerate; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashAggregate; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin; +import org.apache.doris.nereids.trees.plans.physical.PhysicalJdbcScan; import org.apache.doris.nereids.trees.plans.physical.PhysicalLimit; import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan; @@ -240,6 +241,11 @@ public class ChildOutputPropertyDeriver extends PlanVisitor<PhysicalProperties, return storageLayerAggregate.getRelation().accept(this, context); } + @Override + public PhysicalProperties visitPhysicalJdbcScan(PhysicalJdbcScan jdbcScan, PlanContext context) { + return PhysicalProperties.ANY; + } + @Override public PhysicalProperties visitPhysicalTVFRelation(PhysicalTVFRelation tvfRelation, PlanContext context) { TableValuedFunction function = tvfRelation.getFunction(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java index 01884bbf23..96d4aa03a3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java @@ -34,6 +34,7 @@ import org.apache.doris.nereids.rules.implementation.LogicalFileScanToPhysicalFi import org.apache.doris.nereids.rules.implementation.LogicalFilterToPhysicalFilter; import org.apache.doris.nereids.rules.implementation.LogicalGenerateToPhysicalGenerate; import org.apache.doris.nereids.rules.implementation.LogicalIntersectToPhysicalIntersect; +import org.apache.doris.nereids.rules.implementation.LogicalJdbcScanToPhysicalJdbcScan; import org.apache.doris.nereids.rules.implementation.LogicalJoinToHashJoin; import org.apache.doris.nereids.rules.implementation.LogicalJoinToNestedLoopJoin; import org.apache.doris.nereids.rules.implementation.LogicalLimitToPhysicalLimit; @@ -117,6 +118,7 @@ public class RuleSet { .add(new LogicalOlapScanToPhysicalOlapScan()) .add(new LogicalSchemaScanToPhysicalSchemaScan()) .add(new LogicalFileScanToPhysicalFileScan()) + .add(new LogicalJdbcScanToPhysicalJdbcScan()) .add(new LogicalProjectToPhysicalProject()) .add(new LogicalLimitToPhysicalLimit()) .add(new LogicalWindowToPhysicalWindow()) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java index f69413309d..5409ea0799 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java @@ -243,6 +243,7 @@ public enum RuleType { LOGICAL_OLAP_SCAN_TO_PHYSICAL_OLAP_SCAN_RULE(RuleTypeClass.IMPLEMENTATION), LOGICAL_SCHEMA_SCAN_TO_PHYSICAL_SCHEMA_SCAN_RULE(RuleTypeClass.IMPLEMENTATION), LOGICAL_FILE_SCAN_TO_PHYSICAL_FILE_SCAN_RULE(RuleTypeClass.IMPLEMENTATION), + LOGICAL_JDBC_SCAN_TO_PHYSICAL_JDBC_SCAN_RULE(RuleTypeClass.IMPLEMENTATION), LOGICAL_ASSERT_NUM_ROWS_TO_PHYSICAL_ASSERT_NUM_ROWS(RuleTypeClass.IMPLEMENTATION), STORAGE_LAYER_AGGREGATE_WITHOUT_PROJECT(RuleTypeClass.IMPLEMENTATION), STORAGE_LAYER_AGGREGATE_WITH_PROJECT(RuleTypeClass.IMPLEMENTATION), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java index 9011b80f08..8ba0997572 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java @@ -22,9 +22,9 @@ import org.apache.doris.catalog.DatabaseIf; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.OlapTable; import org.apache.doris.catalog.Partition; -import org.apache.doris.catalog.Table; import org.apache.doris.catalog.TableIf; import org.apache.doris.catalog.View; +import org.apache.doris.catalog.external.ExternalTable; import org.apache.doris.catalog.external.HMSExternalTable; import org.apache.doris.common.util.Util; import org.apache.doris.datasource.CatalogIf; @@ -43,6 +43,7 @@ import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalFileScan; import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; +import org.apache.doris.nereids.trees.plans.logical.LogicalJdbcScan; import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan; import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; import org.apache.doris.nereids.trees.plans.logical.LogicalSchemaScan; @@ -194,10 +195,13 @@ public class BindRelation extends OneAnalysisRuleFactory { Plan viewPlan = parseAndAnalyzeView(((View) table).getDdlSql(), cascadesContext); return new LogicalSubQueryAlias<>(tableQualifier, viewPlan); case HMS_EXTERNAL_TABLE: - return new LogicalFileScan(cascadesContext.getStatementContext().getNextRelationId(), + return new LogicalFileScan(RelationUtil.newRelationId(), (HMSExternalTable) table, ImmutableList.of(dbName)); case SCHEMA: - return new LogicalSchemaScan(RelationUtil.newRelationId(), (Table) table, ImmutableList.of(dbName)); + return new LogicalSchemaScan(RelationUtil.newRelationId(), table, ImmutableList.of(dbName)); + case JDBC_EXTERNAL_TABLE: + return new LogicalJdbcScan(RelationUtil.newRelationId(), + (ExternalTable) table, ImmutableList.of(dbName)); default: throw new AnalysisException("Unsupported tableType:" + table.getType()); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJdbcScanToPhysicalJdbcScan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJdbcScanToPhysicalJdbcScan.java new file mode 100644 index 0000000000..3bff1699ba --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJdbcScanToPhysicalJdbcScan.java @@ -0,0 +1,43 @@ +// 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.doris.nereids.rules.implementation; + +import org.apache.doris.nereids.properties.DistributionSpecAny; +import org.apache.doris.nereids.rules.Rule; +import org.apache.doris.nereids.rules.RuleType; +import org.apache.doris.nereids.trees.plans.physical.PhysicalJdbcScan; + +import java.util.Optional; + +/** + * Implementation rule that convert logical JdbcScan to physical JdbcScan. + */ +public class LogicalJdbcScanToPhysicalJdbcScan extends OneImplementationRuleFactory { + @Override + public Rule build() { + return logicalJdbcScan().then(jdbcScan -> + new PhysicalJdbcScan( + jdbcScan.getId(), + jdbcScan.getTable(), + jdbcScan.getQualifier(), + DistributionSpecAny.INSTANCE, + Optional.empty(), + jdbcScan.getLogicalProperties()) + ).toRule(RuleType.LOGICAL_JDBC_SCAN_TO_PHYSICAL_JDBC_SCAN_RULE); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java index 214c8a97bd..de3c719513 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java @@ -47,6 +47,7 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalFileScan; import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; import org.apache.doris.nereids.trees.plans.logical.LogicalGenerate; import org.apache.doris.nereids.trees.plans.logical.LogicalIntersect; +import org.apache.doris.nereids.trees.plans.logical.LogicalJdbcScan; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; import org.apache.doris.nereids.trees.plans.logical.LogicalLimit; import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan; @@ -69,6 +70,7 @@ import org.apache.doris.nereids.trees.plans.physical.PhysicalGenerate; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashAggregate; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalIntersect; +import org.apache.doris.nereids.trees.plans.physical.PhysicalJdbcScan; import org.apache.doris.nereids.trees.plans.physical.PhysicalLimit; import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan; @@ -185,6 +187,12 @@ public class StatsCalculator extends DefaultPlanVisitor<StatsDeriveResult, Void> return tvfRelation.getFunction().computeStats(tvfRelation.getOutput()); } + @Override + public StatsDeriveResult visitLogicalJdbcScan(LogicalJdbcScan jdbcScan, Void context) { + jdbcScan.getExpressions(); + return computeScan(jdbcScan); + } + @Override public StatsDeriveResult visitLogicalProject(LogicalProject<? extends Plan> project, Void context) { return computeProject(project); @@ -290,6 +298,11 @@ public class StatsCalculator extends DefaultPlanVisitor<StatsDeriveResult, Void> return tvfRelation.getFunction().computeStats(tvfRelation.getOutput()); } + @Override + public StatsDeriveResult visitPhysicalJdbcScan(PhysicalJdbcScan jdbcScan, Void context) { + return computeScan(jdbcScan); + } + @Override public StatsDeriveResult visitPhysicalQuickSort(PhysicalQuickSort<? extends Plan> sort, Void context) { return groupExpression.childStatistics(0); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java index c8e1a2222e..5afe8b4cf6 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java @@ -45,6 +45,7 @@ public enum PlanType { LOGICAL_OLAP_SCAN, LOGICAL_SCHEMA_SCAN, LOGICAL_FILE_SCAN, + LOGICAL_JDBC_SCAN, LOGICAL_APPLY, LOGICAL_SELECT_HINT, LOGICAL_ASSERT_NUM_ROWS, @@ -63,6 +64,7 @@ public enum PlanType { PHYSICAL_ONE_ROW_RELATION, PHYSICAL_OLAP_SCAN, PHYSICAL_FILE_SCAN, + PHYSICAL_JDBC_SCAN, PHYSICAL_TVF_RELATION, PHYSICAL_SCHEMA_SCAN, PHYSICAL_PROJECT, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJdbcScan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJdbcScan.java new file mode 100644 index 0000000000..386baea1f3 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJdbcScan.java @@ -0,0 +1,83 @@ +// 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.doris.nereids.trees.plans.logical; + +import org.apache.doris.catalog.external.ExternalTable; +import org.apache.doris.nereids.memo.GroupExpression; +import org.apache.doris.nereids.properties.LogicalProperties; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.RelationId; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +import org.apache.doris.nereids.util.Utils; + +import com.google.common.base.Preconditions; + +import java.util.List; +import java.util.Optional; + +/** + * Logical scan for external jdbc catalog. + */ +public class LogicalJdbcScan extends LogicalRelation { + + /** + * Constructor for LogicalJdbcScan. + */ + public LogicalJdbcScan(RelationId id, ExternalTable table, List<String> qualifier, + Optional<GroupExpression> groupExpression, + Optional<LogicalProperties> logicalProperties) { + super(id, PlanType.LOGICAL_JDBC_SCAN, table, qualifier, + groupExpression, logicalProperties); + } + + public LogicalJdbcScan(RelationId id, ExternalTable table, List<String> qualifier) { + this(id, table, qualifier, Optional.empty(), Optional.empty()); + } + + @Override + public ExternalTable getTable() { + Preconditions.checkArgument(table instanceof ExternalTable); + return (ExternalTable) table; + } + + @Override + public String toString() { + return Utils.toSqlString("LogicalJdbcScan", + "qualified", qualifiedName(), + "output", getOutput() + ); + } + + @Override + public LogicalJdbcScan withGroupExpression(Optional<GroupExpression> groupExpression) { + return new LogicalJdbcScan(id, (ExternalTable) table, qualifier, groupExpression, + Optional.of(getLogicalProperties())); + } + + @Override + public LogicalJdbcScan withLogicalProperties(Optional<LogicalProperties> logicalProperties) { + return new LogicalJdbcScan(id, (ExternalTable) table, qualifier, groupExpression, + logicalProperties); + } + + @Override + public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { + return visitor.visitLogicalJdbcScan(this, context); + } + +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalJdbcScan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalJdbcScan.java new file mode 100644 index 0000000000..237f33a18e --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalJdbcScan.java @@ -0,0 +1,119 @@ +// 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.doris.nereids.trees.plans.physical; + +import org.apache.doris.catalog.external.ExternalTable; +import org.apache.doris.nereids.memo.GroupExpression; +import org.apache.doris.nereids.properties.DistributionSpec; +import org.apache.doris.nereids.properties.LogicalProperties; +import org.apache.doris.nereids.properties.PhysicalProperties; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.RelationId; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +import org.apache.doris.nereids.util.Utils; +import org.apache.doris.statistics.StatsDeriveResult; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * Physical jdbc scan for external catalog. + */ +public class PhysicalJdbcScan extends PhysicalRelation { + + private final ExternalTable table; + private final DistributionSpec distributionSpec; + + /** + * Constructor for PhysicalJdbcScan. + */ + public PhysicalJdbcScan(RelationId id, ExternalTable table, List<String> qualifier, + DistributionSpec distributionSpec, Optional<GroupExpression> groupExpression, + LogicalProperties logicalProperties) { + super(id, PlanType.PHYSICAL_JDBC_SCAN, qualifier, groupExpression, logicalProperties); + this.table = table; + this.distributionSpec = distributionSpec; + } + + /** + * Constructor for PhysicalJdbcScan. + */ + public PhysicalJdbcScan(RelationId id, ExternalTable table, List<String> qualifier, + DistributionSpec distributionSpec, Optional<GroupExpression> groupExpression, + LogicalProperties logicalProperties, PhysicalProperties physicalProperties, + StatsDeriveResult statsDeriveResult) { + super(id, PlanType.PHYSICAL_JDBC_SCAN, qualifier, groupExpression, logicalProperties, + physicalProperties, statsDeriveResult); + this.table = table; + this.distributionSpec = distributionSpec; + } + + @Override + public String toString() { + return Utils.toSqlString("PhysicalJdbcScan", + "qualified", Utils.qualifiedName(qualifier, table.getName()), + "output", getOutput(), + "stats", statsDeriveResult + ); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass() || !super.equals(o)) { + return false; + } + PhysicalJdbcScan that = ((PhysicalJdbcScan) o); + return Objects.equals(table, that.table); + } + + @Override + public int hashCode() { + return Objects.hash(id, table); + } + + @Override + public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { + return visitor.visitPhysicalJdbcScan(this, context); + } + + @Override + public PhysicalJdbcScan withGroupExpression(Optional<GroupExpression> groupExpression) { + return new PhysicalJdbcScan(id, table, qualifier, distributionSpec, groupExpression, getLogicalProperties()); + } + + @Override + public PhysicalJdbcScan withLogicalProperties(Optional<LogicalProperties> logicalProperties) { + return new PhysicalJdbcScan(id, table, qualifier, distributionSpec, groupExpression, logicalProperties.get()); + } + + @Override + public ExternalTable getTable() { + return table; + } + + @Override + public PhysicalJdbcScan withPhysicalPropertiesAndStats(PhysicalProperties physicalProperties, + StatsDeriveResult statsDeriveResult) { + return new PhysicalJdbcScan(id, table, qualifier, distributionSpec, groupExpression, getLogicalProperties(), + physicalProperties, statsDeriveResult); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java index cd09c69df5..6faee87943 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java @@ -37,6 +37,7 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; import org.apache.doris.nereids.trees.plans.logical.LogicalGenerate; import org.apache.doris.nereids.trees.plans.logical.LogicalHaving; import org.apache.doris.nereids.trees.plans.logical.LogicalIntersect; +import org.apache.doris.nereids.trees.plans.logical.LogicalJdbcScan; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; import org.apache.doris.nereids.trees.plans.logical.LogicalLimit; import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan; @@ -65,6 +66,7 @@ import org.apache.doris.nereids.trees.plans.physical.PhysicalGenerate; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashAggregate; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalIntersect; +import org.apache.doris.nereids.trees.plans.physical.PhysicalJdbcScan; import org.apache.doris.nereids.trees.plans.physical.PhysicalLimit; import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan; @@ -179,6 +181,10 @@ public abstract class PlanVisitor<R, C> { return visitLogicalRelation(tvfRelation, context); } + public R visitLogicalJdbcScan(LogicalJdbcScan jdbcScan, C context) { + return visitLogicalRelation(jdbcScan, context); + } + public R visitLogicalProject(LogicalProject<? extends Plan> project, C context) { return visit(project, context); } @@ -276,6 +282,10 @@ public abstract class PlanVisitor<R, C> { return visitPhysicalScan(fileScan, context); } + public R visitPhysicalJdbcScan(PhysicalJdbcScan jdbcScan, C context) { + return visitPhysicalScan(jdbcScan, context); + } + public R visitPhysicalStorageLayerAggregate(PhysicalStorageLayerAggregate storageLayerAggregate, C context) { return storageLayerAggregate.getRelation().accept(this, context); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/JdbcScanNode.java b/fe/fe-core/src/main/java/org/apache/doris/planner/JdbcScanNode.java index 8f3c89ebd5..51d4534731 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/JdbcScanNode.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/JdbcScanNode.java @@ -73,12 +73,21 @@ public class JdbcScanNode extends ScanNode { computeStats(analyzer); } + /** + * Used for Nereids. Should NOT use this function in anywhere else. + */ + public void init() throws UserException { + numNodes = numNodes <= 0 ? 1 : numNodes; + StatsRecursiveDerive.getStatsRecursiveDerive().statsRecursiveDerive(this); + cardinality = (long) statsDeriveResult.getRowCount(); + } + @Override public List<TScanRangeLocations> getScanRangeLocations(long maxScanRangeLength) { return null; } - private void createJdbcFilters(Analyzer analyzer) { + private void createJdbcFilters() { if (conjuncts.isEmpty()) { return; } @@ -103,7 +112,7 @@ public class JdbcScanNode extends ScanNode { } } - private void createJdbcColumns(Analyzer analyzer) { + private void createJdbcColumns() { for (SlotDescriptor slot : desc.getSlots()) { if (!slot.isMaterialized()) { continue; @@ -168,8 +177,13 @@ public class JdbcScanNode extends ScanNode { @Override public void finalize(Analyzer analyzer) throws UserException { // Convert predicates to Jdbc columns and filters. - createJdbcColumns(analyzer); - createJdbcFilters(analyzer); + createJdbcColumns(); + createJdbcFilters(); + } + + public void finalizeForNerieds() throws UserException { + createJdbcColumns(); + createJdbcFilters(); } @Override diff --git a/regression-test/data/jdbc_catalog_p0/test_mysql_jdbc_catalog_nereids.out b/regression-test/data/jdbc_catalog_p0/test_mysql_jdbc_catalog_nereids.out new file mode 100644 index 0000000000..7b1a18c3a9 --- /dev/null +++ b/regression-test/data/jdbc_catalog_p0/test_mysql_jdbc_catalog_nereids.out @@ -0,0 +1,177 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !ex_tb0 -- +111 abc +112 abd +113 abe +114 abf +115 abg + +-- !in_tb -- +111 abc +112 abd +113 abe +114 abf +115 abg + +-- !ex_tb1 -- +{"k1":"v1", "k2":"v2"} + +-- !ex_tb2 -- +123 10 +123 15 +123 20 + +-- !ex_tb3 -- +mus plat_code 1001169339 1590381433914 1590420872639 11 1006061 beijing +mus plat_code 1001169339 1590402594411 1590420872639 11 1006061 beijing +mus plat_code 1001169339 1590406790026 1590420872639 11 1006061 beijing +mus plat_code 1001169339 1590420482288 1590420872639 11 1006061 beijing +mus plat_code 1001169339 1590420872639 1590420872639 11 1006061 beijing + +-- !ex_tb4 -- +1 111 2021-09-01T07:01:01 2021-09-01T08:01:01 1 +2 112 2021-09-02T07:01:01 2021-09-02T08:01:01 1 +3 113 0000-01-01T00:00 2021-12-01T08:01:01 2 +5 115 2021-09-01T07:02:01 2021-09-01T08:01:04 4 +6 116 2021-10-01T07:03:01 2022-09-01T08:02:05 5 + +-- !ex_tb5 -- +1 test_apply_id 123321 zhangsan zhangsan ready ok 2 2022-01-01T02:03:04 + +-- !ex_tb6 -- +639215401565159424 1143681147589283841 test +639237839376089088 1143681147589283841 test123 + +-- !ex_tb7 -- +2 sim 1.000 +2 sim 1.001 +2 sim 1.002 + +-- !ex_tb8 -- +2022-07-15 2222 1 \N +2022-07-15 ddddd 2 0.5 + +-- !ex_tb9 -- +\N +2022-01-01 + +-- !ex_tb10 -- +a 1 2 +b 1 2 +c 1 2 +d 3 2 + +-- !ex_tb11 -- +a 1 +b 1 +c 1 + +-- !ex_tb12 -- +a 1 +b 1 +c 1 + +-- !ex_tb13 -- +张三0 11 1234567 123 321312 1999-02-13T00:00 中国 男 0 +张三1 11 12345678 123 321312 1999-02-13T00:00 中国 男 0 +张三2 11 12345671 123 321312 1999-02-13T00:00 中国 男 0 +张三3 11 12345673 123 321312 1999-02-13T00:00 中国 男 0 +张三4 11 123456711 123 321312 1999-02-13T00:00 中国 男 0 +张三5 11 1232134567 123 321312 1999-02-13T00:00 中国 男 0 +张三6 11 124314567 123 321312 1999-02-13T00:00 中国 男 0 +张三7 11 123445167 123 321312 1998-02-13T00:00 中国 男 0 + +-- !ex_tb14 -- +123 2022-11-02 2022-11-02 8011 oppo +abc 2022-11-02 2022-11-02 8011 agdtb +bca 2022-11-02 2022-11-02 8012 vivo + +-- !ex_tb15 -- +2022-11-04 2022-10-31 2022-11-04 62 5.4103451446E9 7.211386993606482E10 21 10 16 - - 2022-11-04T17:40:19 + +-- !ex_tb16 -- +1 a 0 4 3 6 8 +1 b 0 4 4 8 8 +1 c 0 9 9 5 4 +1 d 0 7 6 1 7 +1 e 0 7 5 6 3 +2 a 0 3 4 1 6 +2 b 0 1 5 4 5 +2 c 0 5 7 9 1 +2 d 0 4 4 8 4 +2 e 0 6 4 7 8 +3 a 0 7 9 4 8 +3 b 0 4 9 8 1 +3 d 0 2 7 1 5 +3 e 0 2 4 3 4 +4 a 0 5 7 4 1 +4 b 0 3 4 2 7 +4 c 0 3 9 3 7 +4 d 0 1 5 6 4 +5 a 0 1 2 2 1 +5 b 0 6 6 2 9 +5 c 0 8 5 7 6 +5 d 0 6 2 7 7 +5 e 0 5 7 9 2 +6 a 0 1 1 8 8 +6 b 0 3 9 1 6 +6 c 0 3 1 3 8 +6 d 0 1 2 4 7 +6 e 0 1 9 7 6 +7 a 0 1 1 3 8 +7 b 0 3 2 8 1 +7 c 0 3 7 7 1 +7 d 0 6 1 5 6 +7 e 0 6 1 3 7 +8 a 0 3 2 8 2 +8 b 0 4 9 4 9 +8 c 0 1 7 1 5 +8 e 0 4 4 5 4 +9 a 0 8 3 9 1 +9 b 0 2 1 4 2 +9 c 0 8 3 9 8 +9 d 0 6 6 5 3 +9 e 0 9 1 9 7 + +-- !ex_tb17 -- +1 6 1 1 2099.18 3 8 1554296.82 68781940.49 d 8 5 0 d a 7 9 +2 8 9 8 2900.42 1 6 97486621.73 59634489.39 c 3 2 0 a e 7 4 +3 5 7 3 6276.86 8 9 32758730.38 10260499.72 c 8 1 0 d c 9 2 +4 3 7 5 2449.00 6 3 91359059.28 64743145.92 e 7 8 0 b d 8 4 +5 6 4 5 9137.82 2 7 26526675.70 90098303.36 a 6 7 0 d e 4 1 +6 3 6 8 7601.25 4 9 49117098.47 46499188.80 c 3 3 0 c d 4 8 +7 3 2 8 5297.81 9 3 23753694.20 96930000.64 c 7 2 0 b e 1 5 +8 3 6 7 3683.85 5 7 26056250.91 1127755.43 b 7 6 0 d b 4 7 +9 3 9 1 4785.38 1 5 95199488.12 94869703.42 a 4 4 0 c d 2 4 + +-- !ex_tb18 -- +-128 255 -32768 65535 -8388608 16777215 -9223372036854775808 -2147483648 2147483647 4294967295 33.14 422113.141 2342.23 aa asdawdasdaasdasd aaa bbbbbbbb xaqwdqwdqwdqd asdas +1 1 1 1 1 1 1 1 1 1 3.14 13.141 2342.23 aa asdawdasdaasdasd aaa bbbbbbbb xaqwdqwdqwdqdwqwdqwdqd asdadwqdqwddqwdsadqwdas +127 255 32767 65535 8388607 16777215 9223372036854775807 -2147483648 2147483647 4294967295 33.14 422113.141 2342.23 aa asdawdasdaasdasd aaa bbbbbbbb xaqwdqwdqwdqd asdadwqdqwdsadqwdas + +-- !ex_tb19 -- +2022-11-27 07:09:51 2022 2022-11-27T07:09:51 2022-11-27T07:09:51 + +-- !ex_tb20 -- +1.12345 1.12345 1.12345 1.12345 1.12345 1.12345 +123456789012345678901234567890123.12345 12345678901234567890123456789012.12345 1234567890123456789012345678901234.12345 123456789012345678901234567890123.12345 123456789012345678901234567890123456789012345678901234567890.12345 123456789012345678901234567890123456789012345678901234567890.12345 + +-- !test_insert1 -- +doris1 18 + +-- !test_insert2 -- +doris2 19 +doris3 20 + +-- !test_insert3 -- +doris2 19 +doris2 19 +doris3 20 +doris3 20 + +-- !test_insert4 -- +1 abcHa1.12345 1.123450xkalowadawd 2022-10-01 3.14159 1 2 0 100000 1.2345678 24.000 07:09:51 2022 2022-11-27T07:09:51 2022-11-27T07:09:51 + +-- !ex_tb1 -- +{"k1":"v1", "k2":"v2"} + diff --git a/regression-test/suites/jdbc_catalog_p0/test_mysql_jdbc_catalog_nereids.groovy b/regression-test/suites/jdbc_catalog_p0/test_mysql_jdbc_catalog_nereids.groovy new file mode 100644 index 0000000000..f974d5171c --- /dev/null +++ b/regression-test/suites/jdbc_catalog_p0/test_mysql_jdbc_catalog_nereids.groovy @@ -0,0 +1,141 @@ +// 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. + +suite("test_mysql_jdbc_catalog_nereids", "p0") { + String enabled = context.config.otherConfigs.get("enableJdbcTest") + if (enabled != null && enabled.equalsIgnoreCase("true")) { + String resource_name = "jdbc_resource_catalog_mysql_nereids" + String catalog_name = "mysql_jdbc_catalog_nereids"; + String internal_db_name = "regression_test_jdbc_catalog_p0"; + String ex_db_name = "doris_test"; + String mysql_port = context.config.otherConfigs.get("mysql_57_port"); + String inDorisTable = "doris_in_tb_nereids"; + String ex_tb0 = "ex_tb0"; + String ex_tb1 = "ex_tb1"; + String ex_tb2 = "ex_tb2"; + String ex_tb3 = "ex_tb3"; + String ex_tb4 = "ex_tb4"; + String ex_tb5 = "ex_tb5"; + String ex_tb6 = "ex_tb6"; + String ex_tb7 = "ex_tb7"; + String ex_tb8 = "ex_tb8"; + String ex_tb9 = "ex_tb9"; + String ex_tb10 = "ex_tb10"; + String ex_tb11 = "ex_tb11"; + String ex_tb12 = "ex_tb12"; + String ex_tb13 = "ex_tb13"; + String ex_tb14 = "ex_tb14"; + String ex_tb15 = "ex_tb15"; + String ex_tb16 = "ex_tb16"; + String ex_tb17 = "ex_tb17"; + String ex_tb18 = "ex_tb18"; + String ex_tb19 = "ex_tb19"; + String ex_tb20 = "ex_tb20"; + String test_insert = "test_insert"; + String test_insert2 = "test_insert2"; + + sql """ADMIN SET FRONTEND CONFIG ("enable_decimal_conversion" = "true");""" + sql """drop catalog if exists ${catalog_name} """ + sql """ drop resource if exists ${resource_name} """ + + sql """set enable_nereids_planner=true;""" + sql """set enable_fallback_to_original_planner=false;""" + + sql """create resource if not exists ${resource_name} properties( + "type"="jdbc", + "user"="root", + "password"="123456", + "jdbc_url" = "jdbc:mysql://127.0.0.1:${mysql_port}/doris_test?useSSL=false", + "driver_url" = "https://doris-community-test-1308700295.cos.ap-hongkong.myqcloud.com/jdbc_driver/mysql-connector-java-8.0.25.jar", + "driver_class" = "com.mysql.cj.jdbc.Driver" + );""" + + sql """CREATE CATALOG ${catalog_name} WITH RESOURCE ${resource_name}""" + + + sql """ drop table if exists ${inDorisTable} """ + sql """ + CREATE TABLE ${inDorisTable} ( + `id` INT NULL COMMENT "主键id", + `name` string NULL COMMENT "名字" + ) DISTRIBUTED BY HASH(id) BUCKETS 10 + PROPERTIES("replication_num" = "1"); + """ + + sql """switch ${catalog_name}""" + sql """ use ${ex_db_name}""" + + order_qt_ex_tb0 """ select id, name from ${ex_tb0} order by id; """ + sql """ insert into internal.${internal_db_name}.${inDorisTable} select id, name from ${ex_tb0}; """ + order_qt_in_tb """ select id, name from internal.${internal_db_name}.${inDorisTable} order by id; """ + + order_qt_ex_tb1 """ select * from ${ex_tb1} order by id; """ + order_qt_ex_tb2 """ select * from ${ex_tb2} order by id; """ + order_qt_ex_tb3 """ select * from ${ex_tb3} order by game_code; """ + order_qt_ex_tb4 """ select * from ${ex_tb4} order by products_id; """ + order_qt_ex_tb5 """ select * from ${ex_tb5} order by id; """ + order_qt_ex_tb6 """ select * from ${ex_tb6} order by id; """ + order_qt_ex_tb7 """ select * from ${ex_tb7} order by id; """ + order_qt_ex_tb8 """ select * from ${ex_tb8} order by uid; """ + order_qt_ex_tb9 """ select * from ${ex_tb9} order by c_date; """ + order_qt_ex_tb10 """ select * from ${ex_tb10} order by aa; """ + order_qt_ex_tb11 """ select * from ${ex_tb11} order by aa; """ + order_qt_ex_tb12 """ select * from ${ex_tb12} order by cc; """ + order_qt_ex_tb13 """ select * from ${ex_tb13} order by name; """ + order_qt_ex_tb14 """ select * from ${ex_tb14} order by tid; """ + order_qt_ex_tb15 """ select * from ${ex_tb15} order by col1; """ + order_qt_ex_tb16 """ select * from ${ex_tb16} order by id; """ + order_qt_ex_tb17 """ select * from ${ex_tb17} order by id; """ + order_qt_ex_tb18 """ select * from ${ex_tb18} order by num_tinyint; """ + order_qt_ex_tb19 """ select * from ${ex_tb19} order by date_value; """ + order_qt_ex_tb20 """ select * from ${ex_tb20} order by decimal_normal; """ + + // test insert + String uuid1 = UUID.randomUUID().toString(); + sql """ insert into ${test_insert} values ('${uuid1}', 'doris1', 18) """ + order_qt_test_insert1 """ select name, age from ${test_insert} where id = '${uuid1}' order by age """ + + String uuid2 = UUID.randomUUID().toString(); + sql """ insert into ${test_insert} values ('${uuid2}', 'doris2', 19), ('${uuid2}', 'doris3', 20) """ + order_qt_test_insert2 """ select name, age from ${test_insert} where id = '${uuid2}' order by age """ + + sql """ insert into ${test_insert} select * from ${test_insert} where id = '${uuid2}' """ + order_qt_test_insert3 """ select name, age from ${test_insert} where id = '${uuid2}' order by age """ + + String uuid3 = UUID.randomUUID().toString(); + sql """ INSERT INTO ${test_insert2} VALUES + ('${uuid3}', true, 'abcHa1.12345', '1.123450xkalowadawd', '2022-10-01', 3.14159, 1, 2, 0, 100000, 1.2345678, 24.000, '07:09:51', '2022', '2022-11-27 07:09:51', '2022-11-27 07:09:51'); """ + order_qt_test_insert4 """ select k1,k2,k3,k4,k5,k6,k7,k8,k9,k10,k11,k12,k13,k14,k15 from ${test_insert2} where id = '${uuid3}' """ + + sql """ drop catalog if exists ${catalog_name} """ + sql """ drop resource if exists ${resource_name} """ + + // test old create-catalog syntax for compatibility + sql """ CREATE CATALOG ${catalog_name} PROPERTIES ( + "type"="jdbc", + "jdbc.user"="root", + "jdbc.password"="123456", + "jdbc.jdbc_url" = "jdbc:mysql://127.0.0.1:${mysql_port}/doris_test?useSSL=false", + "jdbc.driver_url" = "https://doris-community-test-1308700295.cos.ap-hongkong.myqcloud.com/jdbc_driver/mysql-connector-java-8.0.25.jar", + "jdbc.driver_class" = "com.mysql.cj.jdbc.Driver"); + """ + sql """ switch ${catalog_name} """ + sql """ use ${ex_db_name} """ + order_qt_ex_tb1 """ select * from ${ex_tb1} order by id; """ + sql """ drop catalog if exists ${catalog_name} """ + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org