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

yujun777 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 7129a3e8c6b [fix](ivm) Propagate and compensate failures of the IVM 
excluded-trigger-tables ALTER (#67665)
7129a3e8c6b is described below

commit 7129a3e8c6bf087cb5a3a818e53343f5fee2c297
Author: yujun <[email protected]>
AuthorDate: Thu Sep 10 11:22:11 2026 +0800

    [fix](ivm) Propagate and compensate failures of the IVM 
excluded-trigger-tables ALTER (#67665)
    
    Follow-up of the #62606 review round.
    
    ALTER MATERIALIZED VIEW ... SET ('excluded_trigger_tables' = ...) on an
    IVM MTMV transitions the base-table streams alongside the property. That
    transition used to run inside `processAlterMTMV`, whose catch swallowed
    any `UserException`: a mid-transition failure (e.g. a stream create
    throwing after an earlier create was already journaled) reported success
    to the client while the property stayed unchanged and stray streams
    remained.
    
    Key changes:
    - Live ALTER PROPERTY statements now run through the new
    `Alter.processAlterMTMVProperty`, which propagates failures to the
    client; the journal replay path keeps the tolerant `processAlterMTMV`
    behavior.
    - The stream transition is reordered: create the streams of newly
    un-excluded bases first (compensated by dropping exactly the streams
    created in this call on failure), then apply the property, then
    best-effort drop the streams of newly excluded bases - a failed drop
    only leaks a stream of an already excluded table and never fails the
    ALTER after the property took effect.
    - Two test debug points (count-based, independent of the base-table
    iteration order) inject stream create/drop failures.
    
    Tests: `AlterMTMVTest` two new cases covering create-failure
    compensation and drop-failure best effort with multi-table excluded-set
    changes; the full class (24 tests) passes.
    
    Trace issue: https://github.com/apache/doris/issues/65418
---
 .../main/java/org/apache/doris/alter/Alter.java    | 172 ++++++++++++++++++---
 .../java/org/apache/doris/catalog/Database.java    |   5 +
 .../main/java/org/apache/doris/catalog/Env.java    |   6 +-
 .../java/org/apache/doris/mtmv/AlterMTMVTest.java  | 105 +++++++++++++
 4 files changed, 264 insertions(+), 24 deletions(-)

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 2a246e64deb..8c30d35a733 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
@@ -43,6 +43,7 @@ import org.apache.doris.common.DdlException;
 import org.apache.doris.common.MetaNotFoundException;
 import org.apache.doris.common.UserException;
 import org.apache.doris.common.cache.NereidsSqlCacheManager;
+import org.apache.doris.common.util.DebugPointUtil;
 import org.apache.doris.common.util.DynamicPartitionUtil;
 import org.apache.doris.common.util.MetaLockUtils;
 import org.apache.doris.common.util.PropertyAnalyzer;
@@ -128,6 +129,15 @@ import java.util.stream.Collectors;
 public class Alter {
     private static final Logger LOG = LogManager.getLogger(Alter.class);
 
+    // Test hooks for the IVM excluded_trigger_tables stream transition (see
+    // alterIvmExcludedTriggerTables): when enabled, the "value" param is the 
number of
+    // successful stream creates/drops to allow first (e.g. "1" allows one and 
fails the
+    // next), independent of the base-table iteration order.
+    public static final String DEBUG_POINT_CREATE_EXCLUDED_STREAM_FAIL =
+            "Alter.alterIvmExcludedTriggerTables.create_stream_fail";
+    public static final String DEBUG_POINT_DROP_EXCLUDED_STREAM_FAIL =
+            "Alter.alterIvmExcludedTriggerTables.drop_stream_fail";
+
     private AlterHandler schemaChangeHandler;
     private AlterHandler materializedViewHandler;
     private SystemHandler systemHandler;
@@ -1315,16 +1325,10 @@ public class Alter {
                     mtmv.alterStatus(alterMTMV.getStatus());
                     break;
                 case ALTER_PROPERTY:
-                    if (mtmv.isIvm() && 
alterMTMV.getMvProperties().containsKey(
-                            
PropertyAnalyzer.PROPERTIES_EXCLUDED_TRIGGER_TABLES)) {
-                        Set<TableNameInfo> oldExcludedTriggerTables = 
mtmv.getExcludedTriggerTables();
-                        Set<TableNameInfo> newExcludedTriggerTables = 
MTMVPropertyUtil.parseTableNameInfos(
-                                alterMTMV.getMvProperties().get(
-                                        
PropertyAnalyzer.PROPERTIES_EXCLUDED_TRIGGER_TABLES));
-                        updateIvmStreamsForExcludedTables(db, mtmv, 
oldExcludedTriggerTables,
-                                newExcludedTriggerTables, isReplay);
-                    }
-                    mtmv.alterMvProperties(alterMTMV, isReplay);
+                    // Live ALTER PROPERTY statements call 
processAlterMTMVProperty directly
+                    // (see Env.alterMTMVProperty) so that failures surface to 
the client;
+                    // this path only replays the journaled op, where errors 
stay tolerated.
+                    processAlterMTMVProperty(alterMTMV, isReplay);
                     return;
                 case ADD_TASK:
                     if (!mtmv.addTaskResult(alterMTMV, isReplay)) {
@@ -1355,28 +1359,141 @@ public class Alter {
         }
     }
 
-    private void updateIvmStreamsForExcludedTables(Database db, MTMV mtmv,
+    /**
+     * Applies an ALTER PROPERTY op. Live statements call this method directly 
through
+     * {@code Env.alterMTMVProperty} so that a failure (e.g. a partial IVM 
stream
+     * transition) propagates to the client instead of being swallowed; the 
replay path
+     * runs it through {@link #processAlterMTMV} where errors are tolerated.
+     */
+    public void processAlterMTMVProperty(AlterMTMV alterMTMV, boolean 
isReplay) throws UserException {
+        MTMV mtmv;
+        Database db = 
Env.getCurrentInternalCatalog().getDbOrDdlException(alterMTMV.getMvName().getDb());
+        // Fail before touching anything when the database is being dropped: a 
later step
+        // (e.g. the stream drop under the db write lock) would otherwise fail 
after the
+        // property was already applied.
+        if (db.isDropped()) {
+            throw new DdlException("unknown db, dbName=" + db.getFullName());
+        }
+        mtmv = (MTMV) 
db.getTableOrMetaException(alterMTMV.getMvName().getTbl(), 
TableType.MATERIALIZED_VIEW);
+        if (mtmv.isIvm() && alterMTMV.getMvProperties().containsKey(
+                PropertyAnalyzer.PROPERTIES_EXCLUDED_TRIGGER_TABLES)) {
+            Set<TableNameInfo> oldExcludedTriggerTables = 
mtmv.getExcludedTriggerTables();
+            Set<TableNameInfo> newExcludedTriggerTables = 
MTMVPropertyUtil.parseTableNameInfos(
+                    
alterMTMV.getMvProperties().get(PropertyAnalyzer.PROPERTIES_EXCLUDED_TRIGGER_TABLES));
+            alterIvmExcludedTriggerTables(db, mtmv, oldExcludedTriggerTables,
+                    newExcludedTriggerTables, alterMTMV, isReplay);
+            return;
+        }
+        mtmv.alterMvProperties(alterMTMV, isReplay);
+    }
+
+    private void alterIvmExcludedTriggerTables(Database db, MTMV mtmv,
+            Set<TableNameInfo> oldExcludedTriggerTables, Set<TableNameInfo> 
newExcludedTriggerTables,
+            AlterMTMV alterMTMV, boolean isReplay) throws UserException {
+        // Step 1: create streams for base tables leaving the excluded set 
(skipped on
+        // replay, each create journals itself). A mid-loop failure is 
compensated by
+        // dropping exactly the streams created here, leaving the previous 
property in
+        // effect without stray streams.
+        List<String> createdStreamNames = new ArrayList<>();
+        if (!isReplay) {
+            try {
+                createStreamsForUnExcludedTables(db, mtmv, 
oldExcludedTriggerTables,
+                        newExcludedTriggerTables, createdStreamNames);
+            } catch (UserException e) {
+                try {
+                    dropStreamsByNames(db, createdStreamNames, false);
+                } catch (UserException compensateException) {
+                    // Keep the original failure for the client; a failed 
compensation
+                    // leaves stray streams that the idempotent retry of the 
ALTER
+                    // cleans up.
+                    LOG.error("failed to compensate streams created for mv={} 
after create failure",
+                            mtmv.getName(), compensateException);
+                }
+                throw e;
+            }
+        }
+        // Step 2: apply the property, the source of truth for refresh.
+        mtmv.alterMvProperties(alterMTMV, isReplay);
+        // Step 3: drop streams of base tables that just joined the excluded 
set. This
+        // runs after the property on purpose: a failed drop then only leaks 
the stream
+        // of a table that is already excluded (harmless, and stream leaks are 
a
+        // pre-existing risk), whereas dropping first could remove the stream 
of a table
+        // that is still active under the old property.
+        try {
+            dropStreamsForExcludedTables(db, mtmv, newExcludedTriggerTables, 
isReplay);
+        } catch (UserException e) {
+            LOG.warn("failed to drop IVM streams for excluded trigger tables 
of mv={}, "
+                    + "the streams may leak: {}", mtmv.getName(), 
e.getMessage());
+        }
+    }
+
+    private void createStreamsForUnExcludedTables(Database db, MTMV mtmv,
             Set<TableNameInfo> oldExcludedTriggerTables, Set<TableNameInfo> 
newExcludedTriggerTables,
-            boolean isReplay) throws UserException {
+            List<String> createdStreamNames) throws UserException {
         MTMVRelation relation = mtmv.getRelation();
         if (relation == null || relation.getBaseTables() == null) {
             return;
         }
-        Set<BaseTableInfo> baseTables = relation.getBaseTables();
-        for (BaseTableInfo baseTableInfo : baseTables) {
+        int createdCount = 0;
+        for (BaseTableInfo baseTableInfo : relation.getBaseTables()) {
             TableNameInfo baseTableName = new 
TableNameInfo(baseTableInfo.getCtlName(),
                     baseTableInfo.getDbName(), baseTableInfo.getTableName());
-            boolean wasExcluded = MTMVPartitionUtil.isTableExcluded(
-                    oldExcludedTriggerTables, baseTableName);
-            boolean isExcluded = MTMVPartitionUtil.isTableExcluded(
-                    newExcludedTriggerTables, baseTableName);
-            if (wasExcluded && !isExcluded) {
-                if (!isReplay) {
-                    TableIf baseTable = MTMVUtil.getTable(baseTableInfo);
-                    CreateMTMVCommand.createTableStream(ConnectContext.get(), 
db, mtmv, baseTable);
+            if (!MTMVPartitionUtil.isTableExcluded(oldExcludedTriggerTables, 
baseTableName)
+                    || 
MTMVPartitionUtil.isTableExcluded(newExcludedTriggerTables, baseTableName)) {
+                continue;
+            }
+            failCreateStreamIfDebugPointed(createdCount);
+            TableIf baseTable = MTMVUtil.getTable(baseTableInfo);
+            CreateMTMVCommand.createTableStream(ConnectContext.get(), db, 
mtmv, baseTable);
+            createdStreamNames.add(IvmUtil.streamName(mtmv.getId(), 
baseTable.getFullQualifiers()));
+            createdCount++;
+        }
+    }
+
+    /** Fails before the (allowedCreates+1)-th create when the create debug 
point is enabled. */
+    private void failCreateStreamIfDebugPointed(int createdCount) throws 
DdlException {
+        String allowCreates = 
DebugPointUtil.getDebugParamOrDefault(DEBUG_POINT_CREATE_EXCLUDED_STREAM_FAIL, 
"");
+        if (!allowCreates.isEmpty() && createdCount >= 
Integer.parseInt(allowCreates)) {
+            throw new DdlException("debug point: creating IVM stream for an 
excluded-trigger base table "
+                    + "failed after " + allowCreates + " successful 
create(s)");
+        }
+    }
+
+    /** Drops the named stream tables under the db write lock; 
missing/non-stream tables are skipped. */
+    private void dropStreamsByNames(Database db, List<String> streamNames, 
boolean isReplay)
+            throws UserException {
+        if (streamNames.isEmpty()) {
+            return;
+        }
+        db.writeLockOrDdlException();
+        try {
+            for (String streamName : streamNames) {
+                TableIf streamTable = db.getTableNullable(streamName);
+                if (!(streamTable instanceof BaseTableStream)) {
+                    continue;
+                }
+                Table table = (Table) streamTable;
+                table.writeLock();
+                try {
+                    Env.getCurrentEnv().unprotectDropTable(db, table, true, 
isReplay, 0L);
+                } finally {
+                    table.writeUnlock();
                 }
+                LOG.info("dropped IVM stream {}", streamName);
             }
+        } finally {
+            db.writeUnlock();
+        }
+    }
+
+    private void dropStreamsForExcludedTables(Database db, MTMV mtmv,
+            Set<TableNameInfo> newExcludedTriggerTables, boolean isReplay) 
throws UserException {
+        MTMVRelation relation = mtmv.getRelation();
+        if (relation == null || relation.getBaseTables() == null) {
+            return;
         }
+        Set<BaseTableInfo> baseTables = relation.getBaseTables();
+        int droppedCount = 0;
         db.writeLockOrDdlException();
         try {
             for (BaseTableInfo baseTableInfo : baseTables) {
@@ -1385,6 +1502,7 @@ public class Alter {
                 if 
(!MTMVPartitionUtil.isTableExcluded(newExcludedTriggerTables, baseTableName)) {
                     continue;
                 }
+                failDropStreamIfDebugPointed(droppedCount);
                 List<String> baseTableFullQualifiers = baseTableInfo.toList();
                 String streamName = IvmUtil.streamName(mtmv.getId(), 
baseTableFullQualifiers);
                 TableIf streamTable = db.getTableNullable(streamName);
@@ -1409,9 +1527,19 @@ public class Alter {
                 }
                 LOG.info("dropped IVM stream {} because its base table is 
excluded from MTMV",
                         streamName);
+                droppedCount++;
             }
         } finally {
             db.writeUnlock();
         }
     }
+
+    /** Fails before the (allowedDrops+1)-th drop when the drop debug point is 
enabled. */
+    private void failDropStreamIfDebugPointed(int droppedCount) throws 
DdlException {
+        String allowDrops = 
DebugPointUtil.getDebugParamOrDefault(DEBUG_POINT_DROP_EXCLUDED_STREAM_FAIL, 
"");
+        if (!allowDrops.isEmpty() && droppedCount >= 
Integer.parseInt(allowDrops)) {
+            throw new DdlException("debug point: dropping an IVM stream of an 
excluded-trigger base table "
+                    + "failed after " + allowDrops + " successful drop(s)");
+        }
+    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java
index 05369b9cbd2..55d3ec15602 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java
@@ -176,6 +176,11 @@ public class Database extends MetaObject implements 
Writable, DatabaseIf<Table>,
         isDropped = false;
     }
 
+    /** True while the database is being dropped (before it is removed from 
the catalog). */
+    public boolean isDropped() {
+        return isDropped;
+    }
+
     public void readLock() {
         this.rwLock.readLock().lock();
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
index 50151ddb08f..51833705acf 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
@@ -7658,10 +7658,12 @@ public class Env {
         this.alter.processAlterMTMV(alter, false);
     }
 
-    public void alterMTMVProperty(AlterMTMVPropertyInfo info) {
+    public void alterMTMVProperty(AlterMTMVPropertyInfo info) throws 
UserException {
         AlterMTMV alter = new AlterMTMV(info.getMvName(), 
MTMVAlterOpType.ALTER_PROPERTY);
         alter.setMvProperties(info.getProperties());
-        this.alter.processAlterMTMV(alter, false);
+        // Runs outside the tolerant processAlterMTMV catch so that failures 
(e.g. a
+        // partial IVM excluded-trigger-tables stream transition) reach the 
client.
+        this.alter.processAlterMTMVProperty(alter, false);
     }
 
     public void alterMTMVStatus(TableNameInfo mvName, MTMVStatus status) {
diff --git a/fe/fe-core/src/test/java/org/apache/doris/mtmv/AlterMTMVTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/mtmv/AlterMTMVTest.java
index ab525e44ecc..deeed90db1d 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/mtmv/AlterMTMVTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/mtmv/AlterMTMVTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.mtmv;
 
+import org.apache.doris.alter.Alter;
 import org.apache.doris.catalog.Database;
 import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.MTMV;
@@ -24,6 +25,7 @@ import org.apache.doris.catalog.Table;
 import org.apache.doris.catalog.info.TableNameInfo;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.DdlException;
+import org.apache.doris.common.util.DebugPointUtil;
 import org.apache.doris.mtmv.MTMVRefreshEnum.RefreshMethod;
 import org.apache.doris.mtmv.ivm.IvmInfo;
 import org.apache.doris.mtmv.ivm.IvmUtil;
@@ -624,4 +626,107 @@ public class AlterMTMVTest extends TestWithFeService {
         alterMv("ALTER MATERIALIZED VIEW owner_mv SET 
('excluded_trigger_tables' = 'owner_base1')");
         Assertions.assertSame(conflictingStream, 
db.getTableOrMetaException(streamName));
     }
+
+    @Test
+    public void 
testAlterIvmExcludedTriggerTablesCreateStreamFailureCompensatesAndFails() 
throws Exception {
+        createDatabaseAndUse("alter_ivm_excl_create_fail_test");
+        createTable("CREATE TABLE excl_fail_base1 (k1 int, v1 int) UNIQUE 
KEY(k1) "
+                + "DISTRIBUTED BY HASH(k1) BUCKETS 1 "
+                + "PROPERTIES ('replication_num' = '1', 
'enable_unique_key_merge_on_write' = 'true', "
+                + "'binlog.enable' = 'true', 'binlog.format' = 'ROW', "
+                + "'binlog.need_historical_value' = 'true')");
+        createTable("CREATE TABLE excl_fail_base2 (k1 int, v1 int) UNIQUE 
KEY(k1) "
+                + "DISTRIBUTED BY HASH(k1) BUCKETS 1 "
+                + "PROPERTIES ('replication_num' = '1', 
'enable_unique_key_merge_on_write' = 'true', "
+                + "'binlog.enable' = 'true', 'binlog.format' = 'ROW', "
+                + "'binlog.need_historical_value' = 'true')");
+        createMvByNereids("CREATE MATERIALIZED VIEW excl_create_fail_mv\n"
+                + " BUILD DEFERRED REFRESH INCREMENTAL ON MANUAL\n"
+                + " DISTRIBUTED BY RANDOM BUCKETS 2\n"
+                + " PROPERTIES ('replication_num' = '1',\n"
+                + "   'excluded_trigger_tables' = 'excl_fail_base1, 
excl_fail_base2')\n"
+                + " AS SELECT k1, v1 FROM excl_fail_base1 UNION ALL SELECT k1, 
v1 FROM excl_fail_base2");
+
+        Database db = 
Env.getCurrentInternalCatalog().getDbOrDdlException("alter_ivm_excl_create_fail_test");
+        MTMV mtmv = (MTMV) db.getTableOrMetaException("excl_create_fail_mv");
+        String stream1 = ivmStreamName(db, mtmv.getId(), "excl_fail_base1");
+        String stream2 = ivmStreamName(db, mtmv.getId(), "excl_fail_base2");
+        Assertions.assertFalse(db.getTable(stream1).isPresent());
+        Assertions.assertFalse(db.getTable(stream2).isPresent());
+
+        boolean originEnableDebugPoints = Config.enable_debug_points;
+        try {
+            Config.enable_debug_points = true;
+            DebugPointUtil.clearDebugPoints();
+            // Allow the first stream create to succeed and fail the second 
one (the count
+            // makes this independent of the base-table iteration order), so 
the
+            // compensation must drop the first stream again.
+            DebugPointUtil.addDebugPointWithValue(
+                    Alter.DEBUG_POINT_CREATE_EXCLUDED_STREAM_FAIL, "1");
+            Exception exception = Assertions.assertThrows(Exception.class,
+                    () -> alterMv("ALTER MATERIALIZED VIEW 
excl_create_fail_mv\n"
+                            + " SET ('excluded_trigger_tables' = '')"));
+            Assertions.assertTrue(exception.getMessage().contains("debug 
point"),
+                    "unexpected error message: " + exception.getMessage());
+        } finally {
+            DebugPointUtil.clearDebugPoints();
+            Config.enable_debug_points = originEnableDebugPoints;
+        }
+
+        // Compensated: no stream remains and the property still excludes both 
tables.
+        Assertions.assertFalse(db.getTable(stream1).isPresent(),
+                "compensation must drop the stream created before the failing 
one");
+        Assertions.assertFalse(db.getTable(stream2).isPresent());
+        Assertions.assertEquals(2, mtmv.getExcludedTriggerTables().size());
+    }
+
+    @Test
+    public void 
testAlterIvmExcludedTriggerTablesDropStreamFailureIsBestEffort() throws 
Exception {
+        createDatabaseAndUse("alter_ivm_excl_drop_fail_test");
+        createTable("CREATE TABLE excl_drop_base1 (k1 int, v1 int) UNIQUE 
KEY(k1) "
+                + "DISTRIBUTED BY HASH(k1) BUCKETS 1 "
+                + "PROPERTIES ('replication_num' = '1', 
'enable_unique_key_merge_on_write' = 'true', "
+                + "'binlog.enable' = 'true', 'binlog.format' = 'ROW', "
+                + "'binlog.need_historical_value' = 'true')");
+        createTable("CREATE TABLE excl_drop_base2 (k1 int, v1 int) UNIQUE 
KEY(k1) "
+                + "DISTRIBUTED BY HASH(k1) BUCKETS 1 "
+                + "PROPERTIES ('replication_num' = '1', 
'enable_unique_key_merge_on_write' = 'true', "
+                + "'binlog.enable' = 'true', 'binlog.format' = 'ROW', "
+                + "'binlog.need_historical_value' = 'true')");
+        createMvByNereids("CREATE MATERIALIZED VIEW excl_drop_fail_mv\n"
+                + " BUILD DEFERRED REFRESH INCREMENTAL ON MANUAL\n"
+                + " DISTRIBUTED BY RANDOM BUCKETS 2\n"
+                + " PROPERTIES ('replication_num' = '1')\n"
+                + " AS SELECT k1, v1 FROM excl_drop_base1 UNION ALL SELECT k1, 
v1 FROM excl_drop_base2");
+
+        Database db = 
Env.getCurrentInternalCatalog().getDbOrDdlException("alter_ivm_excl_drop_fail_test");
+        MTMV mtmv = (MTMV) db.getTableOrMetaException("excl_drop_fail_mv");
+        String stream1 = ivmStreamName(db, mtmv.getId(), "excl_drop_base1");
+        String stream2 = ivmStreamName(db, mtmv.getId(), "excl_drop_base2");
+        Assertions.assertTrue(db.getTable(stream1).isPresent());
+        Assertions.assertTrue(db.getTable(stream2).isPresent());
+
+        boolean originEnableDebugPoints = Config.enable_debug_points;
+        try {
+            Config.enable_debug_points = true;
+            DebugPointUtil.clearDebugPoints();
+            // Both bases join the excluded set; allow one stream drop to 
succeed and fail
+            // the next one (the count makes this independent of the 
base-table iteration
+            // order). The property is already applied and the ALTER must 
still succeed:
+            // exactly one of the two now-unused streams leaks.
+            DebugPointUtil.addDebugPointWithValue(
+                    Alter.DEBUG_POINT_DROP_EXCLUDED_STREAM_FAIL, "1");
+            alterMv("ALTER MATERIALIZED VIEW excl_drop_fail_mv\n"
+                    + " SET ('excluded_trigger_tables' = 'excl_drop_base1, 
excl_drop_base2')");
+        } finally {
+            DebugPointUtil.clearDebugPoints();
+            Config.enable_debug_points = originEnableDebugPoints;
+        }
+
+        Assertions.assertEquals(2, mtmv.getExcludedTriggerTables().size());
+        boolean stream1Present = db.getTable(stream1).isPresent();
+        boolean stream2Present = db.getTable(stream2).isPresent();
+        Assertions.assertEquals(1, (stream1Present ? 1 : 0) + (stream2Present 
? 1 : 0),
+                "exactly one stream drop must have failed and leaked");
+    }
 }


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

Reply via email to