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]