HyukjinKwon commented on code in PR #58615:
URL: https://github.com/apache/spark/pull/58615#discussion_r3994456188


##########
sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveUtils.scala:
##########
@@ -200,6 +200,24 @@ private[spark] object HiveUtils extends Logging {
     .booleanConf
     .createWithDefault(false)
 
+  val INITIALIZE_METASTORE_FORMAT_CLASSES =
+    buildConf("spark.sql.hive.initializeMetastoreFormatClasses")
+      .doc("When true, an InputFormat/OutputFormat class name stored in the 
Hive metastore is " +
+        "resolved with its static initializer run at resolution time. When 
false, the class is " +
+        "resolved without running its static initializer, which then runs 
later when the format " +
+        "is instantiated for a scan/write. Only the class name is needed when 
converting " +
+        "metastore metadata, so setting this to false avoids running a format 
class's static " +
+        "initializer during a metadata operation. Note that the conversion 
also runs when " +
+        "planning a scan or write and when inferring the schema of a Hive 
serde table, so with " +
+        "false a format class whose static initializer fails no longer fails 
fast on the driver " +
+        "at resolution time; the failure instead surfaces later on an executor 
when the format " +
+        "is instantiated (as NoClassDefFoundError: Could not initialize class 
...). Keep this " +
+        "true (the default) to preserve the fail-fast behavior.")

Review Comment:
   Adopted your suggested doc in 384ea6b: scan instantiates on the driver at 
split computation, write on an executor, the built-in Parquet/ORC reader never 
instantiates the format, and the class is still loaded so a missing class still 
fails at resolution time.



##########
sql/hive/src/test/scala/org/apache/spark/sql/hive/client/HiveClientImplSuite.scala:
##########
@@ -20,9 +20,41 @@ package org.apache.spark.sql.hive.client
 import org.apache.hadoop.hive.metastore.api.FieldSchema
 
 import org.apache.spark.{SparkFunSuite, SparkUnsupportedOperationException}
+import org.apache.spark.sql.catalyst.TableIdentifier
+import org.apache.spark.sql.catalyst.catalog.{CatalogStorageFormat, 
CatalogTable, CatalogTableType}
+import org.apache.spark.sql.hive.{HiveUtils, StaticInitFlags, 
StaticInitInputFormat}
+import org.apache.spark.sql.internal.SQLConf
+import org.apache.spark.sql.types.StructType
 
 class HiveClientImplSuite extends SparkFunSuite {
 
+  test("SPARK-59330: toHiveTable skips the format class static initializer 
when " +
+    "spark.sql.hive.initializeMetastoreFormatClasses is false") {
+    val table = CatalogTable(
+      identifier = TableIdentifier("t", Some("default")),
+      tableType = CatalogTableType.MANAGED,
+      storage = CatalogStorageFormat.empty.copy(
+        inputFormat = Some(classOf[StaticInitInputFormat].getName)),
+      schema = new StructType().add("a", "int"))
+
+    def toHiveTableWith(initialize: Boolean): Unit = {
+      val conf = new SQLConf()
+      conf.setConf(HiveUtils.INITIALIZE_METASTORE_FORMAT_CLASSES, initialize)
+      SQLConf.withExistingConf(conf) {
+        HiveClientImpl.toHiveTable(table)
+      }
+    }
+
+    // The false half must run first: class initialization is one-way per JVM. 
Resolving the
+    // format class name without initializing it must not run the static 
initializer.
+    toHiveTableWith(initialize = false)
+    assert(!StaticInitFlags.inputFormatInitialized)
+
+    // With initialization enabled (the default), resolving the class name 
runs the initializer.
+    toHiveTableWith(initialize = true)
+    assert(StaticInitFlags.inputFormatInitialized)

Review Comment:
   Done in 384ea6b. Added `StaticInitOutputFormat` (`HiveOutputFormat<Void, 
Void>` whose methods throw) and `outputFormatInitialized` on `StaticInitFlags`, 
put both formats on the test table storage, and assert both flags in each half 
-- so `toOutputFormat` is now covered alongside `toInputFormat`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to