This is an automated email from the ASF dual-hosted git repository.
philo-he 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 79df455ce8 [GLUTEN-13179][CORE] Fix NPE when a column has a null name
(#13206)
79df455ce8 is described below
commit 79df455ce85ac4985ad67548254768e4f73fc167
Author: rdtr <[email protected]>
AuthorDate: Fri Oct 9 22:28:55 2026 -0700
[GLUTEN-13179][CORE] Fix NPE when a column has a null name (#13206)
---
.../gluten/execution/VeloxLocalTableScanSuite.scala | 19 +++++++++++++++++++
.../org/apache/gluten/expression/ConverterUtils.scala | 5 +++++
.../gluten/expression/ConverterUtilsSuite.scala | 13 ++++++++++++-
3 files changed, 36 insertions(+), 1 deletion(-)
diff --git
a/backends-velox/src/test/scala/org/apache/gluten/execution/VeloxLocalTableScanSuite.scala
b/backends-velox/src/test/scala/org/apache/gluten/execution/VeloxLocalTableScanSuite.scala
index cdb63cc782..068411bbd2 100644
---
a/backends-velox/src/test/scala/org/apache/gluten/execution/VeloxLocalTableScanSuite.scala
+++
b/backends-velox/src/test/scala/org/apache/gluten/execution/VeloxLocalTableScanSuite.scala
@@ -21,6 +21,9 @@ import org.apache.gluten.sql.shims.SparkShimLoader
import org.apache.spark.SparkConf
import org.apache.spark.sql.{DataFrame, Row}
+import org.apache.spark.sql.catalyst.expressions.AttributeReference
+import org.apache.spark.sql.catalyst.plans.logical.LocalRelation
+import org.apache.spark.sql.classic.ClassicDataset
import org.apache.spark.sql.execution.LocalTableScanExec
import org.apache.spark.sql.execution.adaptive.AdaptiveSparkPlanHelper
import org.apache.spark.sql.types._
@@ -71,6 +74,22 @@ class VeloxLocalTableScanSuite
assertHasVeloxLocalTableScan(df)
}
+ // Before Spark 4.2 (SPARK-57725), Spark itself fails to resolve a plan with
a null-named
+ // attribute.
+ testWithMinSparkVersion("LocalTableScan with a null-named attribute", "4.2")
{
+ val attrs = Seq(AttributeReference(null, IntegerType)(),
AttributeReference("b", IntegerType)())
+ val relation = LocalRelation.fromExternalRows(attrs, Seq(Row(1, 2)))
+ // With and without offloading the LocalTableScan itself.
+ Seq("true", "false").foreach {
+ offload =>
+ withSQLConf("spark.gluten.sql.columnar.localTableScan" -> offload) {
+ val df = ClassicDataset.ofRows(spark, relation).select("b")
+ checkAnswer(df, Row(2))
+ checkGlutenPlan[ProjectExecTransformer](df)
+ }
+ }
+ }
+
test("LocalTableScan with numeric types") {
val schema = StructType(
Seq(
diff --git
a/gluten-substrait/src/main/scala/org/apache/gluten/expression/ConverterUtils.scala
b/gluten-substrait/src/main/scala/org/apache/gluten/expression/ConverterUtils.scala
index be5522721d..cf4803e37b 100644
---
a/gluten-substrait/src/main/scala/org/apache/gluten/expression/ConverterUtils.scala
+++
b/gluten-substrait/src/main/scala/org/apache/gluten/expression/ConverterUtils.scala
@@ -49,6 +49,11 @@ object ConverterUtils extends Logging {
}
def normalizeColName(name: String): String = {
+ // An attribute may carry a null name (e.g. built from a StructField with
a null name,
+ // SPARK-57725). Map it to an empty name; generated column names stay
unique via the exprId.
+ if (name == null) {
+ return ""
+ }
val caseSensitive = SQLConf.get.caseSensitiveAnalysis
if (caseSensitive) name else name.toLowerCase(Locale.ROOT)
}
diff --git
a/gluten-substrait/src/test/scala/org/apache/gluten/expression/ConverterUtilsSuite.scala
b/gluten-substrait/src/test/scala/org/apache/gluten/expression/ConverterUtilsSuite.scala
index 268538af15..bfa3b0ea1b 100644
---
a/gluten-substrait/src/test/scala/org/apache/gluten/expression/ConverterUtilsSuite.scala
+++
b/gluten-substrait/src/test/scala/org/apache/gluten/expression/ConverterUtilsSuite.scala
@@ -16,7 +16,8 @@
*/
package org.apache.gluten.expression
-import org.apache.spark.sql.types.{DataType, TimestampType}
+import org.apache.spark.sql.catalyst.expressions.AttributeReference
+import org.apache.spark.sql.types.{DataType, IntegerType, TimestampType}
import io.substrait.proto.Type
import org.scalatest.funsuite.AnyFunSuiteLike
@@ -64,4 +65,14 @@ class ConverterUtilsSuite extends AnyFunSuiteLike {
assert(parsedNullable === nullable)
}
}
+
+ test("column names for an attribute with a null name") {
+ // An attribute can have a null name, e.g. from a StructField built with a
null name.
+ val nullNamed = AttributeReference(null, IntegerType)()
+ assert(ConverterUtils.genColumnNameWithoutExprId(nullNamed) === "")
+ assert(ConverterUtils.genColumnNameWithExprId(nullNamed) ===
s"#${nullNamed.exprId.id}")
+
+ val named = AttributeReference("B", IntegerType)()
+ assert(ConverterUtils.genColumnNameWithExprId(named) ===
s"b#${named.exprId.id}")
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]