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

taiyang-li pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gluten.git


The following commit(s) were added to refs/heads/main by this push:
     new 99f8383746 [GLUTEN] Fix wrong input_file_name() for BHJ build-side 
LocalRelation (#12272)
99f8383746 is described below

commit 99f838374607bf443662e52a024dd2da4dde3e56
Author: 李扬 <[email protected]>
AuthorDate: Fri Jun 12 16:45:29 2026 +0800

    [GLUTEN] Fix wrong input_file_name() for BHJ build-side LocalRelation 
(#12272)
---
 .../functions/ScalarFunctionsValidateSuite.scala   | 44 ++++++++++++++++++++++
 .../columnar/PushDownInputFileExpression.scala     | 27 +++++++++++--
 2 files changed, 68 insertions(+), 3 deletions(-)

diff --git 
a/backends-velox/src/test/scala/org/apache/gluten/functions/ScalarFunctionsValidateSuite.scala
 
b/backends-velox/src/test/scala/org/apache/gluten/functions/ScalarFunctionsValidateSuite.scala
index cd49c23029..74b2933a67 100644
--- 
a/backends-velox/src/test/scala/org/apache/gluten/functions/ScalarFunctionsValidateSuite.scala
+++ 
b/backends-velox/src/test/scala/org/apache/gluten/functions/ScalarFunctionsValidateSuite.scala
@@ -1077,6 +1077,50 @@ abstract class ScalarFunctionsValidateSuite extends 
FunctionsValidateSuite {
     }
   }
 
+  test("input_file_name() with BHJ build-side LocalRelation must return real 
path") {
+    withTempPath {
+      path =>
+        Seq(("event_a", 1001L, "param1"))
+          .toDF("event", "device_id", "params")
+          .write
+          .parquet(path.getCanonicalPath)
+        
spark.read.parquet(path.getCanonicalPath).createOrReplaceTempView("event_log")
+
+        withSQLConf(
+          "spark.sql.autoBroadcastJoinThreshold" -> "10MB",
+          "spark.sql.adaptive.enabled" -> "true"
+        ) {
+          val sql =
+            """
+              |SELECT  a.event,
+              |        a.params,
+              |        a.device_id,
+              |        input_file_name() AS fname
+              |FROM    event_log a
+              |JOIN
+              |        (
+              |            SELECT  'event_a' AS envent,
+              |                    1001 AS device_id
+              |        ) b
+              |ON      a.event     = b.envent
+              |AND     a.device_id = b.device_id
+              |""".stripMargin
+
+          compareResultsAgainstVanillaSpark(sql, true, { _ => })
+
+          val df = spark.sql(sql)
+          val rows = df.collect()
+          assert(rows.nonEmpty, "Join should match at least one row")
+          rows.foreach {
+            r =>
+              val fname = r.getAs[String]("fname")
+              assert(fname != null && fname.nonEmpty)
+              assert(fname.contains(path.getName))
+          }
+        }
+    }
+  }
+
   testWithMinSparkVersion("array insert", "3.4") {
     withTempPath {
       path =>
diff --git 
a/gluten-substrait/src/main/scala/org/apache/gluten/extension/columnar/PushDownInputFileExpression.scala
 
b/gluten-substrait/src/main/scala/org/apache/gluten/extension/columnar/PushDownInputFileExpression.scala
index 7c9d1bea2d..8e3a2d53ad 100644
--- 
a/gluten-substrait/src/main/scala/org/apache/gluten/extension/columnar/PushDownInputFileExpression.scala
+++ 
b/gluten-substrait/src/main/scala/org/apache/gluten/extension/columnar/PushDownInputFileExpression.scala
@@ -21,7 +21,8 @@ import 
org.apache.gluten.execution.{BatchScanExecTransformerBase, FileSourceScan
 import org.apache.spark.sql.catalyst.expressions.{Alias, Attribute, 
AttributeReference, Expression, InputFileBlockLength, InputFileBlockStart, 
InputFileName, NamedExpression}
 import org.apache.spark.sql.catalyst.optimizer.CollapseProjectShim
 import org.apache.spark.sql.catalyst.rules.Rule
-import org.apache.spark.sql.execution.{DeserializeToObjectExec, LeafExecNode, 
ProjectExec, SerializeFromObjectExec, SparkPlan, UnionExec}
+import org.apache.spark.sql.execution.{DeserializeToObjectExec, 
FileSourceScanExec, LeafExecNode, ProjectExec, SerializeFromObjectExec, 
SparkPlan, UnionExec}
+import org.apache.spark.sql.execution.datasources.v2.BatchScanExec
 import org.apache.spark.sql.hive.HiveTableScanExecTransformer
 
 import java.util.Locale
@@ -87,7 +88,8 @@ object PushDownInputFileExpression {
 
   object PreOffload extends Rule[SparkPlan] {
     override def apply(plan: SparkPlan): SparkPlan = plan.transformUp {
-      case ProjectExec(projectList, child) if 
projectList.exists(containsInputFileRelatedExpr) =>
+      case ProjectExec(projectList, child)
+          if projectList.exists(containsInputFileRelatedExpr) && 
hasInputFileRelatedSource(child) =>
         val replacedExprs = mutable.Map[String, Alias]()
         val newProjectList = projectList.map {
           expr => rewriteExpr(expr, 
replacedExprs).asInstanceOf[NamedExpression]
@@ -104,8 +106,10 @@ object PushDownInputFileExpression {
           // For BatchScanExecTransformerBase (includes Iceberg scans), add 
fallback tag
           // to prevent offloading when input_file expressions are present
           addFallbackTag(ProjectExec(p.output ++ replacedExprs.values, p))
-        case p: LeafExecNode =>
+        case p: LeafExecNode if shouldAddInputFileExpr(p) =>
           addFallbackTag(ProjectExec(p.output ++ replacedExprs.values, p))
+        case p: LeafExecNode =>
+          p
         // Output of SerializeFromObjectExec's child and output of 
DeserializeToObjectExec must be
         // a single-field row.
         case p @ (_: SerializeFromObjectExec | _: DeserializeToObjectExec) =>
@@ -127,6 +131,23 @@ object PushDownInputFileExpression {
           u.copy(children = newFirstChild +: newOtherChildren)
         case p => p.withNewChildren(p.children.map(child => 
addMetadataCol(child, replacedExprs)))
       }
+
+    private def hasInputFileRelatedSource(plan: SparkPlan): Boolean = {
+      plan match {
+        case _: BatchScanExecTransformerBase => true
+        case p: LeafExecNode => shouldAddInputFileExpr(p)
+        case _ => plan.children.exists(hasInputFileRelatedSource)
+      }
+    }
+
+    private def shouldAddInputFileExpr(plan: SparkPlan): Boolean = {
+      plan match {
+        case _: FileSourceScanExec => true
+        case _: BatchScanExec => true
+        case p if HiveTableScanExecTransformer.isHiveTableScan(p) => true
+        case _ => false
+      }
+    }
   }
 
   object PostOffload extends Rule[SparkPlan] {


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

Reply via email to