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

ashrigondekar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new 0bc3f740c9ee [SPARK-56453][SS] Add ResolveEventTimeWatermark to 
HiveSessionStateBuilder
0bc3f740c9ee is described below

commit 0bc3f740c9ee44602a1d9bfe06ceb10bce533e36
Author: ericm-db <[email protected]>
AuthorDate: Sun Apr 12 11:46:45 2026 -0700

    [SPARK-56453][SS] Add ResolveEventTimeWatermark to HiveSessionStateBuilder
    
    ### What changes were proposed in this pull request?
    
    Add `ResolveEventTimeWatermark` to the `extendedResolutionRules` in 
`HiveSessionStateBuilder`.
    
    `BaseSessionStateBuilder` already includes this rule, but 
`HiveSessionStateBuilder` overrides `extendedResolutionRules` entirely without 
including it. This causes `UnresolvedEventTimeWatermark` nodes (which have 
`output = Nil`) to persist through analysis when using the Hive session state, 
blocking column resolution in downstream operators such as JOIN conditions and 
WHERE/ORDER BY clauses that reference aliased STREAM WATERMARK relations.
    
    ### Why are the changes needed?
    
    This is a regression introduced by #52428 (SPARK-53477), which added 
`ResolveEventTimeWatermark` to 
`BaseSessionStateBuilder.extendedResolutionRules` but missed that 
`HiveSessionStateBuilder` overrides that list entirely. When a query uses 
`STREAM(...) WATERMARK ... <alias>` syntax with the Hive session state, the 
`UnresolvedEventTimeWatermark` node is never resolved, causing 
`UNRESOLVED_COLUMN` errors when referencing columns through the alias.
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes. Streaming SQL queries using `WATERMARK` with table aliases now resolve 
correctly when using the Hive session state, fixing `UNRESOLVED_COLUMN` errors.
    
    ### How was this patch tested?
    
    Added `WatermarkColumnResolutionSuite` with three test cases:
    - STREAM JOIN with WATERMARK and alias resolves columns correctly
    - STREAM with WATERMARK and alias resolves columns in WHERE
    - STREAM with WATERMARK and alias resolves columns in ORDER BY
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Claude Opus 4.6)
    
    Closes #55312 from ericm-db/watermark-hive-resolution.
    
    Authored-by: ericm-db <[email protected]>
    Signed-off-by: Anish Shrigondekar <[email protected]>
---
 .../spark/sql/hive/HiveSessionStateBuilder.scala   |  3 +-
 .../streaming/WatermarkColumnResolutionSuite.scala | 95 ++++++++++++++++++++++
 2 files changed, 97 insertions(+), 1 deletion(-)

diff --git 
a/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveSessionStateBuilder.scala
 
b/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveSessionStateBuilder.scala
index 9f5566407e38..0fbc41492e00 100644
--- 
a/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveSessionStateBuilder.scala
+++ 
b/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveSessionStateBuilder.scala
@@ -25,7 +25,7 @@ import org.apache.hadoop.hive.ql.exec.{UDAF, UDF}
 import org.apache.hadoop.hive.ql.udf.generic.{AbstractGenericUDAFResolver, 
GenericUDF, GenericUDTF}
 
 import org.apache.spark.sql.AnalysisException
-import org.apache.spark.sql.catalyst.analysis.{Analyzer, 
EvalSubqueriesForTimeTravel, InvokeProcedures, ReplaceCharWithVarchar, 
ResolveDataSource, ResolveExecuteImmediate, ResolveMetricView, 
ResolveSessionCatalog, ResolveTranspose}
+import org.apache.spark.sql.catalyst.analysis.{Analyzer, 
EvalSubqueriesForTimeTravel, InvokeProcedures, ReplaceCharWithVarchar, 
ResolveDataSource, ResolveEventTimeWatermark, ResolveExecuteImmediate, 
ResolveMetricView, ResolveSessionCatalog, ResolveTranspose}
 import org.apache.spark.sql.catalyst.analysis.resolver.ResolverExtension
 import org.apache.spark.sql.catalyst.catalog.{ExternalCatalogWithListener, 
InvalidUDFClassException}
 import org.apache.spark.sql.catalyst.expressions.{Expression, 
ExtractSemiStructuredFields}
@@ -136,6 +136,7 @@ class HiveSessionStateBuilder(
         new InvokeProcedures(session) +:
         ResolveExecuteImmediate(session, catalogManager) +:
         ExtractSemiStructuredFields +:
+        ResolveEventTimeWatermark +:
         customResolutionRules
 
     override val postHocResolutionRules: Seq[Rule[LogicalPlan]] =
diff --git 
a/sql/hive/src/test/scala/org/apache/spark/sql/execution/streaming/WatermarkColumnResolutionSuite.scala
 
b/sql/hive/src/test/scala/org/apache/spark/sql/execution/streaming/WatermarkColumnResolutionSuite.scala
new file mode 100644
index 000000000000..577e0ca72f8d
--- /dev/null
+++ 
b/sql/hive/src/test/scala/org/apache/spark/sql/execution/streaming/WatermarkColumnResolutionSuite.scala
@@ -0,0 +1,95 @@
+/*
+ * 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.spark.sql.execution.streaming
+
+import org.apache.spark.sql.QueryTest
+import org.apache.spark.sql.hive.test.TestHiveSingleton
+import org.apache.spark.sql.test.SQLTestUtils
+
+/**
+ * Regression tests for ResolveEventTimeWatermark in HiveSessionStateBuilder.
+ *
+ * SPARK-53687 introduced UnresolvedEventTimeWatermark / 
ResolveEventTimeWatermark but only
+ * added the rule to BaseSessionStateBuilder, missing HiveSessionStateBuilder 
(used in all
+ * Databricks production environments). Without the rule, 
UnresolvedEventTimeWatermark
+ * (output=Nil) persists through analysis, breaking any SQL query that uses 
the WATERMARK clause.
+ *
+ * Uses TestHiveSingleton to go through HiveSessionStateBuilder, matching 
production behavior.
+ */
+class WatermarkColumnResolutionSuite extends QueryTest with TestHiveSingleton 
with SQLTestUtils {
+
+  private def createTestTables(): Unit = {
+    sql("CREATE TABLE IF NOT EXISTS wm_signup_details " +
+      "(updated_at TIMESTAMP, consumer_profile_id INT) USING PARQUET")
+    sql("CREATE TABLE IF NOT EXISTS wm_profiles " +
+      "(updated_at TIMESTAMP, id INT) USING PARQUET")
+    sql("CREATE TABLE IF NOT EXISTS wm_events " +
+      "(ts TIMESTAMP, a INT) USING PARQUET")
+  }
+
+  private def analyzeStreamSQL(query: String): Unit = {
+    val plan = spark.sessionState.sqlParser.parsePlan(query)
+    val analyzed = spark.sessionState.analyzer.execute(plan)
+    spark.sessionState.analyzer.checkAnalysis(analyzed)
+  }
+
+  test("STREAM JOIN with WATERMARK and alias resolves columns correctly") {
+    createTestTables()
+    analyzeStreamSQL(
+      """
+        |SELECT *
+        |FROM
+        |  STREAM(wm_signup_details) WATERMARK updated_at DELAY OF INTERVAL 60 
SECONDS d
+        |JOIN
+        |  STREAM(wm_profiles) WATERMARK updated_at DELAY OF INTERVAL 60 
SECONDS p
+        |ON d.consumer_profile_id = p.id
+        |  AND d.updated_at BETWEEN p.updated_at - INTERVAL '24 hours' AND 
p.updated_at
+        |""".stripMargin)
+  }
+
+  test("STREAM with WATERMARK and alias resolves columns in WHERE") {
+    createTestTables()
+    analyzeStreamSQL(
+      """
+        |SELECT *
+        |FROM STREAM(wm_events) WATERMARK ts DELAY OF INTERVAL 10 SECONDS t
+        |WHERE t.a > 1
+        |""".stripMargin)
+  }
+
+  test("STREAM with WATERMARK and alias resolves columns in ORDER BY") {
+    createTestTables()
+    analyzeStreamSQL(
+      """
+        |SELECT *
+        |FROM STREAM(wm_events) WATERMARK ts DELAY OF INTERVAL 10 SECONDS d
+        |ORDER BY d.a
+        |""".stripMargin)
+  }
+
+  test("STREAM with computed WATERMARK expression resolves correctly") {
+    createTestTables()
+    analyzeStreamSQL(
+      """
+        |SELECT *
+        |FROM STREAM(wm_events) WATERMARK CAST(ts AS TIMESTAMP) AS wm_time
+        |  DELAY OF INTERVAL 10 SECONDS d
+        |WHERE d.a > 1
+        |""".stripMargin)
+  }
+}


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

Reply via email to