This is an automated email from the ASF dual-hosted git repository.
morrysnow 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 ffd70239875 [feature](nereids) Support to get partition related table
from mv and check the query operator (#28064)
ffd70239875 is described below
commit ffd70239875bdd954f140c9161bd6f61743d78ab
Author: seawinde <[email protected]>
AuthorDate: Wed Dec 6 19:15:21 2023 +0800
[feature](nereids) Support to get partition related table from mv and check
the query operator (#28064)
Function 1:
check the select query plan is contain the stmt as following or not
SELECT
[hint_statement, ...]
[ALL | DISTINCT | DISTINCTROW | ALL EXCEPT ( col_name1 [, col_name2,
col_name3, ...] )]
elect_expr [, select_expr ...]
[FROM table_references
PARTITION partition_list]
[TABLET tabletid_list]
[TABLESAMPLE sample_value [ROWS | PERCENT]
[REPEATABLE pos_seek]]
[WHERE where_condition]
[GROUP BY [GROUPING SETS | ROLLUP | CUBE] {col_name | expr | position}]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[INTO OUTFILE 'file_name']
if analyzedPlan contains the stmt as following
[PARTITION partition_list]
[TABLET tabletid_list] or
[TABLESAMPLE sample_value [ROWS | PERCENT]
[REPEATABLE pos_seek]]
this method will return true.
Function 2:
Get related base table info which materialized view plan column reference,
input param plan should be rewritten plan that sub query should be
eliminated
---
.../exploration/mv/MaterializedViewUtils.java | 335 +++++++++++++++++++++
.../exploration/mv/MaterializedViewUtilsTest.java | 274 +++++++++++++++++
.../doris/nereids/trees/plans/PlanVisitorTest.java | 18 ++
.../doris/nereids/util/ExpressionUtilsTest.java | 4 +-
4 files changed, 628 insertions(+), 3 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java
new file mode 100644
index 00000000000..48f4cb37fbe
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java
@@ -0,0 +1,335 @@
+// 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.exploration.mv;
+
+import org.apache.doris.catalog.Column;
+import org.apache.doris.catalog.OlapTable;
+import org.apache.doris.catalog.PartitionInfo;
+import org.apache.doris.catalog.PartitionType;
+import org.apache.doris.catalog.TableIf;
+import org.apache.doris.mtmv.BaseTableInfo;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.expressions.WindowExpression;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
+import org.apache.doris.nereids.trees.plans.logical.LogicalCatalogRelation;
+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.LogicalJoin;
+import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+import org.apache.doris.nereids.trees.plans.logical.LogicalRelation;
+import org.apache.doris.nereids.trees.plans.logical.LogicalResultSink;
+import org.apache.doris.nereids.trees.plans.logical.LogicalWindow;
+import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanVisitor;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * The common util for materialized view
+ */
+public class MaterializedViewUtils {
+
+ /**
+ * Get related base table info which materialized view plan column
reference,
+ * input param plan should be rewritten plan that sub query should be
eliminated
+ *
+ * @param materializedViewPlan this should be rewritten or analyzed plan,
should not be physical plan.
+ * @param column ref column name.
+ */
+ public static Optional<RelatedTableInfo> getRelatedTableInfo(String
column, Plan materializedViewPlan) {
+ List<Slot> outputExpressions = materializedViewPlan.getOutput();
+ Slot columnExpr = null;
+ // get column slot
+ for (Slot outputSlot : outputExpressions) {
+ if (outputSlot.getName().equals(column)) {
+ columnExpr = outputSlot;
+ break;
+ }
+ }
+ if (columnExpr == null) {
+ return Optional.empty();
+ }
+ if (!(columnExpr instanceof SlotReference)) {
+ return Optional.empty();
+ }
+ SlotReference columnSlot = (SlotReference) columnExpr;
+ if (!columnSlot.isColumnFromTable()) {
+ return Optional.empty();
+ }
+ // check sql pattern
+ IncrementCheckerContext context = new
IncrementCheckerContext(columnSlot);
+ materializedViewPlan.accept(MaterializedViewIncrementChecker.INSTANCE,
context);
+ if (context.getRelatedTable() == null
+ || context.getRelatedTableColumn() == null
+ || !context.isPctPossible()) {
+ return Optional.empty();
+ }
+ return Optional.of(new RelatedTableInfo(new
BaseTableInfo(context.getRelatedTable()),
+ context.isPctPossible(),
+ context.getRelatedTableColumn().getName()));
+ }
+
+ /**
+ * This method check the select query plan is contain the stmt as
following or not
+ * <p>
+ * SELECT
+ * [hint_statement, ...]
+ * [ALL | DISTINCT | DISTINCTROW | ALL EXCEPT ( col_name1 [, col_name2,
col_name3, ...] )]
+ * select_expr [, select_expr ...]
+ * [FROM table_references
+ * [PARTITION partition_list]
+ * [TABLET tabletid_list]
+ * [TABLESAMPLE sample_value [ROWS | PERCENT]
+ * [REPEATABLE pos_seek]]
+ * [WHERE where_condition]
+ * [GROUP BY [GROUPING SETS | ROLLUP | CUBE] {col_name | expr | position}]
+ * [HAVING where_condition]
+ * [ORDER BY {col_name | expr | position}
+ * [ASC | DESC], ...]
+ * [LIMIT {[offset,] row_count | row_count OFFSET offset}]
+ * [INTO OUTFILE 'file_name']
+ * <p>
+ * if analyzedPlan contains the stmt as following:
+ * [PARTITION partition_list]
+ * [TABLET tabletid_list] or
+ * [TABLESAMPLE sample_value [ROWS | PERCENT]
+ * * [REPEATABLE pos_seek]]
+ * this method will return true.
+ */
+ public static boolean containTableQueryOperator(Plan analyzedPlan) {
+ return analyzedPlan.accept(TableQueryOperatorChecker.INSTANCE, null);
+ }
+
+ private static final class TableQueryOperatorChecker extends
DefaultPlanVisitor<Boolean, Void> {
+ public static final TableQueryOperatorChecker INSTANCE = new
TableQueryOperatorChecker();
+
+ @Override
+ public Boolean visitLogicalRelation(LogicalRelation relation, Void
context) {
+ if (relation instanceof LogicalFileScan && ((LogicalFileScan)
relation).getTableSample().isPresent()) {
+ return true;
+ }
+ if (relation instanceof LogicalOlapScan) {
+ LogicalOlapScan logicalOlapScan = (LogicalOlapScan) relation;
+ if (logicalOlapScan.getTableSample().isPresent()) {
+ return true;
+ }
+ if (!logicalOlapScan.getSelectedTabletIds().isEmpty()) {
+ return true;
+ }
+ if
(!logicalOlapScan.getManuallySpecifiedPartitions().isEmpty()) {
+ return true;
+ }
+ }
+ return visit(relation, context);
+ }
+
+ @Override
+ public Boolean visit(Plan plan, Void context) {
+ for (Plan child : plan.children()) {
+ Boolean checkResult = child.accept(this, context);
+ if (checkResult) {
+ return checkResult;
+ }
+ }
+ return false;
+ }
+ }
+
+ private static final class MaterializedViewIncrementChecker extends
+ DefaultPlanVisitor<Void, IncrementCheckerContext> {
+
+ public static final MaterializedViewIncrementChecker INSTANCE = new
MaterializedViewIncrementChecker();
+
+ @Override
+ public Void visitLogicalProject(LogicalProject<? extends Plan>
project, IncrementCheckerContext context) {
+ return visit(project, context);
+ }
+
+ @Override
+ public Void visitLogicalFilter(LogicalFilter<? extends Plan> filter,
IncrementCheckerContext context) {
+ return visit(filter, context);
+ }
+
+ @Override
+ public Void visitLogicalJoin(LogicalJoin<? extends Plan, ? extends
Plan> join,
+ IncrementCheckerContext context) {
+ return visit(join, context);
+ }
+
+ @Override
+ public Void visitLogicalRelation(LogicalRelation relation,
IncrementCheckerContext context) {
+ if (!(relation instanceof LogicalCatalogRelation) ||
context.getRelatedTable() != null) {
+ return visit(relation, context);
+ }
+ LogicalCatalogRelation logicalCatalogRelation =
(LogicalCatalogRelation) relation;
+ TableIf table = logicalCatalogRelation.getTable();
+ if (!(table instanceof OlapTable)) {
+ return visit(relation, context);
+ }
+ OlapTable olapTable = (OlapTable) table;
+ PartitionInfo partitionInfo = olapTable.getPartitionInfo();
+ Set<Column> partitionColumnSet = new
HashSet<>(partitionInfo.getPartitionColumns());
+ if (PartitionType.UNPARTITIONED.equals(partitionInfo.getType())) {
+ return visit(relation, context);
+ }
+ Column mvReferenceColumn =
context.getMvPartitionColumn().getColumn().get();
+ if (partitionColumnSet.contains(mvReferenceColumn)) {
+ context.setRelatedTable(table);
+ context.setRelatedTableColumn(mvReferenceColumn);
+ }
+ return visit(relation, context);
+ }
+
+ @Override
+ public Void visitLogicalAggregate(LogicalAggregate<? extends Plan>
aggregate,
+ IncrementCheckerContext context) {
+ Set<Expression> groupByExprSet = new
HashSet<>(aggregate.getGroupByExpressions());
+ if (groupByExprSet.isEmpty()) {
+ return visit(aggregate, context);
+ }
+ Set<Column> originalGroupbyExprSet = new HashSet<>();
+ groupByExprSet.forEach(groupExpr -> {
+ if (groupExpr instanceof SlotReference &&
groupExpr.isColumnFromTable()) {
+ originalGroupbyExprSet.add(((SlotReference)
groupExpr).getColumn().get());
+ }
+ });
+ if
(!originalGroupbyExprSet.contains(context.getMvPartitionColumn().getColumn().get()))
{
+ context.setPctPossible(false);
+ }
+ return visit(aggregate, context);
+ }
+
+ @Override
+ public Void visitLogicalWindow(LogicalWindow<? extends Plan> window,
IncrementCheckerContext context) {
+ List<NamedExpression> windowExpressions =
window.getWindowExpressions();
+ if (windowExpressions.isEmpty()) {
+ return visit(window, context);
+ }
+ windowExpressions.forEach(expr -> checkWindowPartition(expr,
context));
+ return super.visitLogicalWindow(window, context);
+ }
+
+ @Override
+ public Void visit(Plan plan, IncrementCheckerContext context) {
+ if (!context.isPctPossible()) {
+ return null;
+ }
+ if (plan instanceof LogicalProject
+ || plan instanceof LogicalFilter
+ || plan instanceof LogicalJoin
+ || plan instanceof LogicalAggregate
+ || plan instanceof LogicalCatalogRelation
+ || plan instanceof LogicalResultSink
+ || plan instanceof LogicalWindow) {
+ return super.visit(plan, context);
+ }
+ context.setPctPossible(false);
+ return null;
+ }
+
+ private void checkWindowPartition(Expression expression,
IncrementCheckerContext context) {
+ expression.collectToList(expressionTreeNode -> expressionTreeNode
instanceof WindowExpression)
+ .forEach(windowObj -> {
+ WindowExpression windowExpression = (WindowExpression)
windowObj;
+ List<Expression> partitionKeys =
windowExpression.getPartitionKeys();
+ Set<Column> originalPartitionbyExprSet = new
HashSet<>();
+ partitionKeys.forEach(groupExpr -> {
+ if (groupExpr instanceof SlotReference &&
groupExpr.isColumnFromTable()) {
+
originalPartitionbyExprSet.add(((SlotReference) groupExpr).getColumn().get());
+ }
+ });
+ if
(!originalPartitionbyExprSet.contains(context.getMvPartitionColumn().getColumn().get()))
{
+ context.setPctPossible(false);
+ }
+ });
+ }
+ }
+
+ private static final class IncrementCheckerContext {
+ private final SlotReference mvPartitionColumn;
+ private boolean pctPossible = true;
+ private TableIf relatedTable;
+ private Column relatedTableColumn;
+
+ public IncrementCheckerContext(SlotReference mvPartitionColumn) {
+ this.mvPartitionColumn = mvPartitionColumn;
+ }
+
+ public SlotReference getMvPartitionColumn() {
+ return mvPartitionColumn;
+ }
+
+ public boolean isPctPossible() {
+ return pctPossible;
+ }
+
+ public void setPctPossible(boolean pctPossible) {
+ this.pctPossible = pctPossible;
+ }
+
+ public TableIf getRelatedTable() {
+ return relatedTable;
+ }
+
+ public void setRelatedTable(TableIf relatedTable) {
+ this.relatedTable = relatedTable;
+ }
+
+ public Column getRelatedTableColumn() {
+ return relatedTableColumn;
+ }
+
+ public void setRelatedTableColumn(Column relatedTableColumn) {
+ this.relatedTableColumn = relatedTableColumn;
+ }
+ }
+
+ /**
+ * The related table info that mv relate
+ */
+ public static final class RelatedTableInfo {
+ private BaseTableInfo tableInfo;
+ private boolean pctPossible;
+ private String column;
+
+ public RelatedTableInfo(BaseTableInfo tableInfo, boolean pctPossible,
String column) {
+ this.tableInfo = tableInfo;
+ this.pctPossible = pctPossible;
+ this.column = column;
+ }
+
+ public BaseTableInfo getTableInfo() {
+ return tableInfo;
+ }
+
+ public boolean isPctPossible() {
+ return pctPossible;
+ }
+
+ public String getColumn() {
+ return column;
+ }
+ }
+}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtilsTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtilsTest.java
new file mode 100644
index 00000000000..f6dba539962
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtilsTest.java
@@ -0,0 +1,274 @@
+// 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.exploration.mv;
+
+import org.apache.doris.catalog.Env;
+import org.apache.doris.catalog.TableIf;
+import org.apache.doris.mtmv.BaseTableInfo;
+import
org.apache.doris.nereids.rules.exploration.mv.MaterializedViewUtils.RelatedTableInfo;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.util.PlanChecker;
+import org.apache.doris.utframe.TestWithFeService;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Optional;
+
+/**
+ * Test for materialized view util
+ */
+public class MaterializedViewUtilsTest extends TestWithFeService {
+
+ @Override
+ protected void runBeforeAll() throws Exception {
+ createDatabase("mv_util_test");
+ useDatabase("mv_util_test");
+
+ createTable("CREATE TABLE IF NOT EXISTS lineitem (\n"
+ + " L_ORDERKEY INTEGER NOT NULL,\n"
+ + " L_PARTKEY INTEGER NOT NULL,\n"
+ + " L_SUPPKEY INTEGER NOT NULL,\n"
+ + " L_LINENUMBER INTEGER NOT NULL,\n"
+ + " L_QUANTITY DECIMALV3(15,2) NOT NULL,\n"
+ + " L_EXTENDEDPRICE DECIMALV3(15,2) NOT NULL,\n"
+ + " L_DISCOUNT DECIMALV3(15,2) NOT NULL,\n"
+ + " L_TAX DECIMALV3(15,2) NOT NULL,\n"
+ + " L_RETURNFLAG CHAR(1) NOT NULL,\n"
+ + " L_LINESTATUS CHAR(1) NOT NULL,\n"
+ + " L_SHIPDATE DATE NOT NULL,\n"
+ + " L_COMMITDATE DATE NOT NULL,\n"
+ + " L_RECEIPTDATE DATE NOT NULL,\n"
+ + " L_SHIPINSTRUCT CHAR(25) NOT NULL,\n"
+ + " L_SHIPMODE CHAR(10) NOT NULL,\n"
+ + " L_COMMENT VARCHAR(44) NOT NULL\n"
+ + ")\n"
+ + "DUPLICATE KEY(L_ORDERKEY, L_PARTKEY, L_SUPPKEY,
L_LINENUMBER)\n"
+ + "PARTITION BY RANGE(L_SHIPDATE) (PARTITION `day_1` VALUES
LESS THAN ('2017-02-01'))\n"
+ + "DISTRIBUTED BY HASH(L_ORDERKEY) BUCKETS 3\n"
+ + "PROPERTIES (\n"
+ + " \"replication_num\" = \"1\"\n"
+ + ")");
+ createTable("CREATE TABLE IF NOT EXISTS orders (\n"
+ + " O_ORDERKEY INTEGER NOT NULL,\n"
+ + " O_CUSTKEY INTEGER NOT NULL,\n"
+ + " O_ORDERSTATUS CHAR(1) NOT NULL,\n"
+ + " O_TOTALPRICE DECIMALV3(15,2) NOT NULL,\n"
+ + " O_ORDERDATE DATE NOT NULL,\n"
+ + " O_ORDERPRIORITY CHAR(15) NOT NULL, \n"
+ + " O_CLERK CHAR(15) NOT NULL, \n"
+ + " O_SHIPPRIORITY INTEGER NOT NULL,\n"
+ + " O_COMMENT VARCHAR(79) NOT NULL\n"
+ + ")\n"
+ + "DUPLICATE KEY(O_ORDERKEY, O_CUSTKEY)\n"
+ + "PARTITION BY RANGE(O_ORDERDATE) (PARTITION `day_2` VALUES
LESS THAN ('2017-03-01'))\n"
+ + "DISTRIBUTED BY HASH(O_ORDERKEY) BUCKETS 3\n"
+ + "PROPERTIES (\n"
+ + " \"replication_num\" = \"1\"\n"
+ + ")");
+ createTable("CREATE TABLE IF NOT EXISTS partsupp (\n"
+ + " PS_PARTKEY INTEGER NOT NULL,\n"
+ + " PS_SUPPKEY INTEGER NOT NULL,\n"
+ + " PS_AVAILQTY INTEGER NOT NULL,\n"
+ + " PS_SUPPLYCOST DECIMALV3(15,2) NOT NULL,\n"
+ + " PS_COMMENT VARCHAR(199) NOT NULL \n"
+ + ")\n"
+ + "DUPLICATE KEY(PS_PARTKEY, PS_SUPPKEY)\n"
+ + "DISTRIBUTED BY HASH(PS_PARTKEY) BUCKETS 3\n"
+ + "PROPERTIES (\n"
+ + " \"replication_num\" = \"1\"\n"
+ + ")");
+ }
+
+ @Test
+ public void getRelatedTableInfoTestWithoutGroupTest() {
+ PlanChecker.from(connectContext)
+ .checkExplain("SELECT (o.c1_abs + ps.c2_abs) as add_alias,
l.L_SHIPDATE, l.L_ORDERKEY, o.O_ORDERDATE, "
+ + "ps.PS_AVAILQTY "
+ + "FROM "
+ + "lineitem as l "
+ + "LEFT JOIN "
+ + "(SELECT abs(O_TOTALPRICE + 10) as c1_abs,
O_CUSTKEY, O_ORDERDATE, O_ORDERKEY "
+ + "FROM orders) as o "
+ + "ON l.L_ORDERKEY = o.O_ORDERKEY "
+ + "JOIN "
+ + "(SELECT abs(sqrt(PS_SUPPLYCOST)) as c2_abs,
PS_AVAILQTY, PS_PARTKEY, PS_SUPPKEY "
+ + "FROM partsupp) as ps "
+ + "ON l.L_PARTKEY = ps.PS_PARTKEY and
l.L_SUPPKEY = ps.PS_SUPPKEY",
+ nereidsPlanner -> {
+ Plan rewrittenPlan =
nereidsPlanner.getRewrittenPlan();
+ Optional<RelatedTableInfo> relatedTableInfo =
+
MaterializedViewUtils.getRelatedTableInfo("L_SHIPDATE", rewrittenPlan);
+ checkRelatedTableInfo(relatedTableInfo,
+ "lineitem",
+ "L_SHIPDATE",
+ true);
+ });
+ }
+
+ @Test
+ public void getRelatedTableInfoTestWithAliasAndGroupTest() {
+ PlanChecker.from(connectContext)
+ .checkExplain("SELECT l.L_SHIPDATE AS ship_data_alias,
o.O_ORDERDATE, count(*) "
+ + "FROM "
+ + "lineitem as l "
+ + "LEFT JOIN "
+ + "(SELECT abs(O_TOTALPRICE + 10) as c1_abs,
O_CUSTKEY, O_ORDERDATE, O_ORDERKEY "
+ + "FROM orders) as o "
+ + "ON l.L_ORDERKEY = o.O_ORDERKEY "
+ + "JOIN "
+ + "(SELECT abs(sqrt(PS_SUPPLYCOST)) as c2_abs,
PS_AVAILQTY, PS_PARTKEY, PS_SUPPKEY "
+ + "FROM partsupp) as ps "
+ + "ON l.L_PARTKEY = ps.PS_PARTKEY and
l.L_SUPPKEY = ps.PS_SUPPKEY "
+ + "GROUP BY l.L_SHIPDATE, o.O_ORDERDATE ",
+ nereidsPlanner -> {
+ Plan rewrittenPlan =
nereidsPlanner.getRewrittenPlan();
+ Optional<RelatedTableInfo> relatedTableInfo =
+
MaterializedViewUtils.getRelatedTableInfo("ship_data_alias", rewrittenPlan);
+ checkRelatedTableInfo(relatedTableInfo,
+ "lineitem",
+ "L_SHIPDATE",
+ true);
+ });
+ }
+
+ @Test
+ public void getRelatedTableInfoTestWithoutPartitionTest() {
+ PlanChecker.from(connectContext)
+ .checkExplain("SELECT ps_1.PS_SUPPLYCOST "
+ + "FROM "
+ + "partsupp as ps_1 "
+ + "LEFT JOIN "
+ + "partsupp as ps_2 "
+ + "ON ps_1.PS_PARTKEY = ps_2.PS_SUPPKEY ",
+ nereidsPlanner -> {
+ Plan rewrittenPlan =
nereidsPlanner.getRewrittenPlan();
+ Optional<RelatedTableInfo> relatedTableInfo =
+
MaterializedViewUtils.getRelatedTableInfo("PS_SUPPLYCOST", rewrittenPlan);
+
Assertions.assertFalse(relatedTableInfo.isPresent());
+ });
+ }
+
+ @Test
+ public void getRelatedTableInfoTestWithWindowTest() {
+ PlanChecker.from(connectContext)
+ .checkExplain("SELECT (o.c1_abs + ps.c2_abs) as add_alias,
l.L_SHIPDATE, l.L_ORDERKEY, o.O_ORDERDATE, "
+ + "count(o.O_ORDERDATE) over (partition by
l.L_SHIPDATE order by l.L_ORDERKEY rows between unbounded preceding and
current row) as window_count "
+ + "FROM "
+ + "lineitem as l "
+ + "LEFT JOIN "
+ + "(SELECT abs(O_TOTALPRICE + 10) as c1_abs,
O_CUSTKEY, O_ORDERDATE, O_ORDERKEY "
+ + "FROM orders) as o "
+ + "ON l.L_ORDERKEY = o.O_ORDERKEY "
+ + "JOIN "
+ + "(SELECT abs(sqrt(PS_SUPPLYCOST)) as c2_abs,
PS_AVAILQTY, PS_PARTKEY, PS_SUPPKEY "
+ + "FROM partsupp) as ps "
+ + "ON l.L_PARTKEY = ps.PS_PARTKEY and
l.L_SUPPKEY = ps.PS_SUPPKEY",
+ nereidsPlanner -> {
+ Plan rewrittenPlan =
nereidsPlanner.getRewrittenPlan();
+ Optional<RelatedTableInfo> relatedTableInfo =
+
MaterializedViewUtils.getRelatedTableInfo("L_SHIPDATE", rewrittenPlan);
+ checkRelatedTableInfo(relatedTableInfo,
+ "lineitem",
+ "L_SHIPDATE",
+ true);
+ });
+ }
+
+ @Test
+ public void getRelatedTableInfoTestWithWindowButNotPartitionTest() {
+ PlanChecker.from(connectContext)
+ .checkExplain("SELECT (o.c1_abs + ps.c2_abs) as add_alias,
l.L_SHIPDATE, l.L_ORDERKEY, o.O_ORDERDATE, "
+ + "count(o.O_ORDERDATE) over (partition by
l.L_ORDERKEY order by l.L_ORDERKEY rows between unbounded preceding and
current row) as window_count "
+ + "FROM "
+ + "lineitem as l "
+ + "LEFT JOIN "
+ + "(SELECT abs(O_TOTALPRICE + 10) as c1_abs,
O_CUSTKEY, O_ORDERDATE, O_ORDERKEY "
+ + "FROM orders) as o "
+ + "ON l.L_ORDERKEY = o.O_ORDERKEY "
+ + "JOIN "
+ + "(SELECT abs(sqrt(PS_SUPPLYCOST)) as c2_abs,
PS_AVAILQTY, PS_PARTKEY, PS_SUPPKEY "
+ + "FROM partsupp) as ps "
+ + "ON l.L_PARTKEY = ps.PS_PARTKEY and
l.L_SUPPKEY = ps.PS_SUPPKEY",
+ nereidsPlanner -> {
+ Plan rewrittenPlan =
nereidsPlanner.getRewrittenPlan();
+ Optional<RelatedTableInfo> relatedTableInfo =
+
MaterializedViewUtils.getRelatedTableInfo("L_SHIPDATE", rewrittenPlan);
+
Assertions.assertFalse(relatedTableInfo.isPresent());
+ });
+ }
+
+ @Test
+ public void containTableQueryOperatorWithTabletTest() {
+ PlanChecker.from(connectContext)
+ .checkExplain("select * from orders TABLET(11080)",
+ nereidsPlanner -> {
+ Plan analyzedPlan =
nereidsPlanner.getAnalyzedPlan();
+
Assertions.assertTrue(MaterializedViewUtils.containTableQueryOperator(analyzedPlan));
+ });
+ }
+
+ @Test
+ public void containTableQueryOperatorTableSampleTest() {
+ PlanChecker.from(connectContext)
+ .checkExplain("select * from orders TABLESAMPLE(20 percent)",
+ nereidsPlanner -> {
+ Plan analyzedPlan =
nereidsPlanner.getAnalyzedPlan();
+
Assertions.assertTrue(MaterializedViewUtils.containTableQueryOperator(analyzedPlan));
+ });
+ }
+
+ @Test
+ public void containTableQueryOperatorPartitionTest() {
+ PlanChecker.from(connectContext)
+ .checkExplain("select * from orders PARTITION day_2",
+ nereidsPlanner -> {
+ Plan analyzedPlan =
nereidsPlanner.getAnalyzedPlan();
+
Assertions.assertTrue(MaterializedViewUtils.containTableQueryOperator(analyzedPlan));
+ });
+ }
+
+ @Test
+ public void containTableQueryOperatorWithoutOperatorTest() {
+ PlanChecker.from(connectContext)
+ .checkExplain("select * from orders",
+ nereidsPlanner -> {
+ Plan analyzedPlan =
nereidsPlanner.getAnalyzedPlan();
+
Assertions.assertFalse(MaterializedViewUtils.containTableQueryOperator(analyzedPlan));
+ });
+ }
+
+ private void checkRelatedTableInfo(Optional<RelatedTableInfo>
relatedTableInfo,
+ String expectTableName,
+ String expectColumnName,
+ boolean pctPossible) {
+ Assertions.assertTrue(relatedTableInfo.isPresent());
+ BaseTableInfo relatedBaseTableInfo =
relatedTableInfo.get().getTableInfo();
+ try {
+ TableIf tableIf = Env.getCurrentEnv().getCatalogMgr()
+
.getCatalogOrAnalysisException(relatedBaseTableInfo.getCtlId())
+ .getDbOrAnalysisException(relatedBaseTableInfo.getDbId())
+
.getTableOrAnalysisException(relatedBaseTableInfo.getTableId());
+ Assertions.assertEquals(tableIf.getName(), expectTableName);
+ } catch (Exception exception) {
+ Assertions.fail();
+ }
+ Assertions.assertEquals(relatedTableInfo.get().getColumn(),
expectColumnName);
+ Assertions.assertTrue(pctPossible);
+ }
+}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanVisitorTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanVisitorTest.java
index c6ca20577cc..775bc05e163 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanVisitorTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanVisitorTest.java
@@ -21,6 +21,8 @@ import org.apache.doris.catalog.TableIf;
import org.apache.doris.catalog.TableIf.TableType;
import org.apache.doris.nereids.trees.TreeNode;
import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.CurrentDate;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.Now;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Random;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Uuid;
import org.apache.doris.nereids.trees.plans.physical.PhysicalPlan;
@@ -142,4 +144,20 @@ public class PlanVisitorTest extends TestWithFeService {
expectedTables);
});
}
+
+ @Test
+ public void testTimeFunction() {
+ PlanChecker.from(connectContext)
+ .checkExplain("SELECT *, now() FROM table1 "
+ + "LEFT SEMI JOIN table2 ON table1.c1 =
table2.c1 "
+ + "WHERE table1.c1 IN (SELECT c1 FROM table2)
OR CURDATE() < '2023-01-01'",
+ nereidsPlanner -> {
+ List<TreeNode<Expression>> collectResult = new
ArrayList<>();
+ // Check nondeterministic collect
+
nereidsPlanner.getAnalyzedPlan().accept(NondeterministicFunctionCollector.INSTANCE,
collectResult);
+ Assertions.assertEquals(2, collectResult.size());
+ Assertions.assertTrue(collectResult.get(0)
instanceof Now);
+ Assertions.assertTrue(collectResult.get(1)
instanceof CurrentDate);
+ });
+ }
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ExpressionUtilsTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ExpressionUtilsTest.java
index 7ab3e8083d1..f68d37a24db 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ExpressionUtilsTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ExpressionUtilsTest.java
@@ -91,8 +91,6 @@ public class ExpressionUtilsTest extends TestWithFeService {
+ "PROPERTIES (\n"
+ " \"replication_num\" = \"1\"\n"
+ ")");
- connectContext.getSessionVariable().enableNereidsTimeout = false;
-
}
@Test
@@ -158,7 +156,7 @@ public class ExpressionUtilsTest extends TestWithFeService {
}
@Test
- public void testShuttleExpressionWithLineage1() {
+ public void shuttleExpressionWithLineageTest1() {
PlanChecker.from(connectContext)
.checkExplain("SELECT (o.c1_abs + ps.c2_abs) as add_alias,
l.L_LINENUMBER, o.O_ORDERSTATUS "
+ "FROM "
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]