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

zhouyuan 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 0364eaf6e0 [VL][Iceberg] Register iceberg spark session extensions 
automatically (#12823)
0364eaf6e0 is described below

commit 0364eaf6e05ea642b2a643bc9b5b1757159ebc12
Author: inf <[email protected]>
AuthorDate: Mon Aug 24 11:08:55 2026 +0000

    [VL][Iceberg] Register iceberg spark session extensions automatically 
(#12823)
---
 .../gluten/component/VeloxIcebergComponent.scala   |  8 +++-
 .../scala/org/apache/gluten/GlutenPlugin.scala     | 23 ++++++----
 .../org/apache/gluten/component/Component.scala    |  2 +
 .../org/apache/gluten/execution/IcebergSuite.scala | 13 ++++--
 .../gluten/GlutenSessionExtensionsSuite.scala      | 52 ++++++++++++++++++++++
 5 files changed, 85 insertions(+), 13 deletions(-)

diff --git 
a/backends-velox/src-iceberg/main/scala/org/apache/gluten/component/VeloxIcebergComponent.scala
 
b/backends-velox/src-iceberg/main/scala/org/apache/gluten/component/VeloxIcebergComponent.scala
index 8b6af1f045..71414a7be4 100644
--- 
a/backends-velox/src-iceberg/main/scala/org/apache/gluten/component/VeloxIcebergComponent.scala
+++ 
b/backends-velox/src-iceberg/main/scala/org/apache/gluten/component/VeloxIcebergComponent.scala
@@ -23,15 +23,19 @@ import org.apache.gluten.extension.injector.Injector
 import org.apache.spark.util.SparkReflectionUtil
 
 class VeloxIcebergComponent extends Component {
+  private val icebergSparkSessionExtension =
+    "org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions"
+
   override def name(): String = "velox-iceberg"
 
   override def dependencies(): Seq[Class[_ <: Component]] = 
classOf[VeloxBackend] :: Nil
 
   override def isRuntimeCompatible: Boolean = {
-    SparkReflectionUtil.isClassPresent(
-      "org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions")
+    SparkReflectionUtil.isClassPresent(icebergSparkSessionExtension)
   }
 
+  override def sparkSessionExtensions(): Seq[String] = 
icebergSparkSessionExtension :: Nil
+
   override def injectRules(injector: Injector): Unit = {
     OffloadIcebergScan.inject(injector)
     OffloadIcebergWrite.inject(injector)
diff --git a/gluten-core/src/main/scala/org/apache/gluten/GlutenPlugin.scala 
b/gluten-core/src/main/scala/org/apache/gluten/GlutenPlugin.scala
index 81fea4727b..05a1aff350 100644
--- a/gluten-core/src/main/scala/org/apache/gluten/GlutenPlugin.scala
+++ b/gluten-core/src/main/scala/org/apache/gluten/GlutenPlugin.scala
@@ -50,17 +50,11 @@ private[gluten] class GlutenDriverPlugin extends 
DriverPlugin with Logging {
 
   override def init(sc: SparkContext, pluginContext: PluginContext): 
util.Map[String, String] = {
     val conf = pluginContext.conf()
-    // Spark SQL extensions
-    val extensionSeq = conf.get(SPARK_SESSION_EXTENSIONS).getOrElse(Seq.empty)
-    if 
(!extensionSeq.toSet.contains(GlutenSessionExtensions.GLUTEN_SESSION_EXTENSION_NAME))
 {
-      conf.set(
-        SPARK_SESSION_EXTENSIONS,
-        extensionSeq :+ GlutenSessionExtensions.GLUTEN_SESSION_EXTENSION_NAME)
-    }
+    val components = Component.sorted()
+    configureSessionExtensions(conf, components)
 
     setPredefinedConfigs(conf)
 
-    val components = Component.sorted()
     printComponentInfo(components)
     setComponentInfoConfig(conf, components)
     components.foreach(_.onDriverStart(sc, pluginContext))
@@ -77,6 +71,19 @@ private[gluten] class GlutenDriverPlugin extends 
DriverPlugin with Logging {
 }
 
 private object GlutenDriverPlugin extends Logging {
+  private[gluten] def configureSessionExtensions(
+      conf: SparkConf,
+      components: Seq[Component]): Unit = {
+    val configuredExtensions = 
conf.get(SPARK_SESSION_EXTENSIONS).getOrElse(Seq.empty)
+    val requiredExtensions =
+      components.flatMap(_.sparkSessionExtensions()) :+
+        GlutenSessionExtensions.GLUTEN_SESSION_EXTENSION_NAME
+    val mergedExtensions = (configuredExtensions ++ 
requiredExtensions).distinct
+    if (mergedExtensions != configuredExtensions) {
+      conf.set(SPARK_SESSION_EXTENSIONS, mergedExtensions)
+    }
+  }
+
   private def checkOffHeapSettings(conf: SparkConf): Unit = {
     if (conf.get(GlutenCoreConfig.DYNAMIC_OFFHEAP_SIZING_ENABLED)) {
       // When dynamic off-heap sizing is enabled, off-heap mode is not 
strictly required to be
diff --git 
a/gluten-core/src/main/scala/org/apache/gluten/component/Component.scala 
b/gluten-core/src/main/scala/org/apache/gluten/component/Component.scala
index e2256c01e0..f5e6784536 100644
--- a/gluten-core/src/main/scala/org/apache/gluten/component/Component.scala
+++ b/gluten-core/src/main/scala/org/apache/gluten/component/Component.scala
@@ -79,6 +79,8 @@ trait Component {
   def info(): Map[String, String] = Map.empty
   def dependencies(): Seq[Class[_ <: Component]]
 
+  def sparkSessionExtensions(): Seq[String] = Nil
+
   /** Spark listeners. */
   def onDriverStart(sc: SparkContext, pc: PluginContext): Unit = {}
   def onDriverShutdown(): Unit = {}
diff --git 
a/gluten-iceberg/src/test/scala/org/apache/gluten/execution/IcebergSuite.scala 
b/gluten-iceberg/src/test/scala/org/apache/gluten/execution/IcebergSuite.scala
index 56f3fbdace..b5ea553d17 100644
--- 
a/gluten-iceberg/src/test/scala/org/apache/gluten/execution/IcebergSuite.scala
+++ 
b/gluten-iceberg/src/test/scala/org/apache/gluten/execution/IcebergSuite.scala
@@ -37,14 +37,21 @@ abstract class IcebergSuite extends 
WholeStageTransformerSuite {
       .set("spark.memory.offHeap.size", "2g")
       .set("spark.unsafe.exceptionOnMemoryLeak", "true")
       .set("spark.sql.autoBroadcastJoinThreshold", "-1")
-      .set(
-        "spark.sql.extensions",
-        "org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions")
       .set("spark.sql.catalog.spark_catalog", 
"org.apache.iceberg.spark.SparkCatalog")
       .set("spark.sql.catalog.spark_catalog.type", "hadoop")
       .set("spark.sql.catalog.spark_catalog.warehouse", 
s"file://$rootPath/tpch-data-iceberg-velox")
   }
 
+  test("iceberg system procedures are registered by the Gluten plugin") {
+    spark.sessionState.sqlParser.parsePlan(
+      """
+        |CALL spark_catalog.system.register_table(
+        |  table => 'default.issue_12693',
+        |  metadata_file => 'file:///tmp/does-not-exist.metadata.json'
+        |)
+        |""".stripMargin)
+  }
+
   test("iceberg transformer exists") {
     withTable("iceberg_tb") {
       spark.sql("""
diff --git 
a/gluten-ut/test/src/test/scala/org/apache/gluten/GlutenSessionExtensionsSuite.scala
 
b/gluten-ut/test/src/test/scala/org/apache/gluten/GlutenSessionExtensionsSuite.scala
new file mode 100644
index 0000000000..4165cac244
--- /dev/null
+++ 
b/gluten-ut/test/src/test/scala/org/apache/gluten/GlutenSessionExtensionsSuite.scala
@@ -0,0 +1,52 @@
+/*
+ * 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.gluten
+
+import org.apache.gluten.component.Component
+import org.apache.gluten.extension.GlutenSessionExtensions
+import org.apache.gluten.extension.injector.Injector
+
+import org.apache.spark.SparkConf
+import org.apache.spark.sql.internal.StaticSQLConf.SPARK_SESSION_EXTENSIONS
+
+import org.scalatest.funsuite.AnyFunSuite
+
+class GlutenSessionExtensionsSuite extends AnyFunSuite {
+  test("component session extensions are appended once") {
+    val configuredExtension = "example.ConfiguredExtension"
+    val componentExtension = "example.ComponentExtension"
+    val conf = new SparkConf(false).set(
+      SPARK_SESSION_EXTENSIONS.key,
+      Seq(configuredExtension, componentExtension).mkString(","))
+    val component = new TestComponent(Seq(componentExtension, 
componentExtension))
+
+    GlutenDriverPlugin.configureSessionExtensions(conf, component :: Nil)
+
+    assert(
+      conf.get(SPARK_SESSION_EXTENSIONS.key).split(",").toSeq == Seq(
+        configuredExtension,
+        componentExtension,
+        GlutenSessionExtensions.GLUTEN_SESSION_EXTENSION_NAME))
+  }
+
+  private class TestComponent(extensions: Seq[String]) extends Component {
+    override def name(): String = "test"
+    override def dependencies(): Seq[Class[_ <: Component]] = Nil
+    override def sparkSessionExtensions(): Seq[String] = extensions
+    override def injectRules(injector: Injector): Unit = {}
+  }
+}


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

Reply via email to