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

lincoln-lil pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink.git


The following commit(s) were added to refs/heads/master by this push:
     new a417739e30e [FLINK-40153][table] Fix resolving inherited metadata 
columns used by watermarks in LIKE clause
a417739e30e is described below

commit a417739e30e1fa2f40554619c9b35543f2b4d69e
Author: lincoln lee <[email protected]>
AuthorDate: Fri Jul 17 14:20:20 2026 +0800

    [FLINK-40153][table] Fix resolving inherited metadata columns used by 
watermarks in LIKE clause
    
    This closes #28750.
---
 .../operations/converters/MergeTableLikeUtil.java  |  6 ++++
 .../converters/MergeTableLikeUtilTest.java         | 33 ++++++++++++++++++++
 .../planner/plan/stream/sql/TableScanTest.xml      | 22 +++++++++++++
 .../planner/plan/stream/sql/TableScanTest.scala    | 36 ++++++++++++++++++++++
 4 files changed, 97 insertions(+)

diff --git 
a/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/operations/converters/MergeTableLikeUtil.java
 
b/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/operations/converters/MergeTableLikeUtil.java
index a5d722282fd..93676ee49e0 100644
--- 
a/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/operations/converters/MergeTableLikeUtil.java
+++ 
b/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/operations/converters/MergeTableLikeUtil.java
@@ -282,6 +282,12 @@ public class MergeTableLikeUtil {
                 } else if (sourceColumn instanceof UnresolvedMetadataColumn) {
                     if (mergingStrategies.get(FeatureOption.METADATA)
                             != MergingStrategy.EXCLUDING) {
+                        UnresolvedMetadataColumn metadataColumn =
+                                (UnresolvedMetadataColumn) sourceColumn;
+                        LogicalType columnType = 
getLogicalType(dataTypeFactory, metadataColumn);
+                        metadataFieldNamesToTypes.put(
+                                sourceColumn.getName(),
+                                
typeFactory.createFieldTypeFromLogicalType(columnType));
                         columns.put(sourceColumn.getName(), sourceColumn);
                     }
                 }
diff --git 
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/operations/converters/MergeTableLikeUtilTest.java
 
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/operations/converters/MergeTableLikeUtilTest.java
index bdd39709ebd..b7e8ad06743 100644
--- 
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/operations/converters/MergeTableLikeUtilTest.java
+++ 
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/operations/converters/MergeTableLikeUtilTest.java
@@ -507,6 +507,39 @@ class MergeTableLikeUtilTest {
         assertThat(mergedSchema).isEqualTo(expectedSchema);
     }
 
+    @Test
+    void mergeWatermarkReferencingInheritedMetadataColumn() {
+        Schema sourceSchema =
+                Schema.newBuilder()
+                        .column("timestamp", DataTypes.TIMESTAMP(3))
+                        .columnByMetadata("opts", DataTypes.TIMESTAMP(3), true)
+                        .watermark("timestamp", "timestamp")
+                        .build();
+
+        List<SqlWatermark> derivedWatermarkSpecs =
+                List.of(
+                        new SqlWatermark(
+                                SqlParserPos.ZERO,
+                                identifier("opts"),
+                                boundedStrategy("opts", "5")));
+
+        Map<FeatureOption, MergingStrategy> mergingStrategies = 
getDefaultMergingStrategies();
+        mergingStrategies.put(FeatureOption.WATERMARKS, 
MergingStrategy.EXCLUDING);
+
+        Schema mergedSchema =
+                util.mergeTables(
+                        mergingStrategies, sourceSchema, List.of(), 
derivedWatermarkSpecs, null);
+
+        Schema expectedSchema =
+                Schema.newBuilder()
+                        .column("timestamp", DataTypes.TIMESTAMP(3))
+                        .columnByMetadata("opts", DataTypes.TIMESTAMP(3), true)
+                        .watermark("opts", "`opts` - INTERVAL '5' SECOND")
+                        .build();
+
+        assertThat(mergedSchema).isEqualTo(expectedSchema);
+    }
+
     @Test
     void mergeIncludingWatermarksFailsOnDuplicate() {
         Schema sourceSchema =
diff --git 
a/flink-table/flink-table-planner/src/test/resources/org/apache/flink/table/planner/plan/stream/sql/TableScanTest.xml
 
b/flink-table/flink-table-planner/src/test/resources/org/apache/flink/table/planner/plan/stream/sql/TableScanTest.xml
index adf7dd0d612..9a1909432cd 100644
--- 
a/flink-table/flink-table-planner/src/test/resources/org/apache/flink/table/planner/plan/stream/sql/TableScanTest.xml
+++ 
b/flink-table/flink-table-planner/src/test/resources/org/apache/flink/table/planner/plan/stream/sql/TableScanTest.xml
@@ -102,6 +102,28 @@ Calc(select=[a, b, c], changelogMode=[I,UA,D])
             +- Calc(select=[id, a, +(a, 1) AS b, c, TO_TIMESTAMP(c) AS ts], 
changelogMode=[I,UA,D])
                +- DropUpdateBefore(changelogMode=[I,UA,D])
                   +- TableSourceScan(table=[[default_catalog, 
default_database, src]], fields=[id, a, c], changelogMode=[I,UB,UA,D])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testCreateTableLikeWithWatermarkReferencingMetadataColumn">
+    <Resource name="sql">
+      <![CDATA[INSERT INTO SinkTable SELECT `ts`, `opts` FROM 
LikeSourceWithWatermark]]>
+    </Resource>
+    <Resource name="ast">
+      <![CDATA[
+LogicalSink(table=[default_catalog.default_database.SinkTable], fields=[ts, 
opts])
++- LogicalProject(ts=[$0], opts=[$1])
+   +- LogicalWatermarkAssigner(rowtime=[opts], watermark=[-($1, 5000:INTERVAL 
SECOND)])
+      +- LogicalProject(ts=[$0], opts=[CAST($1):TIMESTAMP(3) *ROWTIME*])
+         +- LogicalTableScan(table=[[default_catalog, default_database, 
LikeSourceWithWatermark, metadata=[opts]]])
+]]>
+    </Resource>
+    <Resource name="optimized exec plan">
+      <![CDATA[
+Sink(table=[default_catalog.default_database.SinkTable], fields=[ts, opts])
++- WatermarkAssigner(rowtime=[opts], watermark=[(opts - 5000:INTERVAL SECOND)])
+   +- Calc(select=[ts, CAST(opts AS TIMESTAMP(3) *ROWTIME*) AS opts])
+      +- TableSourceScan(table=[[default_catalog, default_database, 
LikeSourceWithWatermark, metadata=[opts]]], fields=[ts, opts])
 ]]>
     </Resource>
   </TestCase>
diff --git 
a/flink-table/flink-table-planner/src/test/scala/org/apache/flink/table/planner/plan/stream/sql/TableScanTest.scala
 
b/flink-table/flink-table-planner/src/test/scala/org/apache/flink/table/planner/plan/stream/sql/TableScanTest.scala
index ea905662a42..60f39645d10 100644
--- 
a/flink-table/flink-table-planner/src/test/scala/org/apache/flink/table/planner/plan/stream/sql/TableScanTest.scala
+++ 
b/flink-table/flink-table-planner/src/test/scala/org/apache/flink/table/planner/plan/stream/sql/TableScanTest.scala
@@ -146,6 +146,42 @@ class TableScanTest extends TableTestBase {
     util.verifyExecPlan("SELECT `b`, `other_metadata` FROM MetadataTable")
   }
 
+  @Test
+  def testCreateTableLikeWithWatermarkReferencingMetadataColumn(): Unit = {
+    util.tableEnv.executeSql("""
+                               |CREATE TABLE LikeSourceTable (
+                               |  `ts` TIMESTAMP(3),
+                               |  `opts` TIMESTAMP(3) METADATA VIRTUAL,
+                               |  WATERMARK FOR `ts` AS `ts`
+                               |) WITH (
+                               |  'connector' = 'values',
+                               |  'readable-metadata' = 'opts:TIMESTAMP(3)'
+                               |)
+                               |""".stripMargin)
+
+    util.tableEnv.executeSql("""
+                               |CREATE TABLE LikeSourceWithWatermark (
+                               |  WATERMARK FOR `opts`
+                               |    AS `opts` - INTERVAL '5' SECOND
+                               |) LIKE LikeSourceTable (
+                               |  EXCLUDING WATERMARKS
+                               |)
+                               |""".stripMargin)
+
+    util.tableEnv.executeSql("""
+                               |CREATE TABLE SinkTable (
+                               |  `ts` TIMESTAMP(3),
+                               |  `opts` TIMESTAMP(3)
+                               |) WITH (
+                               |  'connector' = 'values'
+                               |)
+                               |""".stripMargin)
+
+    util.verifyExecPlanInsert(
+      "INSERT INTO SinkTable " +
+        "SELECT `ts`, `opts` FROM LikeSourceWithWatermark")
+  }
+
   @Test
   def testDDLWithWatermarkComputedColumn(): Unit = {
     // Create table with field as atom expression.

Reply via email to