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

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


The following commit(s) were added to refs/heads/branch-4.1 by this push:
     new 1dbf5c68709 [fix](mtmv) Preserve origin statement in refresh task 
(#68272)
1dbf5c68709 is described below

commit 1dbf5c687094ebb819a6defc519a81d3bf263b85
Author: morrySnow <[email protected]>
AuthorDate: Mon Sep 21 10:10:41 2026 +0800

    [fix](mtmv) Preserve origin statement in refresh task (#68272)
    
    ### What problem does this PR solve?
    
    Issue Number: None
    
    Related PR: #68269
    
    Problem Summary:
    
    Internal MTMV refresh tasks could construct a StatementContext and
    LogicalPlanAdapter without an origin statement. StmtExecutor then copied
    the null adapter origin back into the context. If CBO candidate costing
    failed, CostBasedRewriteJob dereferenced that missing origin while
    logging and raised an unrelated NullPointerException.
    
    This change initializes refresh planning with the MV query, propagates
    the same origin through the adapter, and makes the CBO failure log
    tolerate internal contexts without an origin statement.
    
    ### Release note
    
    Fix internal materialized view refresh failures caused by a missing
    origin statement.
    
    ### Check List (For Author)
    
    - Test: Unit Test
    - ./run-fe-ut.sh --run
    
org.apache.doris.mtmv.MTMVTaskTest,org.apache.doris.nereids.jobs.rewrite.CostBasedRewriteJobTest
      - 17 tests passed
    - Behavior changed: No
    - Does this need documentation: No
---
 .../apache/doris/job/extensions/mtmv/MTMVTask.java | 14 ++++++-
 .../nereids/jobs/rewrite/CostBasedRewriteJob.java  | 10 ++++-
 .../java/org/apache/doris/mtmv/MTMVTaskTest.java   | 17 +++++++++
 .../jobs/rewrite/CostBasedRewriteJobTest.java      | 44 ++++++++++++++++++++++
 4 files changed, 81 insertions(+), 4 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/job/extensions/mtmv/MTMVTask.java 
b/fe/fe-core/src/main/java/org/apache/doris/job/extensions/mtmv/MTMVTask.java
index 81b4e29e977..02366f011e1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/job/extensions/mtmv/MTMVTask.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/job/extensions/mtmv/MTMVTask.java
@@ -63,6 +63,7 @@ import org.apache.doris.nereids.glue.LogicalPlanAdapter;
 import 
org.apache.doris.nereids.trees.plans.commands.UpdateMvByPartitionCommand;
 import org.apache.doris.qe.AuditLogHelper;
 import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.OriginStatement;
 import org.apache.doris.qe.QeProcessorImpl;
 import org.apache.doris.qe.QueryState.MysqlStateType;
 import org.apache.doris.qe.StmtExecutor;
@@ -333,7 +334,8 @@ public class MTMVTask extends AbstractTask {
             Map<TableIf, String> tableWithPartKey, ConnectContext taskContext)
             throws Exception {
         ConnectContext ctx = MTMVPlanUtil.createMTMVContext(mtmv, 
MTMVPlanUtil.DISABLE_RULES_WHEN_RUN_MTMV_TASK);
-        StatementContext statementContext = new StatementContext();
+        StatementContext statementContext = new StatementContext(
+                ctx, new OriginStatement(mtmv.getQuerySql(), 0));
         ctx.setStatementContext(statementContext);
         executor = null;
         try {
@@ -347,7 +349,7 @@ public class MTMVTask extends AbstractTask {
             UpdateMvByPartitionCommand command = UpdateMvByPartitionCommand
                     .from(mtmv, mtmv.getMvPartitionInfo().getPartitionType() 
!= MTMVPartitionType.SELF_MANAGE
                             ? refreshPartitionNames : Sets.newHashSet(), 
tableWithPartKey, statementContext);
-            executor = new StmtExecutor(ctx, new LogicalPlanAdapter(command, 
ctx.getStatementContext()));
+            executor = createExecutor(ctx, command, statementContext);
             ctx.setExecutor(executor);
             ctx.setQueryId(queryId);
             ctx.getState().setNereids(true);
@@ -371,6 +373,14 @@ public class MTMVTask extends AbstractTask {
         }
     }
 
+    private static StmtExecutor createExecutor(ConnectContext ctx, 
UpdateMvByPartitionCommand command,
+            StatementContext statementContext) {
+        LogicalPlanAdapter adapter = new LogicalPlanAdapter(command, 
statementContext);
+        // StmtExecutor copies the adapter origin back into StatementContext 
during construction.
+        adapter.setOrigStmt(statementContext.getOriginStatement());
+        return new StmtExecutor(ctx, adapter);
+    }
+
     private static void closeExecutionContext(ConnectContext ctx) {
         closeExecutionContext(ctx, null);
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/CostBasedRewriteJob.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/CostBasedRewriteJob.java
index ac0df804da2..6f416faa5ee 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/CostBasedRewriteJob.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/CostBasedRewriteJob.java
@@ -87,8 +87,8 @@ public class CostBasedRewriteJob implements RewriteJob {
         // If one of them optimize failed, just return
         if (!skipCboRuleCost.isPresent() || !appliedCboRuleCost.isPresent()) {
             LOG.warn("Cbo rewrite execute failed on sql: {}, jobs are {}, plan 
is {}.",
-                    
currentCtx.getStatementContext().getOriginStatement().originStmt,
-                    rewriteJobs, currentCtx.getRewritePlan());
+                    getOriginSqlForLogging(currentCtx.getStatementContext()), 
rewriteJobs,
+                    currentCtx.getRewritePlan());
             return;
         }
         if (checkHint.first) {
@@ -106,6 +106,12 @@ public class CostBasedRewriteJob implements RewriteJob {
         }
     }
 
+    static String getOriginSqlForLogging(StatementContext statementContext) {
+        return Optional.ofNullable(statementContext.getOriginStatement())
+                .map(origin -> origin.originStmt)
+                .orElse("<unknown>");
+    }
+
     /**
      * check if we have use rule hint or no use rule hint
      * return an optional object which checkHint.first means whether it use 
hint
diff --git a/fe/fe-core/src/test/java/org/apache/doris/mtmv/MTMVTaskTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/mtmv/MTMVTaskTest.java
index e7cb5201536..799977e64c6 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/mtmv/MTMVTaskTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/mtmv/MTMVTaskTest.java
@@ -31,8 +31,12 @@ import 
org.apache.doris.job.extensions.mtmv.MTMVTask.MTMVTaskTriggerMode;
 import org.apache.doris.job.extensions.mtmv.MTMVTaskContext;
 import org.apache.doris.mtmv.MTMVPartitionInfo.MTMVPartitionType;
 import org.apache.doris.mtmv.MTMVRefreshEnum.RefreshMethod;
+import org.apache.doris.nereids.StatementContext;
+import 
org.apache.doris.nereids.trees.plans.commands.UpdateMvByPartitionCommand;
 import org.apache.doris.persist.gson.GsonUtils;
 import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.OriginStatement;
+import org.apache.doris.qe.StmtExecutor;
 import org.apache.doris.thrift.TRow;
 
 import com.google.common.collect.Lists;
@@ -340,6 +344,19 @@ public class MTMVTaskTest {
         }
     }
 
+    @Test
+    public void testCreateExecutorPreservesOriginStatement(@Mocked 
UpdateMvByPartitionCommand command) {
+        ConnectContext ctx = new ConnectContext();
+        OriginStatement originStatement = new OriginStatement("select k1 from 
test_db.base_table", 0);
+        StatementContext statementContext = new StatementContext(ctx, 
originStatement);
+
+        StmtExecutor executor = Deencapsulation.invoke(
+                MTMVTask.class, "createExecutor", ctx, command, 
statementContext);
+
+        Assert.assertSame(originStatement, 
statementContext.getOriginStatement());
+        Assert.assertSame(originStatement, 
executor.getParsedStmt().getOrigStmt());
+    }
+
     @Test
     public void testGetTvfInfoReturnsNullStringForMissingComputeGroup() {
         MTMVTask task = new MTMVTask(mtmv, relation, new 
MTMVTaskContext(MTMVTaskTriggerMode.MANUAL));
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/rewrite/CostBasedRewriteJobTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/rewrite/CostBasedRewriteJobTest.java
new file mode 100644
index 00000000000..8110c6f10c3
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/rewrite/CostBasedRewriteJobTest.java
@@ -0,0 +1,44 @@
+// 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.jobs.rewrite;
+
+import org.apache.doris.nereids.StatementContext;
+import org.apache.doris.qe.OriginStatement;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class CostBasedRewriteJobTest {
+
+    @Test
+    void testGetOriginSqlForLoggingWithoutOriginStatement() {
+        StatementContext statementContext = new StatementContext(null, null);
+
+        Assertions.assertEquals("<unknown>",
+                CostBasedRewriteJob.getOriginSqlForLogging(statementContext));
+    }
+
+    @Test
+    void testGetOriginSqlForLoggingWithOriginStatement() {
+        StatementContext statementContext = new StatementContext(
+                null, new OriginStatement("select 1", 0));
+
+        Assertions.assertEquals("select 1",
+                CostBasedRewriteJob.getOriginSqlForLogging(statementContext));
+    }
+}


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

Reply via email to