This is an automated email from the ASF dual-hosted git repository.

morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-3.1 by this push:
     new 13e27d934f1 branch-3.1: [fix](mv) Fix stats unknown when calc sync mv 
plan statistics #58426 (#58913)
13e27d934f1 is described below

commit 13e27d934f17c6d2ff61dd22f263acca22271f05
Author: seawinde <[email protected]>
AuthorDate: Mon Dec 15 11:25:11 2025 +0800

    branch-3.1: [fix](mv) Fix stats unknown when calc sync mv plan statistics 
#58426 (#58913)
    
    picked from #58426
---
 .../doris/nereids/stats/StatsCalculator.java       |  4 +-
 .../apache/doris/statistics/StatisticsCache.java   |  6 +-
 .../doris/nereids/stats/StatsCalculatorTest.java   | 36 +++++++++
 .../doris/statistics/StatisticsCacheTest.java      | 90 ++++++++++++++++++++++
 .../availability/materialized_view_switch.groovy   |  4 +-
 5 files changed, 133 insertions(+), 7 deletions(-)

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 394c9a4a1b0..752a70d508f 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
@@ -1199,7 +1199,7 @@ public class StatsCalculator extends 
DefaultPlanVisitor<Statistics, Void> {
 
     private ColumnStatistic getColumnStatistic(TableIf table, String colName, 
long idxId) {
         ConnectContext connectContext = ConnectContext.get();
-        if (connectContext != null && connectContext.getState().isInternal()) {
+        if (connectContext != null && 
connectContext.getState().isPlanWithUnKnownColumnStats()) {
             return ColumnStatistic.UNKNOWN;
         }
         long catalogId;
@@ -1230,7 +1230,7 @@ public class StatsCalculator extends 
DefaultPlanVisitor<Statistics, Void> {
 
     private ColumnStatistic getColumnStatistic(TableIf table, String colName, 
long idxId, List<String> partitionNames) {
         ConnectContext connectContext = ConnectContext.get();
-        if (connectContext != null && connectContext.getState().isInternal()) {
+        if (connectContext != null && 
connectContext.getState().isPlanWithUnKnownColumnStats()) {
             return ColumnStatistic.UNKNOWN;
         }
         long catalogId;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCache.java 
b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCache.java
index 07a0c843f0e..eee60d1025a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCache.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCache.java
@@ -90,7 +90,7 @@ public class StatisticsCache {
 
     public ColumnStatistic getColumnStatistics(long catalogId, long dbId, long 
tblId, long idxId, String colName) {
         ConnectContext ctx = ConnectContext.get();
-        if (ctx != null && ctx.getState().isInternal()) {
+        if (ctx != null && ctx.getState().isPlanWithUnKnownColumnStats()) {
             return ColumnStatistic.UNKNOWN;
         }
         // Need to change base index id to -1 for OlapTable.
@@ -114,7 +114,7 @@ public class StatisticsCache {
     public PartitionColumnStatistic getPartitionColumnStatistics(long 
catalogId, long dbId, long tblId, long idxId,
                                                   String partName, String 
colName) {
         ConnectContext ctx = ConnectContext.get();
-        if (ctx != null && ctx.getState().isInternal()) {
+        if (ctx != null && ctx.getState().isPlanWithUnKnownColumnStats()) {
             return PartitionColumnStatistic.UNKNOWN;
         }
         // Need to change base index id to -1 for OlapTable.
@@ -157,7 +157,7 @@ public class StatisticsCache {
 
     private Optional<Histogram> getHistogram(long ctlId, long dbId, long 
tblId, long idxId, String colName) {
         ConnectContext ctx = ConnectContext.get();
-        if (ctx != null && ctx.getState().isInternal()) {
+        if (ctx != null && ctx.getState().isPlanWithUnKnownColumnStats()) {
             return Optional.empty();
         }
         StatisticsCacheKey k = new StatisticsCacheKey(ctlId, dbId, tblId, 
idxId, colName);
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/stats/StatsCalculatorTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/stats/StatsCalculatorTest.java
index 75cf3f2bea0..37fa061b48d 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/stats/StatsCalculatorTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/stats/StatsCalculatorTest.java
@@ -41,6 +41,7 @@ import 
org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalTopN;
 import org.apache.doris.nereids.types.IntegerType;
 import org.apache.doris.nereids.util.PlanConstructor;
+import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.statistics.ColumnStatistic;
 import org.apache.doris.statistics.ColumnStatisticBuilder;
 import org.apache.doris.statistics.Statistics;
@@ -317,4 +318,39 @@ public class StatsCalculatorTest {
         Assertions.assertEquals(1, slot1Stats.ndv, 0.1);
         Assertions.assertEquals(0, slot1Stats.numNulls, 0.1);
     }
+
+    @Test
+    public void testOlapScanWithPlanWithUnknownColumnStats() {
+        boolean prevFlag = false;
+        if (ConnectContext.get() != null) {
+            prevFlag = 
ConnectContext.get().getState().isPlanWithUnKnownColumnStats();
+            
ConnectContext.get().getState().setPlanWithUnKnownColumnStats(true);
+        }
+        try {
+            long tableId1 = 100;
+            OlapTable table1 = PlanConstructor.newOlapTable(tableId1, 
"t_unknown", 0);
+            List<String> qualifier = ImmutableList.of("test", "t");
+            SlotReference slot1 = new SlotReference(new ExprId(0), "c1", 
IntegerType.INSTANCE, true, qualifier,
+                    table1, new Column("c1", PrimitiveType.INT),
+                    table1, new Column("c1", PrimitiveType.INT));
+
+            LogicalOlapScan logicalOlapScan1 = (LogicalOlapScan) new 
LogicalOlapScan(
+                    StatementScopeIdGenerator.newRelationId(), table1,
+                    
Collections.emptyList()).withGroupExprLogicalPropChildren(Optional.empty(),
+                    Optional.of(new LogicalProperties(() -> 
ImmutableList.of(slot1), () -> DataTrait.EMPTY_TRAIT)), ImmutableList.of());
+
+            GroupExpression groupExpression = new 
GroupExpression(logicalOlapScan1, ImmutableList.of());
+            Group ownerGroup = new Group(null, groupExpression, null);
+            StatsCalculator.estimate(groupExpression, null);
+            Statistics stats = ownerGroup.getStatistics();
+            Assertions.assertEquals(1, stats.columnStatistics().size());
+            ColumnStatistic colStat = stats.columnStatistics().get(slot1);
+            Assertions.assertTrue(colStat.isUnKnown);
+        } finally {
+            if (ConnectContext.get() != null) {
+                
ConnectContext.get().getState().setPlanWithUnKnownColumnStats(prevFlag);
+            }
+        }
+    }
+
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/statistics/StatisticsCacheTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/statistics/StatisticsCacheTest.java
new file mode 100644
index 00000000000..5919b548d00
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/statistics/StatisticsCacheTest.java
@@ -0,0 +1,90 @@
+// 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.statistics;
+
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.utframe.UtFrameUtils;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Assumptions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class StatisticsCacheTest {
+
+    private ConnectContext ctx;
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        if (ConnectContext.get() == null) {
+            ctx = UtFrameUtils.createDefaultCtx();
+        } else {
+            ctx = ConnectContext.get();
+        }
+    }
+
+    @Test
+    public void testGetColumnStatisticsWithPlanWithUnknownColumnStats() {
+        Assumptions.assumeTrue(ConnectContext.get() != null, "ConnectContext 
not available");
+
+        boolean prevFlag = 
ConnectContext.get().getState().isPlanWithUnKnownColumnStats();
+        ConnectContext.get().getState().setPlanWithUnKnownColumnStats(true);
+        try {
+            StatisticsCache cache = new StatisticsCache();
+            ColumnStatistic stat = cache.getColumnStatistics(
+                    1L, 1L, 1L, -1L, "col");
+            Assertions.assertEquals(ColumnStatistic.UNKNOWN, stat,
+                    "Expect UNKNOWN when plan has unknown column stats");
+        } finally {
+            
ConnectContext.get().getState().setPlanWithUnKnownColumnStats(prevFlag);
+        }
+    }
+
+    @Test
+    public void testGetHistogramWithPlanWithUnknownColumnStats() {
+        Assumptions.assumeTrue(ConnectContext.get() != null, "ConnectContext 
not available");
+
+        boolean prevFlag = 
ConnectContext.get().getState().isPlanWithUnKnownColumnStats();
+        ConnectContext.get().getState().setPlanWithUnKnownColumnStats(true);
+        try {
+            StatisticsCache cache = new StatisticsCache();
+            // public getHistogram returns null when underlying optional is 
empty
+            Histogram hist = cache.getHistogram(1L, 1L, 1L, "col");
+            Assertions.assertNull(hist, "Expect null histogram when plan has 
unknown column stats");
+        } finally {
+            
ConnectContext.get().getState().setPlanWithUnKnownColumnStats(prevFlag);
+        }
+    }
+
+    @Test
+    public void 
testGetPartitionColumnStatisticsWithPlanWithUnknownColumnStats() {
+        Assumptions.assumeTrue(ConnectContext.get() != null, "ConnectContext 
not available");
+
+        boolean prevFlag = 
ConnectContext.get().getState().isPlanWithUnKnownColumnStats();
+        ConnectContext.get().getState().setPlanWithUnKnownColumnStats(true);
+        try {
+            StatisticsCache cache = new StatisticsCache();
+            PartitionColumnStatistic pstat = 
cache.getPartitionColumnStatistics(
+                    1L, 1L, 1L, -1L, "p", "col");
+            Assertions.assertEquals(PartitionColumnStatistic.UNKNOWN, pstat,
+                    "Expect UNKNOWN partition col stat when plan has unknown 
column stats");
+        } finally {
+            
ConnectContext.get().getState().setPlanWithUnKnownColumnStats(prevFlag);
+        }
+    }
+}
diff --git 
a/regression-test/suites/nereids_rules_p0/mv/availability/materialized_view_switch.groovy
 
b/regression-test/suites/nereids_rules_p0/mv/availability/materialized_view_switch.groovy
index 4af1d778c00..245087cfb4f 100644
--- 
a/regression-test/suites/nereids_rules_p0/mv/availability/materialized_view_switch.groovy
+++ 
b/regression-test/suites/nereids_rules_p0/mv/availability/materialized_view_switch.groovy
@@ -152,7 +152,7 @@ suite("materialized_view_switch") {
     sql """ DROP MATERIALIZED VIEW IF EXISTS mv_name_2"""
 
     sql "SET enable_materialized_view_rewrite=true"
-    async_mv_rewrite_success(db, mv_name, query, "mv_name_3")
+    async_mv_rewrite_success(db, mv_name, query, "mv_name_1")
     sql """ DROP MATERIALIZED VIEW IF EXISTS mv_name_3"""
 
     // test when materialized_view_relation_mapping_max_count is 8
@@ -167,7 +167,7 @@ suite("materialized_view_switch") {
         inner join lineitem t2 on t1.L_ORDERKEY = t2.L_ORDERKEY;
     """
     order_qt_query1_0_before "${query1_0}"
-    async_mv_rewrite_success(db, mv1_0, query1_0, "mv1_0")
+    async_mv_rewrite_success(db, mv_name, query, "mv_name_1")
     order_qt_query1_0_after "${query1_0}"
     sql """ DROP MATERIALIZED VIEW IF EXISTS mv1_0"""
 


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

Reply via email to