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

morningman 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 c6fd85b28b0 [test](iceberg) Port the branch-4.1 schema matrix 
assertions for joins, branch reads and DESC comments (#69552)
c6fd85b28b0 is described below

commit c6fd85b28b0dff0c762b55307318269aadbe8eee
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Sun Oct 25 11:01:00 2026 +0000

    [test](iceberg) Port the branch-4.1 schema matrix assertions for joins, 
branch reads and DESC comments (#69552)
    
    ### What problem does this PR solve?
    
    Issue Number: None
    
    Related PR: #66246, #66007, #66112
    
    Problem Summary:
    
    **In short.** This ports test assertions from branch-4.1 #66246 that
    master never got. #66246 backported #66112, #66223 and #66007 to
    branch-4.1 and added checks for historical joins, branch reads and DESC
    comments on Iceberg tables. Master already behaves as those checks
    expect, but its suites either lack them or still assert the old,
    negative contract. No production code changes.
    
    **Background.** An audit of every block of #66246 that branch-4.2 still
    has, against master, found these test gaps. Everything else in #66246 is
    on master in another form (mostly in the connector plugins) or was
    replaced on master. One behavior differs on purpose: a plain Hudi read
    on master is not pinned to the instant seen at analysis (#64304). This
    PR leaves that alone.
    
    **The problem, and what it cost.** Without the checks, a regression in
    these paths would go unnoticed, and two suites still describe the
    current behavior as a defect:
    
    | Suite | Master today | After this PR |
    |---|---|---|
    | `test_iceberg_schema_dual_relation_matrix` | no check that a
    historical relation and the latest relation of the same table keep their
    own schemas in one join | both join orders checked: `old_name` on the
    snapshot, `new_name` on the latest table |
    | `test_iceberg_schema_time_travel_matrix` | branch reads checked only
    as "negative contracts": the old name is unknown, nested types are
    promoted | a branch read uses the table's current schema; renamed and
    re-added fields read NULL from the branch head (`qt_`, same rows as
    branch-4.2) |
    | `test_iceberg_schema_metadata_atomicity_matrix` | asserts that DESC
    omits Iceberg field comments, which only holds because
    `show_column_comment_in_describe` is off by default | enables the
    variable and asserts that DESC shows the top-level and nested comments |
    | `CreateTableCommandTest` | #67545 replaced the "existing CTAS target
    fails before any sink is built" case with the configuration preflight
    case | the existing-target case is back, next to the preflight case |
    
    **How this PR fixes it.**
    
    - `test_iceberg_schema_dual_relation_matrix` gets the two joins from
    branch-4.2, written with `assertEquals` like the rest of the master
    suite.
    - `test_iceberg_schema_time_travel_matrix` keeps master's checks,
    rewords their comments, and adds `qt_doris_nested_branch_current_schema`
    and `qt_top_branch_current_schema` from branch-4.2, with a new `.out`.
    - `test_iceberg_schema_metadata_atomicity_matrix` sets
    `show_column_comment_in_describe=true` and asserts that the comments are
    shown, as on branch-4.2.
    -
    `CreateTableCommandTest#existingCtasTargetPrecedesUnsupportedSinkValidation`
    comes from branch-4.2. On master the configuration preflight runs first,
    so the test stubs it to pass.
    
    **Results.** On a local cluster built from master with the Iceberg
    docker environment, the three suites pass. The `.out` is generated by
    the regression script and has the same rows as branch-4.2. All 4 cases
    of `CreateTableCommandTest` pass, and checkstyle passes.
    
    Co-authored-by: Gabriel <[email protected]>
---
 .../plans/commands/CreateTableCommandTest.java     | 34 ++++++++++++++++++++++
 .../test_iceberg_schema_time_travel_matrix.out     |  7 +++++
 ...test_iceberg_schema_dual_relation_matrix.groovy | 16 ++++++++++
 ...iceberg_schema_metadata_atomicity_matrix.groovy |  7 +++--
 .../test_iceberg_schema_time_travel_matrix.groovy  | 19 ++++++++++--
 5 files changed, 78 insertions(+), 5 deletions(-)

diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommandTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommandTest.java
index 5e502220dcd..0f8113bfc3a 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommandTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommandTest.java
@@ -100,6 +100,40 @@ class CreateTableCommandTest {
         }
     }
 
+    @Test
+    void existingCtasTargetPrecedesUnsupportedSinkValidation() throws 
Exception {
+        LogicalPlan query = Mockito.mock(LogicalPlan.class);
+        CreateTableInfo createTableInfo = Mockito.mock(CreateTableInfo.class);
+        ConnectContext context = Mockito.mock(ConnectContext.class);
+        StmtExecutor executor = Mockito.mock(StmtExecutor.class);
+        Env env = Mockito.mock(Env.class);
+        List<String> tableNameParts = ImmutableList.of("catalog", "database", 
"target");
+
+        
Mockito.when(createTableInfo.getTableNameParts()).thenReturn(tableNameParts);
+        Mockito.when(createTableInfo.getTableName()).thenReturn("target");
+        CreateTableCommand command = Mockito.spy(
+                new CreateTableCommand(Optional.of(query), createTableInfo));
+        Mockito.doNothing().when(command).validateCreateTableAsSelect(context, 
query);
+        
Mockito.doNothing().when(command).validateCreateTableProperties(context);
+        Mockito.doReturn(true).when(command).targetTableExists(context);
+
+        try (MockedStatic<Env> envMock = Mockito.mockStatic(Env.class);
+                MockedStatic<UnboundTableSinkCreator> sinkMock =
+                        Mockito.mockStatic(UnboundTableSinkCreator.class)) {
+            envMock.when(Env::getCurrentEnv).thenReturn(env);
+            Exception exception = 
org.junit.jupiter.api.Assertions.assertThrows(
+                    Exception.class, () -> command.run(context, executor));
+
+            
org.junit.jupiter.api.Assertions.assertTrue(exception.getMessage().contains("already
 exists"));
+            sinkMock.verifyNoInteractions();
+            Mockito.verify(env, Mockito.never()).createTable(createTableInfo);
+            Mockito.verify(env, Mockito.never()).dropTable(
+                    Mockito.anyString(), Mockito.anyString(), 
Mockito.anyString(),
+                    Mockito.anyBoolean(), Mockito.anyBoolean(), 
Mockito.anyBoolean(),
+                    Mockito.anyBoolean(), Mockito.anyBoolean(), 
Mockito.anyBoolean());
+        }
+    }
+
     @Test
     void ctasConfigurationPreflightPrecedesTargetLookup() throws Exception {
         LogicalPlan query = Mockito.mock(LogicalPlan.class);
diff --git 
a/regression-test/data/external_table_p0/iceberg/test_iceberg_schema_time_travel_matrix.out
 
b/regression-test/data/external_table_p0/iceberg/test_iceberg_schema_time_travel_matrix.out
new file mode 100644
index 00000000000..bf4a957a123
--- /dev/null
+++ 
b/regression-test/data/external_table_p0/iceberg/test_iceberg_schema_time_travel_matrix.out
@@ -0,0 +1,7 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !doris_nested_branch_current_schema --
+1      10      \N      100     \N      1000    \N
+
+-- !top_branch_current_schema --
+1      alpha   \N      10
+
diff --git 
a/regression-test/suites/external_table_p0/iceberg/test_iceberg_schema_dual_relation_matrix.groovy
 
b/regression-test/suites/external_table_p0/iceberg/test_iceberg_schema_dual_relation_matrix.groovy
index 3dddfe69b87..db60c79d1d3 100644
--- 
a/regression-test/suites/external_table_p0/iceberg/test_iceberg_schema_dual_relation_matrix.groovy
+++ 
b/regression-test/suites/external_table_p0/iceberg/test_iceberg_schema_dual_relation_matrix.groovy
@@ -93,6 +93,22 @@ suite("test_iceberg_schema_dual_relation_matrix",
             order by id
         """))
 
+        // Latest metadata must be restored even when a historical relation is 
bound first.
+        assertEquals([[1, "old-1", "old-1"]], sql("""
+            select h.id, h.old_name, l.new_name
+            from ${tableName} for version as of ${oldSnapshot} h
+            join ${tableName} l on h.id = l.id
+            order by h.id
+        """))
+
+        // Binding the same pair in reverse order must preserve both 
relation-local schemas.
+        assertEquals([[1, "old-1", "old-1"]], sql("""
+            select l.id, l.new_name, h.old_name
+            from ${tableName} l
+            join ${tableName} for version as of ${oldSnapshot} h on l.id = h.id
+            order by l.id
+        """))
+
         // Scenario TC07-join: each historical relation binds and scans its 
OWN snapshot schema, so a
         // self-join across the rename resolves old_name (old snapshot) and 
new_name (new snapshot).
         assertEquals([[1, "old-1", "old-1"]], sql("""
diff --git 
a/regression-test/suites/external_table_p0/iceberg/test_iceberg_schema_metadata_atomicity_matrix.groovy
 
b/regression-test/suites/external_table_p0/iceberg/test_iceberg_schema_metadata_atomicity_matrix.groovy
index 14fc7771089..365d4a58b1a 100644
--- 
a/regression-test/suites/external_table_p0/iceberg/test_iceberg_schema_metadata_atomicity_matrix.groovy
+++ 
b/regression-test/suites/external_table_p0/iceberg/test_iceberg_schema_metadata_atomicity_matrix.groovy
@@ -58,6 +58,8 @@ suite("test_iceberg_schema_metadata_atomicity_matrix",
     sql """switch ${catalogName}"""
     sql """create database if not exists ${dbName}"""
     sql """use ${dbName}"""
+    // DESC hides comments by default, so enable them before validating 
Iceberg field docs.
+    sql """set show_column_comment_in_describe=true"""
 
     try {
         sql """drop table if exists ${tableName}"""
@@ -89,9 +91,8 @@ suite("test_iceberg_schema_metadata_atomicity_matrix",
             it == null ? "" : it.toString()
         }.join(" ")
         assertTrue(sparkDescriptionText.contains("top-level-comment"))
-        // Negative contract: Doris DESC currently omits Iceberg field 
comments.
-        assertFalse(descAfterComment.contains("top-level-comment"))
-        assertFalse(descAfterComment.contains("nested-comment"))
+        assertTrue(descAfterComment.contains("top-level-comment"))
+        assertTrue(descAfterComment.contains("nested-comment"))
         assertEquals(initialSnapshots, snapshotCount())
 
         // Scenario S19-nullability: relaxing required to optional preserves 
data and historical refs.
diff --git 
a/regression-test/suites/external_table_p0/iceberg/test_iceberg_schema_time_travel_matrix.groovy
 
b/regression-test/suites/external_table_p0/iceberg/test_iceberg_schema_time_travel_matrix.groovy
index dffbc236ea7..67e944ff3df 100644
--- 
a/regression-test/suites/external_table_p0/iceberg/test_iceberg_schema_time_travel_matrix.groovy
+++ 
b/regression-test/suites/external_table_p0/iceberg/test_iceberg_schema_time_travel_matrix.groovy
@@ -443,13 +443,22 @@ suite("test_iceberg_schema_time_travel_matrix",
                     from ${dorisNestedTable}@tag(doris_nested_cp0)
                     order by id
                 """))
-        // Negative contract: an old branch currently leaks the latest BIGINT 
nested types.
+        // A branch read uses the table's current schema, so an old branch 
reads the promoted BIGINT
+        // nested types.
         assertEquals([[1, 10L, 100L, 1000L]],
                 sql("""
                     select id, info.metric, events[1].score, attrs['k'].code
                     from ${dorisNestedTable}@branch(doris_nested_cp0_branch)
                     order by id
                 """))
+        // Named branches keep their head rows but expose renamed fields from 
the current schema.
+        qt_doris_nested_branch_current_schema """
+            select id, info.metric, info.renamed,
+                   events[1].score, events[1].renamed,
+                   attrs['k'].code, attrs['k'].renamed
+            from ${dorisNestedTable}@branch(doris_nested_cp0_branch)
+            order by id
+        """
         assertUnknownColumn("""
             select info.renamed
             from ${dorisNestedTable} for version as of ${dorisNestedCp0}
@@ -546,7 +555,8 @@ suite("test_iceberg_schema_time_travel_matrix",
             from ${topTable}@tag(top_cp0)
             order by id
         """))
-        // Negative contract: an old branch is currently analyzed with the 
latest rename schema.
+        // A branch read uses the table's current schema, so the old name is 
unknown on an old branch
+        // and the current names read the branch head rows.
         test {
             sql """
                 select id, old_name, victim, metric
@@ -555,6 +565,11 @@ suite("test_iceberg_schema_time_travel_matrix",
             """
             exception "Unknown column 'old_name'"
         }
+        qt_top_branch_current_schema """
+            select id, MixedName, victim, metric
+            from ${topTable}@branch(top_cp0_branch)
+            order by id
+        """
         assertUnknownColumn("""
             select MixedName from ${topTable} for version as of ${topCp0}
         """, "MixedName")


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

Reply via email to