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 86a9d57f56d branch-4.1: [fix](view) ALTER VIEW definition not synced
to follower FE when COMMENT is specified #61670 (#61805)
86a9d57f56d is described below
commit 86a9d57f56d94776880b280b462335c9d841f907
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Mon Mar 30 10:50:46 2026 +0800
branch-4.1: [fix](view) ALTER VIEW definition not synced to follower FE
when COMMENT is specified #61670 (#61805)
Cherry-picked from #61670
Co-authored-by: minghong <[email protected]>
---
.../main/java/org/apache/doris/alter/Alter.java | 3 +-
.../doris/alter/ReplayModifyViewDefTest.java | 196 +++++++++++++++++++++
2 files changed, 198 insertions(+), 1 deletion(-)
diff --git a/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
b/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
index 62039cddc88..8392f1e6cf8 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
@@ -898,7 +898,8 @@ public class Alter {
String viewName = view.getName();
if (comment != null) {
view.setComment(comment);
- } else {
+ }
+ if (!Strings.isNullOrEmpty(inlineViewDef)) {
view.setInlineViewDefWithSessionVariables(inlineViewDef,
alterViewInfo.getSessionVariables());
view.setNewFullSchema(newFullSchema);
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/alter/ReplayModifyViewDefTest.java
b/fe/fe-core/src/test/java/org/apache/doris/alter/ReplayModifyViewDefTest.java
new file mode 100644
index 00000000000..25343e9d86a
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/alter/ReplayModifyViewDefTest.java
@@ -0,0 +1,196 @@
+// 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.alter;
+
+import org.apache.doris.catalog.Column;
+import org.apache.doris.catalog.Database;
+import org.apache.doris.catalog.Env;
+import org.apache.doris.catalog.PrimitiveType;
+import org.apache.doris.catalog.View;
+import org.apache.doris.nereids.parser.NereidsParser;
+import org.apache.doris.nereids.trees.plans.commands.CreateDatabaseCommand;
+import org.apache.doris.nereids.trees.plans.commands.CreateTableCommand;
+import org.apache.doris.nereids.trees.plans.commands.CreateViewCommand;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+import org.apache.doris.persist.AlterViewInfo;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.StmtExecutor;
+import org.apache.doris.utframe.UtFrameUtils;
+
+import com.google.common.collect.Lists;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Unit tests for {@link Alter#replayModifyViewDef}.
+ *
+ * Covers three replay scenarios:
+ * 1. Replay a full view definition change (new SQL + new schema).
+ * 2. Replay a comment-only change (inlineViewDef is empty / null → def must
not change).
+ * 3. Replay with both a new definition and a new comment simultaneously.
+ */
+public class ReplayModifyViewDefTest {
+
+ private static final String RUNNING_DIR =
+ "fe/mocked/ReplayModifyViewDefTest/" + UUID.randomUUID() + "/";
+
+ private static ConnectContext connectContext;
+
+ //
──────────────────────────────────────────────────────────────────────────
+ // Setup / Teardown
+ //
──────────────────────────────────────────────────────────────────────────
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ UtFrameUtils.createDorisCluster(RUNNING_DIR);
+ connectContext = UtFrameUtils.createDefaultCtx();
+
connectContext.getSessionVariable().setDisableNereidsRules("PRUNE_EMPTY_PARTITION");
+
+ NereidsParser parser = new NereidsParser();
+
+ // create database
+ String createDb = "create database test_replay_view;";
+ LogicalPlan plan = parser.parseSingle(createDb);
+ if (plan instanceof CreateDatabaseCommand) {
+ ((CreateDatabaseCommand) plan).run(connectContext, new
StmtExecutor(connectContext, createDb));
+ }
+
+ // create table
+ String createTbl = "create table test_replay_view.tbl1(k1 int, k2 int,
v1 int)"
+ + " duplicate key(k1) distributed by hash(k1) buckets 1"
+ + " properties('replication_num' = '1');";
+ plan = parser.parseSingle(createTbl);
+ if (plan instanceof CreateTableCommand) {
+ ((CreateTableCommand) plan).run(connectContext, new
StmtExecutor(connectContext, createTbl));
+ }
+
+ // create initial view
+ String createView = "create view test_replay_view.v1 as select k1, k2
from test_replay_view.tbl1;";
+ plan = parser.parseSingle(createView);
+ if (plan instanceof CreateViewCommand) {
+ ((CreateViewCommand) plan).run(connectContext, new
StmtExecutor(connectContext, createView));
+ }
+ }
+
+ @AfterClass
+ public static void tearDown() {
+ new File(RUNNING_DIR).delete();
+ }
+
+ //
──────────────────────────────────────────────────────────────────────────
+ // Helpers
+ //
──────────────────────────────────────────────────────────────────────────
+
+ private static View getView(String viewName) throws Exception {
+ Database db =
Env.getCurrentInternalCatalog().getDbOrDdlException("test_replay_view");
+ return (View) db.getTableOrDdlException(viewName);
+ }
+
+ private static long getDbId() throws Exception {
+ return
Env.getCurrentInternalCatalog().getDbOrDdlException("test_replay_view").getId();
+ }
+
+ //
──────────────────────────────────────────────────────────────────────────
+ // Tests
+ //
──────────────────────────────────────────────────────────────────────────
+
+ /**
+ * Replay a full definition change.
+ * After replay the view's inlineViewDef and full-schema must reflect the
new values.
+ */
+ @Test
+ public void testReplayModifyViewDefWithNewDef() throws Exception {
+ View view = getView("v1");
+ long dbId = getDbId();
+ long tableId = view.getId();
+
+ String newDef = "select k1, v1 from test_replay_view.tbl1 where k1 >
0";
+ List<Column> newSchema = Lists.newArrayList(
+ new Column("k1", PrimitiveType.INT),
+ new Column("v1", PrimitiveType.INT));
+
+ AlterViewInfo info = new AlterViewInfo(dbId, tableId, newDef,
newSchema,
+ new HashMap<>(), null);
+
+ Env.getCurrentEnv().getAlterInstance().replayModifyViewDef(info);
+
+ View updated = getView("v1");
+ Assert.assertEquals(newDef, updated.getInlineViewDef());
+ Assert.assertEquals(2, updated.getFullSchema().size());
+ Assert.assertNotNull(updated.getColumn("k1"));
+ Assert.assertNotNull(updated.getColumn("v1"));
+ Assert.assertNull(updated.getColumn("k2"));
+ }
+
+ /**
+ * Replay a comment-only change (inlineViewDef is null).
+ * The view definition must remain unchanged; only the comment is updated.
+ */
+ @Test
+ public void testReplayModifyViewDefCommentOnly() throws Exception {
+ // First bring v1 back to a known state with two columns.
+ View view = getView("v1");
+ long dbId = getDbId();
+ long tableId = view.getId();
+ String originalDef = view.getInlineViewDef();
+
+ AlterViewInfo info = new AlterViewInfo(dbId, tableId, null,
+ Collections.emptyList(), new HashMap<>(), "my comment");
+
+ Env.getCurrentEnv().getAlterInstance().replayModifyViewDef(info);
+
+ View updated = getView("v1");
+ // Definition must not change.
+ Assert.assertEquals(originalDef, updated.getInlineViewDef());
+ // Comment must be set.
+ Assert.assertEquals("my comment", updated.getComment());
+ }
+
+ /**
+ * Replay with both a new definition and a comment.
+ * Both the def/schema and the comment must be updated.
+ */
+ @Test
+ public void testReplayModifyViewDefWithDefAndComment() throws Exception {
+ View view = getView("v1");
+ long dbId = getDbId();
+ long tableId = view.getId();
+
+ String newDef = "select k2 from test_replay_view.tbl1";
+ List<Column> newSchema = Lists.newArrayList(new Column("k2",
PrimitiveType.INT));
+
+ AlterViewInfo info = new AlterViewInfo(dbId, tableId, newDef,
newSchema,
+ new HashMap<>(), "updated comment");
+
+ Env.getCurrentEnv().getAlterInstance().replayModifyViewDef(info);
+
+ View updated = getView("v1");
+ Assert.assertEquals(newDef, updated.getInlineViewDef());
+ Assert.assertEquals(1, updated.getFullSchema().size());
+ Assert.assertNotNull(updated.getColumn("k2"));
+ Assert.assertEquals("updated comment", updated.getComment());
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]