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 baf7ea3daf4 [fix](mtmv) Fix getting related partition table wrongly 
when multi base partition table exists (#34781)
baf7ea3daf4 is described below

commit baf7ea3daf4098610529127413730dd2447c83dc
Author: seawinde <[email protected]>
AuthorDate: Wed May 29 15:41:43 2024 +0800

    [fix](mtmv) Fix getting related partition table wrongly when multi base 
partition table exists (#34781)
    
    Fix getting related partition table wrongly when multi base partition
    table exists
    such as base table def is as following:
    
    CREATE TABLE `test1` (
    `pre_batch_no` VARCHAR(100) NULL COMMENT 'pre_batch_no',
    `batch_no` VARCHAR(100) NULL COMMENT 'batch_no',
    `vin_type1` VARCHAR(50) NULL COMMENT 'vin',
    `upgrade_day` date COMMENT 'upgrade_day'
    ) ENGINE=OLAP
    unique KEY(`pre_batch_no`,`batch_no`, `vin_type1`, `upgrade_day`)
    COMMENT 'OLAP'
    PARTITION BY RANGE(`upgrade_day`)
    (
    FROM ("2024-03-20") TO ("2024-03-31") INTERVAL 1 DAY
    )
    DISTRIBUTED BY HASH(`vin_type1`) BUCKETS 10
    PROPERTIES (
           "replication_num" = "1"
    );
    
    CREATE TABLE `test2` (
    `batch_no` VARCHAR(100) NULL COMMENT 'batch_no',
    `vin_type2` VARCHAR(50) NULL COMMENT 'vin',
    `status` VARCHAR(50) COMMENT 'status',
    `upgrade_day` date  not null COMMENT 'upgrade_day'
    ) ENGINE=OLAP
    Duplicate KEY(`batch_no`,`vin_type2`)
    COMMENT 'OLAP'
    PARTITION BY RANGE(`upgrade_day`)
    (
    FROM ("2024-01-01") TO ("2024-01-10") INTERVAL 1 DAY
    )
    DISTRIBUTED BY HASH(`vin_type2`) BUCKETS 10
    PROPERTIES (
           "replication_num" = "1"
    );
    
    if you create partition mv which partition by ` t1.upgrade_day` as
    following it will be successful
    
    select
      t1.upgrade_day,
      t1.batch_no,
      t1.vin_type1
    from
      (
        SELECT
          batch_no,
          vin_type1,
          upgrade_day
        FROM
          test1
        where
          batch_no like 'c%'
        group by
          batch_no,
          vin_type1,
          upgrade_day
      ) t1
      left join (
        select
          batch_no,
          vin_type2,
          status
        from
          test2
        group by
          batch_no,
          vin_type2,
          status
      ) t2 on t1.vin_type1 = t2.vin_type2;
---
 .../exploration/mv/MaterializedViewUtils.java      | 144 ++++++++++-----------
 .../exploration/mv/MaterializedViewUtilsTest.java  | 103 +++++++++++++++
 2 files changed, 175 insertions(+), 72 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
index e4dc120c20e..2e45fa44833 100644
--- 
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
@@ -21,7 +21,7 @@ import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.MTMV;
 import org.apache.doris.catalog.PartitionType;
 import org.apache.doris.catalog.TableIf;
-import org.apache.doris.common.Pair;
+import org.apache.doris.catalog.constraint.TableIdentifier;
 import org.apache.doris.mtmv.BaseTableInfo;
 import org.apache.doris.mtmv.MTMVRelatedTableIf;
 import org.apache.doris.nereids.CascadesContext;
@@ -36,6 +36,7 @@ import 
org.apache.doris.nereids.trees.expressions.WindowExpression;
 import org.apache.doris.nereids.trees.plans.JoinType;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PreAggStatus;
+import org.apache.doris.nereids.trees.plans.algebra.CatalogRelation;
 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;
@@ -50,11 +51,12 @@ import 
org.apache.doris.nereids.trees.plans.visitor.DefaultPlanVisitor;
 
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMultimap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
 
-import java.util.ArrayList;
 import java.util.BitSet;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -95,17 +97,29 @@ public class MaterializedViewUtils {
         if (!columnSlot.isColumnFromTable()) {
             return Optional.empty();
         }
-        // check sql pattern
-        IncrementCheckerContext context = new 
IncrementCheckerContext(columnSlot);
-        materializedViewPlan.accept(MaterializedViewIncrementChecker.INSTANCE, 
context);
-        if (context.getPartitionRelatedTableAndColumnList().isEmpty() || 
!context.isPctPossible()) {
+        // Collect table relation map which is used to identify self join
+        List<CatalogRelation> catalogRelationObjs =
+                
materializedViewPlan.collectToList(CatalogRelation.class::isInstance);
+        ImmutableMultimap.Builder<TableIdentifier, CatalogRelation> 
tableCatalogRelationMultimapBuilder =
+                ImmutableMultimap.builder();
+        for (CatalogRelation catalogRelation : catalogRelationObjs) {
+            tableCatalogRelationMultimapBuilder.put(new 
TableIdentifier(catalogRelation.getTable()), catalogRelation);
+        }
+        // Check sql pattern
+        IncrementCheckerContext checkContext =
+                new IncrementCheckerContext(columnSlot, 
tableCatalogRelationMultimapBuilder.build());
+        materializedViewPlan.accept(MaterializedViewIncrementChecker.INSTANCE, 
checkContext);
+        Multimap<TableIf, Column> partitionRelatedTableAndColumnMap =
+                checkContext.getPartitionRelatedTableAndColumnMap();
+        if (partitionRelatedTableAndColumnMap.isEmpty()) {
             return Optional.empty();
         }
         // TODO support to return only one related table info, support multi 
later
-        Pair<TableIf, Column> tableIfColumnPair = 
context.getPartitionRelatedTableAndColumnList().get(0);
-        return Optional.of(new RelatedTableInfo(new 
BaseTableInfo(tableIfColumnPair.key()),
-                context.isPctPossible(),
-                tableIfColumnPair.value().getName()));
+        for (Map.Entry<TableIf, Column> entry : 
partitionRelatedTableAndColumnMap.entries()) {
+            return Optional.of(new RelatedTableInfo(new 
BaseTableInfo(entry.getKey()), true,
+                    entry.getValue().getName()));
+        }
+        return Optional.empty();
     }
 
     /**
@@ -289,7 +303,6 @@ public class MaterializedViewUtils {
         public Void visitLogicalJoin(LogicalJoin<? extends Plan, ? extends 
Plan> join,
                 IncrementCheckerContext context) {
             if (join.isMarkJoin()) {
-                context.setPctPossible(false);
                 return null;
             }
             Plan left = join.child(0);
@@ -301,20 +314,17 @@ public class MaterializedViewUtils {
             boolean useLeft = 
leftColumnSet.contains(context.getMvPartitionColumn().getColumn().get());
             JoinType joinType = join.getJoinType();
             if (joinType.isInnerJoin() || joinType.isCrossJoin()) {
-                context.setPctPossible(true);
-            } else if (joinType.isLeftJoin()
+                return visit(join, context);
+            } else if ((joinType.isLeftJoin()
                     || joinType.isLefSemiJoin()
-                    || joinType.isLeftAntiJoin()) {
-                context.setPctPossible(useLeft);
-            } else if (joinType.isRightJoin()
+                    || joinType.isLeftAntiJoin()) && useLeft) {
+                return visit(join.left(), context);
+            } else if ((joinType.isRightJoin()
                     || joinType.isRightAntiJoin()
-                    || joinType.isRightSemiJoin()) {
-                context.setPctPossible(!useLeft);
-            } else {
-                // un supported join type
-                context.setPctPossible(false);
+                    || joinType.isRightSemiJoin()) && !useLeft) {
+                return visit(join.right(), context);
             }
-            return visit(join, context);
+            return null;
         }
 
         @Override
@@ -324,15 +334,13 @@ public class MaterializedViewUtils {
             }
             LogicalCatalogRelation logicalCatalogRelation = 
(LogicalCatalogRelation) relation;
             TableIf table = logicalCatalogRelation.getTable();
-            // if self join, can't infer partition column
-            if 
(!context.getTableIdAndRelationMapping().get(table.getId()).isEmpty()) {
-                context.setPctPossible(false);
+            // if self join, self join can not partition track now, remove the 
partition column correspondingly
+            if (context.getRelationByTable(table).size() > 1) {
+                
context.getPartitionRelatedTableAndColumnMap().removeAll(table);
                 return null;
             }
-            // record tableId and relation, to check the self join
-            context.addTableIdAndRelation(((LogicalCatalogRelation) 
relation).getTable().getId(), relation);
             // TODO: 2024/1/31 support only one partition referenced column, 
support multi later
-            if (!context.getPartitionRelatedTableAndColumnList().isEmpty()) {
+            if (!context.getPartitionRelatedTableAndColumnMap().isEmpty()) {
                 return null;
             }
             if (!(table instanceof MTMVRelatedTableIf)) {
@@ -345,9 +353,9 @@ public class MaterializedViewUtils {
             }
             Set<Column> partitionColumnSet = new 
HashSet<>(relatedTable.getPartitionColumns());
             Column mvReferenceColumn = 
context.getMvPartitionColumn().getColumn().get();
-            if (partitionColumnSet.contains(mvReferenceColumn)) {
+            if (partitionColumnSet.contains(mvReferenceColumn)
+                    && (!mvReferenceColumn.isAllowNull() || 
relatedTable.isPartitionColumnAllowNull())) {
                 context.addTableColumn(table, mvReferenceColumn);
-                context.setPctPossible(!mvReferenceColumn.isAllowNull() || 
relatedTable.isPartitionColumnAllowNull());
             }
             return visit(relation, context);
         }
@@ -357,7 +365,6 @@ public class MaterializedViewUtils {
                 IncrementCheckerContext context) {
             Set<Expression> groupByExprSet = new 
HashSet<>(aggregate.getGroupByExpressions());
             if (groupByExprSet.isEmpty()) {
-                context.setPctPossible(false);
                 return null;
             }
             Set<Column> originalGroupbyExprSet = new HashSet<>();
@@ -367,7 +374,6 @@ public class MaterializedViewUtils {
                 }
             });
             if 
(!originalGroupbyExprSet.contains(context.getMvPartitionColumn().getColumn().get()))
 {
-                context.setPctPossible(false);
                 return null;
             }
             return visit(aggregate, context);
@@ -379,15 +385,16 @@ public class MaterializedViewUtils {
             if (windowExpressions.isEmpty()) {
                 return visit(window, context);
             }
-            windowExpressions.forEach(expr -> checkWindowPartition(expr, 
context));
+            for (NamedExpression namedExpression : windowExpressions) {
+                if (!checkWindowPartition(namedExpression, context)) {
+                    return null;
+                }
+            }
             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
@@ -397,65 +404,58 @@ public class MaterializedViewUtils {
                     || 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 boolean checkWindowPartition(Expression expression, 
IncrementCheckerContext context) {
+            List<Object> windowExpressions =
+                    expression.collectToList(expressionTreeNode -> 
expressionTreeNode instanceof WindowExpression);
+            for (Object windowExpressionObj : windowExpressions) {
+                WindowExpression windowExpression = (WindowExpression) 
windowExpressionObj;
+                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()))
 {
+                    return false;
+                }
+            }
+            return true;
         }
     }
 
     private static final class IncrementCheckerContext {
         private final SlotReference mvPartitionColumn;
-        private boolean pctPossible = true;
-        private final List<Pair<TableIf, Column>> 
partitionRelatedTableAndColumnList = new ArrayList<>();
-        // This record the table id and relation mapping, because a table 
maybe used repeatedly.
-        private final Multimap<Long, LogicalRelation> 
tableIdAndRelationMapping = HashMultimap.create();
+        private final Multimap<TableIdentifier, CatalogRelation> 
tableAndCatalogRelationMap;
+        private final Multimap<TableIf, Column> 
partitionRelatedTableAndColumnMap = HashMultimap.create();
 
-        public IncrementCheckerContext(SlotReference mvPartitionColumn) {
+        public IncrementCheckerContext(SlotReference mvPartitionColumn,
+                Multimap<TableIdentifier, CatalogRelation> 
tableAndCatalogRelationMap) {
             this.mvPartitionColumn = mvPartitionColumn;
+            this.tableAndCatalogRelationMap = tableAndCatalogRelationMap;
         }
 
         public SlotReference getMvPartitionColumn() {
             return mvPartitionColumn;
         }
 
-        public boolean isPctPossible() {
-            return pctPossible;
-        }
-
-        public void setPctPossible(boolean pctPossible) {
-            this.pctPossible = pctPossible;
-        }
-
         public void addTableColumn(TableIf relatedTable, Column 
partitionColumn) {
-            partitionRelatedTableAndColumnList.add(Pair.of(relatedTable, 
partitionColumn));
+            partitionRelatedTableAndColumnMap.put(relatedTable, 
partitionColumn);
         }
 
-        public List<Pair<TableIf, Column>> 
getPartitionRelatedTableAndColumnList() {
-            return partitionRelatedTableAndColumnList;
+        public Multimap<TableIf, Column> 
getPartitionRelatedTableAndColumnMap() {
+            return partitionRelatedTableAndColumnMap;
         }
 
-        public Multimap<Long, LogicalRelation> getTableIdAndRelationMapping() {
-            return tableIdAndRelationMapping;
+        public Collection<CatalogRelation> getRelationByTable(TableIf tableIf) 
{
+            return tableAndCatalogRelationMap.get(new 
TableIdentifier(tableIf));
         }
 
-        public void addTableIdAndRelation(Long tableId, LogicalRelation 
relation) {
-            tableIdAndRelationMapping.put(tableId, relation);
+        public void addTableAndRelation(TableIf tableIf, CatalogRelation 
relation) {
+            tableAndCatalogRelationMap.put(new TableIdentifier(tableIf), 
relation);
         }
     }
 
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
index a730eacf22b..1ed6b92129a 100644
--- 
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
@@ -200,6 +200,42 @@ public class MaterializedViewUtilsTest extends 
TestWithFeService {
                 + "       \"replication_num\" = \"1\"\n"
                 + "    );\n"
                 + "\n");
+
+        createTable("CREATE TABLE `test1` (\n"
+                + "`pre_batch_no` VARCHAR(100) NULL COMMENT 'pre_batch_no',\n"
+                + "`batch_no` VARCHAR(100) NULL COMMENT 'batch_no',\n"
+                + "`vin_type1` VARCHAR(50) NULL COMMENT 'vin',\n"
+                + "`upgrade_day` date COMMENT 'upgrade_day'\n"
+                + ") ENGINE=OLAP\n"
+                + "unique KEY(`pre_batch_no`,`batch_no`, `vin_type1`, 
`upgrade_day`)\n"
+                + "COMMENT 'OLAP'\n"
+                + "PARTITION BY RANGE(`upgrade_day`)\n"
+                + "(\n"
+                + "FROM (\"2024-03-20\") TO (\"2024-03-31\") INTERVAL 1 DAY\n"
+                + ")\n"
+                + "DISTRIBUTED BY HASH(`vin_type1`) BUCKETS 10\n"
+                + "PROPERTIES (\n"
+                + "       \"replication_num\" = \"1\"\n"
+                + ");\n"
+        );
+
+        createTable("CREATE TABLE `test2` (\n"
+                + "`batch_no` VARCHAR(100) NULL COMMENT 'batch_no',\n"
+                + "`vin_type2` VARCHAR(50) NULL COMMENT 'vin',\n"
+                + "`status` VARCHAR(50) COMMENT 'status',\n"
+                + "`upgrade_day` date  not null COMMENT 'upgrade_day' \n"
+                + ") ENGINE=OLAP\n"
+                + "Duplicate KEY(`batch_no`,`vin_type2`)\n"
+                + "COMMENT 'OLAP'\n"
+                + "PARTITION BY RANGE(`upgrade_day`)\n"
+                + "(\n"
+                + "FROM (\"2024-01-01\") TO (\"2024-01-10\") INTERVAL 1 DAY\n"
+                + ")\n"
+                + "DISTRIBUTED BY HASH(`vin_type2`) BUCKETS 10\n"
+                + "PROPERTIES (\n"
+                + "       \"replication_num\" = \"1\"\n"
+                + ");\n"
+        );
         // Should not make scan to empty relation when the table used by 
materialized view has no data
         
connectContext.getSessionVariable().setDisableNereidsRules("OLAP_SCAN_PARTITION_PRUNE,PRUNE_EMPTY_PARTITION");
     }
@@ -362,6 +398,32 @@ public class MaterializedViewUtilsTest extends 
TestWithFeService {
                                     
MaterializedViewUtils.getRelatedTableInfo("l_orderkey", rewrittenPlan);
                             
Assertions.assertFalse(relatedTableInfo.isPresent());
                         });
+
+        PlanChecker.from(connectContext)
+                .checkExplain("    select t1.l_shipdate, t1.l_orderkey, 
t1.l_partkey, t1.l_suppkey, 1\n"
+                                + "    from lineitem_list_partition t1\n"
+                                + "    left outer join lineitem_list_partition 
t2\n"
+                                + "    on t1.l_shipdate = t2.l_shipdate\n"
+                                + "    group by t1.l_shipdate, t1.l_orderkey, 
t1.l_partkey, t1.l_suppkey",
+                        nereidsPlanner -> {
+                            Plan rewrittenPlan = 
nereidsPlanner.getRewrittenPlan();
+                            Optional<RelatedTableInfo> relatedTableInfo =
+                                    
MaterializedViewUtils.getRelatedTableInfo("l_orderkey", rewrittenPlan);
+                            
Assertions.assertFalse(relatedTableInfo.isPresent());
+                        });
+
+        PlanChecker.from(connectContext)
+                .checkExplain("    select t1.l_shipdate, t1.l_orderkey, 
t1.l_partkey, t1.l_suppkey, 1\n"
+                                + "    from lineitem_list_partition t1\n"
+                                + "    right outer join 
lineitem_list_partition t2\n"
+                                + "    on t1.l_shipdate = t2.l_shipdate\n"
+                                + "    group by t1.l_shipdate, t1.l_orderkey, 
t1.l_partkey, t1.l_suppkey",
+                        nereidsPlanner -> {
+                            Plan rewrittenPlan = 
nereidsPlanner.getRewrittenPlan();
+                            Optional<RelatedTableInfo> relatedTableInfo =
+                                    
MaterializedViewUtils.getRelatedTableInfo("l_orderkey", rewrittenPlan);
+                            
Assertions.assertFalse(relatedTableInfo.isPresent());
+                        });
     }
 
     @Test
@@ -487,6 +549,47 @@ public class MaterializedViewUtilsTest extends 
TestWithFeService {
                         });
     }
 
+    @Test
+    public void getRelatedTableInfoWhenMultiBaseTablePartition() {
+        PlanChecker.from(connectContext)
+                .checkExplain("select\n"
+                                + "t1.upgrade_day,\n"
+                                + "t1.batch_no,\n"
+                                + "t1.vin_type1\n"
+                                + "from\n"
+                                + "(\n"
+                                + "SELECT\n"
+                                + "batch_no,\n"
+                                + "vin_type1,\n"
+                                + "upgrade_day\n"
+                                + "FROM test1\n"
+                                + "where batch_no like 'c%'\n"
+                                + "group by batch_no,\n"
+                                + "vin_type1,\n"
+                                + "upgrade_day\n"
+                                + ")t1\n"
+                                + "left join\n"
+                                + "(\n"
+                                + "select\n"
+                                + "batch_no,\n"
+                                + "vin_type2,\n"
+                                + "status\n"
+                                + "from test2\n"
+                                + "group by batch_no,\n"
+                                + "vin_type2,\n"
+                                + "status\n"
+                                + ")t2 on t1.vin_type1 = t2.vin_type2;",
+                        nereidsPlanner -> {
+                            Plan rewrittenPlan = 
nereidsPlanner.getRewrittenPlan();
+                            Optional<RelatedTableInfo> relatedTableInfo =
+                                    
MaterializedViewUtils.getRelatedTableInfo("upgrade_day", rewrittenPlan);
+                            checkRelatedTableInfo(relatedTableInfo,
+                                    "test1",
+                                    "upgrade_day",
+                                    true);
+                        });
+    }
+
     @Test
     public void containTableQueryOperatorWithTabletTest() {
         PlanChecker.from(connectContext)


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to