You are viewing a plain text version of this content. The canonical link for it is here.
Posted to reviews@spark.apache.org by "LuciferYang (via GitHub)" <gi...@apache.org> on 2026/03/25 04:05:14 UTC

[PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

LuciferYang opened a new pull request, #54998:
URL: https://github.com/apache/spark/pull/54998

   ### What changes were proposed in this pull request?
   This PR enables the V2 file write path for non-partitioned `df.write.mode("append"/"overwrite").save(path)` operations across all built-in file formats (Parquet, ORC, JSON, CSV, Text, Avro), and deletes the `FallBackFileSourceV2` analysis rule which is now redundant.
   
   ### Key changes
   
   **V2 write foundation (`FileTable`, `FileWrite`, `*Write`, `*Table`)**
   - `FileTable.createFileWriteBuilder`: new infrastructure for creating `WriteBuilder` with `SupportsTruncate` and `SupportsDynamicOverwrite` capabilities
   - `FileWrite`: partition schema support, truncation (overwrite), dynamic partition overwrite, schema validation (nested column name duplication, data type, collation in map keys)
   - All 6 format-specific `Write` case classes (`ParquetWrite`, `OrcWrite`, `JsonWrite`, `CSVWrite`, `TextWrite`, `AvroWrite`) accept new parameters from `createFileWriteBuilder`
   - All 6 format-specific `Table` classes implement `newWriteBuilder` via `createFileWriteBuilder`
   
   **Delete `FallBackFileSourceV2`**
   - Remove the analysis rule and its registrations in `BaseSessionStateBuilder` and `HiveSessionStateBuilder`
   - This rule was redundant: `USE_V1_SOURCE_LIST` (defaulting to all built-in formats) already prevents V2 file tables from being created, and `DataSourceV2Utils.getTableProvider` gates catalog table loading
   
   **Cache invalidation (`DataSourceV2Strategy`)**
   - `refreshCache`: use `recacheByPath` (instead of `recacheByPlan`) for `FileTable` writes, with `fileIndex.refresh()` to update the cached file listing
   
   **Error handling (`FileFormatDataWriter`)**
   - Override `writeAll` to wrap errors with `TASK_WRITE_FAILED`, consistent with the per-row `write()` method
   
   **V2 write gating (`DataFrameWriter`, `DataSourceV2Utils`)**
   - `DataFrameWriter.lookupV2Provider`: allow V2 for `FileDataSourceV2` only when mode is `Append` or `Overwrite` AND no `partitionBy` is specified; fall back to V1 for `ErrorIfExists`/`Ignore` (TODO: SPARK-56174) and partitioned writes (TODO: SPARK-56185)
   - `DataFrameWriter.saveAsTable` / `insertInto`: always fall back to V1 for `FileDataSourceV2` (TODO: SPARK-56185)
   - `DataSourceV2Utils.getTableProvider`: return `None` for `FileDataSourceV2` to prevent V2 catalog table loading until stats, partition management, and data type validation gaps are addressed (TODO: SPARK-56185)
   
   **Data type validation (`V2SessionCatalog`)**
   - Add V1 `FileFormat.supportDataType` validation in the `createTable` fallback branch, ensuring `CREATE TABLE` with unsupported types (e.g., Variant in CSV) is rejected consistently
   
   **Avro Table**
   - Fix `formatName` from `"AVRO"` to `"Avro"` to match V1's `AvroFileFormat.toString`
   
   
   ### Why are the changes needed?
   The V2 Data Source API provides a cleaner, more extensible write path than V1's `InsertIntoHadoopFsRelationCommand`. Enabling V2 writes for built-in file formats is a step toward fully migrating file sources to V2, which will simplify the codebase and enable future optimizations.
   
   `FallBackFileSourceV2` was an analysis rule that converted V2 file `InsertIntoStatement` back to V1. It is no longer needed because:
   1. `USE_V1_SOURCE_LIST` (default: all built-in formats) prevents V2 file tables from being created for reads or writes
   2. `DataSourceV2Utils.getTableProvider` gates V2 catalog table loading
   3. The DataFrame API path uses `AppendData`/`OverwriteByExpression`, not `InsertIntoStatement`
   
   
   ### Does this PR introduce _any_ user-facing change?
   No. With default configuration (`spark.sql.sources.useV1SourceList` = `"avro,csv,json,kafka,orc,parquet,text"`), all file writes continue to use the V1 path. The V2 write path is only activated when a user explicitly clears `USE_V1_SOURCE_LIST` and uses `df.write.mode("append"/"overwrite").save(path)` without `partitionBy`.
   
   
   ### How was this patch tested?
   - Pass Github Actions
   - New test suite `FileDataSourceV2WriteSuite` (23 tests) covering:
     - V1 fallback behavior for all save modes
     - V2 non-partitioned append and overwrite across parquet, orc, json, csv
     - V2 cache invalidation on append and overwrite
     - Partitioned writes, dynamic partition overwrite, multi-level partitioning (via V1)
     - Catalog table INSERT INTO and CTAS (via V1)
   
   
   ### Was this patch authored or co-authored using generative AI tooling?
   Generated-by:  Claude Code 4.6
   


-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] closed pull request #54998: [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2`
URL: https://github.com/apache/spark/pull/54998


-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "LuciferYang (via GitHub)" <gi...@apache.org>.
LuciferYang commented on code in PR #54998:
URL: https://github.com/apache/spark/pull/54998#discussion_r3069564236


##########
connector/avro/src/main/scala/org/apache/spark/sql/v2/avro/AvroTable.scala:
##########
@@ -43,13 +43,14 @@ case class AvroTable(
     AvroUtils.inferSchema(sparkSession, options.asScala.toMap, files)
 
   override def newWriteBuilder(info: LogicalWriteInfo): WriteBuilder = {
-    new WriteBuilder {
-      override def build(): Write =
-        AvroWrite(paths, formatName, supportsDataType, mergedWriteInfo(info))
+    createFileWriteBuilder(info) {
+      (mergedInfo, partSchema, customLocs, dynamicOverwrite, truncate) =>
+      AvroWrite(paths, formatName, supportsDataType, mergedInfo, partSchema, customLocs,
+        dynamicOverwrite, truncate)
     }
   }
 
   override def supportsDataType(dataType: DataType): Boolean = AvroUtils.supportsDataType(dataType)
 
-  override def formatName: String = "AVRO"
+  override def formatName: String = "Avro"

Review Comment:
   To fix tests failed:
   
   ```
   [info] - error handling for unsupported Interval data types *** FAILED *** (19 milliseconds)
   [info]   HashMap("columnType" -> ""INTERVAL"", "format" -> "AVRO", "columnName" -> "`INTERVAL '1 days'`") did not equal Map("format" -> "Avro", "columnName" -> "`INTERVAL '1 days'`", "columnType" -> ""INTERVAL"") (SparkTestSuite.scala:324)
   [info]   Analysis:
   [info]   HashMap("format": "AVRO" -> "Avro")
   [info]   org.scalatest.exceptions.TestFailedException:
   [info]   at org.scalatest.Assertions.newAssertionFailedException(Assertions.scala:472)
   [info]   at org.scalatest.Assertions.newAssertionFailedException$(Assertions.scala:471)
   [info]   at org.scalatest.Assertions$.newAssertionFailedException(Assertions.scala:1231)
   [info]   at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:1295)
   [info]   at org.apache.spark.SparkTestSuite.checkError(SparkTestSuite.scala:324)
   [info]   at org.apache.spark.SparkTestSuite.checkError$(SparkTestSuite.scala:297)
   [info]   at org.apache.spark.SparkFunSuite.checkError(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$200(AvroSuite.scala:1822)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$200$adapted(AvroSuite.scala:1820)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1(SQLTestUtils.scala:81)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1$adapted(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir(SparkTestSuite.scala:193)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir$(SparkTestSuite.scala:191)
   [info]   at org.apache.spark.sql.avro.AvroSuite.org$apache$spark$sql$test$SQLTestUtils$$super$withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir$(SQLTestUtils.scala:79)
   [info]   at org.apache.spark.sql.avro.AvroSuite.withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$199(AvroSuite.scala:1820)
   [info]   at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
   [info]   at org.apache.spark.sql.catalyst.SQLConfHelper.withSQLConf(SQLConfHelper.scala:54)
   [info]   at org.apache.spark.sql.catalyst.SQLConfHelper.withSQLConf$(SQLConfHelper.scala:38)
   [info]   at org.apache.spark.sql.avro.AvroSuite.org$apache$spark$sql$test$SQLTestUtilsBase$$super$withSQLConf(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.test.SQLTestUtilsBase.withSQLConf(SQLTestUtils.scala:255)
   [info]   at org.apache.spark.sql.test.SQLTestUtilsBase.withSQLConf$(SQLTestUtils.scala:253)
   [info]   at org.apache.spark.sql.avro.AvroSuite.withSQLConf(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$198(AvroSuite.scala:1820)
   [info]   at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
   [info]   at org.scalatest.enablers.Timed$$anon$1.timeoutAfter(Timed.scala:127)
   [info]   at org.scalatest.concurrent.TimeLimits$.failAfterImpl(TimeLimits.scala:282)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter(TimeLimits.scala:231)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter$(TimeLimits.scala:230)
   [info]   at org.apache.spark.SparkFunSuite.failAfter(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.SparkFunSuite.$anonfun$test$2(SparkFunSuite.scala:41)
   [info]   at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
   [info]   at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
   [info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:22)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:20)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike$$anon$1.apply(AnyFunSuiteLike.scala:226)
   [info]   at org.apache.spark.SparkTestSuite.withFixture(SparkTestSuite.scala:175)
   [info]   at org.apache.spark.SparkTestSuite.withFixture$(SparkTestSuite.scala:169)
   [info]   at org.apache.spark.SparkFunSuite.withFixture(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.invokeWithFixture$1(AnyFunSuiteLike.scala:224)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTest$1(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest$(AnyFunSuiteLike.scala:218)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterEach$$super$runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest(BeforeAndAfterEach.scala:234)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest$(BeforeAndAfterEach.scala:227)
   [info]   at org.apache.spark.SparkFunSuite.runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTests$1(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
   [info]   at scala.collection.immutable.List.foreach(List.scala:323)
   [info]   at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
   [info]   at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
   [info]   at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests$(AnyFunSuiteLike.scala:268)
   [info]   at org.scalatest.funsuite.AnyFunSuite.runTests(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.Suite.run(Suite.scala:1114)
   [info]   at org.scalatest.Suite.run$(Suite.scala:1096)
   [info]   at org.scalatest.funsuite.AnyFunSuite.org$scalatest$funsuite$AnyFunSuiteLike$$super$run(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$run$1(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.SuperEngine.runImpl(Engine.scala:535)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run$(AnyFunSuiteLike.scala:272)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterAll$$super$run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterAll.liftedTree1$1(BeforeAndAfterAll.scala:213)
   [info]   at org.scalatest.BeforeAndAfterAll.run(BeforeAndAfterAll.scala:210)
   [info]   at org.scalatest.BeforeAndAfterAll.run$(BeforeAndAfterAll.scala:208)
   [info]   at org.apache.spark.SparkFunSuite.run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:321)
   [info]   at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:517)
   [info]   at sbt.ForkMain$Run.lambda$runTest$1(ForkMain.java:414)
   [info]   at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
   [info]   at java.base/java.lang.Thread.run(Thread.java:840)
   
   ...
   
   [info] - Geospatial types are not supported in Avro *** FAILED *** (6 milliseconds)
   [info]   HashMap("columnType" -> ""GEOMETRY(0)"", "format" -> "AVRO", "columnName" -> "`g`") did not equal Map("columnName" -> "`g`", "columnType" -> ""GEOMETRY(0)"", "format" -> "Avro") (SparkTestSuite.scala:324)
   [info]   Analysis:
   [info]   HashMap("format": "AVRO" -> "Avro")
   [info]   org.scalatest.exceptions.TestFailedException:
   [info]   at org.scalatest.Assertions.newAssertionFailedException(Assertions.scala:472)
   [info]   at org.scalatest.Assertions.newAssertionFailedException$(Assertions.scala:471)
   [info]   at org.scalatest.Assertions$.newAssertionFailedException(Assertions.scala:1231)
   [info]   at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:1295)
   [info]   at org.apache.spark.SparkTestSuite.checkError(SparkTestSuite.scala:324)
   [info]   at org.apache.spark.SparkTestSuite.checkError$(SparkTestSuite.scala:297)
   [info]   at org.apache.spark.SparkFunSuite.checkError(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$488(AvroSuite.scala:3677)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$488$adapted(AvroSuite.scala:3676)
   [info]   at scala.collection.immutable.List.foreach(List.scala:323)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$487(AvroSuite.scala:3676)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$487$adapted(AvroSuite.scala:3666)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1(SQLTestUtils.scala:81)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1$adapted(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir(SparkTestSuite.scala:193)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir$(SparkTestSuite.scala:191)
   [info]   at org.apache.spark.sql.avro.AvroSuite.org$apache$spark$sql$test$SQLTestUtils$$super$withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir$(SQLTestUtils.scala:79)
   [info]   at org.apache.spark.sql.avro.AvroSuite.withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$486(AvroSuite.scala:3666)
   [info]   at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
   [info]   at org.scalatest.enablers.Timed$$anon$1.timeoutAfter(Timed.scala:127)
   [info]   at org.scalatest.concurrent.TimeLimits$.failAfterImpl(TimeLimits.scala:282)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter(TimeLimits.scala:231)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter$(TimeLimits.scala:230)
   [info]   at org.apache.spark.SparkFunSuite.failAfter(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.SparkFunSuite.$anonfun$test$2(SparkFunSuite.scala:41)
   [info]   at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
   [info]   at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
   [info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:22)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:20)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike$$anon$1.apply(AnyFunSuiteLike.scala:226)
   [info]   at org.apache.spark.SparkTestSuite.withFixture(SparkTestSuite.scala:175)
   [info]   at org.apache.spark.SparkTestSuite.withFixture$(SparkTestSuite.scala:169)
   [info]   at org.apache.spark.SparkFunSuite.withFixture(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.invokeWithFixture$1(AnyFunSuiteLike.scala:224)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTest$1(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest$(AnyFunSuiteLike.scala:218)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterEach$$super$runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest(BeforeAndAfterEach.scala:234)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest$(BeforeAndAfterEach.scala:227)
   [info]   at org.apache.spark.SparkFunSuite.runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTests$1(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
   [info]   at scala.collection.immutable.List.foreach(List.scala:323)
   [info]   at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
   [info]   at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
   [info]   at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests$(AnyFunSuiteLike.scala:268)
   [info]   at org.scalatest.funsuite.AnyFunSuite.runTests(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.Suite.run(Suite.scala:1114)
   [info]   at org.scalatest.Suite.run$(Suite.scala:1096)
   [info]   at org.scalatest.funsuite.AnyFunSuite.org$scalatest$funsuite$AnyFunSuiteLike$$super$run(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$run$1(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.SuperEngine.runImpl(Engine.scala:535)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run$(AnyFunSuiteLike.scala:272)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterAll$$super$run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterAll.liftedTree1$1(BeforeAndAfterAll.scala:213)
   [info]   at org.scalatest.BeforeAndAfterAll.run(BeforeAndAfterAll.scala:210)
   [info]   at org.scalatest.BeforeAndAfterAll.run$(BeforeAndAfterAll.scala:208)
   [info]   at org.apache.spark.SparkFunSuite.run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:321)
   [info]   at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:517)
   [info]   at sbt.ForkMain$Run.lambda$runTest$1(ForkMain.java:414)
   [info]   at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
   [info]   at java.base/java.lang.Thread.run(Thread.java:840)
   ```
   
   Before this pr, the function `formatName` will not be invoked.



-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "LuciferYang (via GitHub)" <gi...@apache.org>.
LuciferYang commented on code in PR #54998:
URL: https://github.com/apache/spark/pull/54998#discussion_r3069566300


##########
connector/avro/src/main/scala/org/apache/spark/sql/v2/avro/AvroTable.scala:
##########
@@ -43,13 +43,14 @@ case class AvroTable(
     AvroUtils.inferSchema(sparkSession, options.asScala.toMap, files)
 
   override def newWriteBuilder(info: LogicalWriteInfo): WriteBuilder = {
-    new WriteBuilder {
-      override def build(): Write =
-        AvroWrite(paths, formatName, supportsDataType, mergedWriteInfo(info))
+    createFileWriteBuilder(info) {
+      (mergedInfo, partSchema, customLocs, dynamicOverwrite, truncate) =>
+      AvroWrite(paths, formatName, supportsDataType, mergedInfo, partSchema, customLocs,
+        dynamicOverwrite, truncate)
     }
   }
 
   override def supportsDataType(dataType: DataType): Boolean = AvroUtils.supportsDataType(dataType)
 
-  override def formatName: String = "AVRO"
+  override def formatName: String = "Avro"

Review Comment:
   Let me take a further look at this issue tomorrow, and if possible, I'll split it into a separate pr to handle it.



-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "LuciferYang (via GitHub)" <gi...@apache.org>.
LuciferYang commented on code in PR #54998:
URL: https://github.com/apache/spark/pull/54998#discussion_r3064281692


##########
sql/core/src/test/scala/org/apache/spark/sql/connector/FileDataSourceV2WriteSuite.scala:
##########
@@ -0,0 +1,553 @@
+/*
+ * 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.connector
+
+import scala.collection.mutable.ArrayBuffer
+
+import org.apache.spark.{SparkConf, SparkException}
+import org.apache.spark.sql.{DataFrame, QueryTest, Row}
+import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan
+import org.apache.spark.sql.connector.catalog.{SupportsRead, SupportsWrite, Table, TableCapability}
+import org.apache.spark.sql.connector.read.ScanBuilder
+import org.apache.spark.sql.connector.write.{LogicalWriteInfo, WriteBuilder}
+import org.apache.spark.sql.execution.{FileSourceScanExec, QueryExecution}
+import org.apache.spark.sql.execution.datasources.{FileFormat, InsertIntoHadoopFsRelationCommand}
+import org.apache.spark.sql.execution.datasources.parquet.ParquetFileFormat
+import org.apache.spark.sql.execution.datasources.v2.FileDataSourceV2
+import org.apache.spark.sql.execution.datasources.v2.parquet.ParquetDataSourceV2
+import org.apache.spark.sql.internal.SQLConf
+import org.apache.spark.sql.test.SharedSparkSession
+import org.apache.spark.sql.types.StructType
+import org.apache.spark.sql.util.{CaseInsensitiveStringMap, QueryExecutionListener}
+
+class DummyReadOnlyFileDataSourceV2 extends FileDataSourceV2 {
+
+  override def fallbackFileFormat: Class[_ <: FileFormat] = classOf[ParquetFileFormat]
+
+  override def shortName(): String = "parquet"
+
+  override def getTable(options: CaseInsensitiveStringMap): Table = {
+    new DummyReadOnlyFileTable
+  }
+}
+
+class DummyReadOnlyFileTable extends Table with SupportsRead {
+  override def name(): String = "dummy"
+
+  override def schema(): StructType = StructType(Nil)
+
+  override def newScanBuilder(options: CaseInsensitiveStringMap): ScanBuilder = {
+    throw SparkException.internalError("Dummy file reader")
+  }
+
+  override def capabilities(): java.util.Set[TableCapability] =
+    java.util.EnumSet.of(TableCapability.BATCH_READ, TableCapability.ACCEPT_ANY_SCHEMA)
+}
+
+class DummyWriteOnlyFileDataSourceV2 extends FileDataSourceV2 {
+
+  override def fallbackFileFormat: Class[_ <: FileFormat] = classOf[ParquetFileFormat]
+
+  override def shortName(): String = "parquet"
+
+  override def getTable(options: CaseInsensitiveStringMap): Table = {
+    new DummyWriteOnlyFileTable
+  }
+}
+
+class DummyWriteOnlyFileTable extends Table with SupportsWrite {
+  override def name(): String = "dummy"
+
+  override def schema(): StructType = StructType(Nil)
+
+  override def newWriteBuilder(info: LogicalWriteInfo): WriteBuilder =
+    throw SparkException.internalError("Dummy file writer")
+
+  override def capabilities(): java.util.Set[TableCapability] =
+    java.util.EnumSet.of(TableCapability.BATCH_WRITE, TableCapability.ACCEPT_ANY_SCHEMA)
+}
+
+class FileDataSourceV2WriteSuite extends QueryTest with SharedSparkSession {
+
+  private val dummyReadOnlyFileSourceV2 = classOf[DummyReadOnlyFileDataSourceV2].getName
+  private val dummyWriteOnlyFileSourceV2 = classOf[DummyWriteOnlyFileDataSourceV2].getName
+
+  // Built-in file formats for write testing. Text is excluded
+  // because it only supports a single string column.
+  private val fileFormats = Seq("parquet", "orc", "json", "csv")

Review Comment:
   There are quite a few loose threads here; let me handle them one by one :)



-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "LuciferYang (via GitHub)" <gi...@apache.org>.
LuciferYang commented on code in PR #54998:
URL: https://github.com/apache/spark/pull/54998#discussion_r3069564236


##########
connector/avro/src/main/scala/org/apache/spark/sql/v2/avro/AvroTable.scala:
##########
@@ -43,13 +43,14 @@ case class AvroTable(
     AvroUtils.inferSchema(sparkSession, options.asScala.toMap, files)
 
   override def newWriteBuilder(info: LogicalWriteInfo): WriteBuilder = {
-    new WriteBuilder {
-      override def build(): Write =
-        AvroWrite(paths, formatName, supportsDataType, mergedWriteInfo(info))
+    createFileWriteBuilder(info) {
+      (mergedInfo, partSchema, customLocs, dynamicOverwrite, truncate) =>
+      AvroWrite(paths, formatName, supportsDataType, mergedInfo, partSchema, customLocs,
+        dynamicOverwrite, truncate)
     }
   }
 
   override def supportsDataType(dataType: DataType): Boolean = AvroUtils.supportsDataType(dataType)
 
-  override def formatName: String = "AVRO"
+  override def formatName: String = "Avro"

Review Comment:
   To fix tests failed in `org.apache.spark.sql.avro.AvroV2Suite`:
   
   ```
   [info] - error handling for unsupported Interval data types *** FAILED *** (19 milliseconds)
   [info]   HashMap("columnType" -> ""INTERVAL"", "format" -> "AVRO", "columnName" -> "`INTERVAL '1 days'`") did not equal Map("format" -> "Avro", "columnName" -> "`INTERVAL '1 days'`", "columnType" -> ""INTERVAL"") (SparkTestSuite.scala:324)
   [info]   Analysis:
   [info]   HashMap("format": "AVRO" -> "Avro")
   [info]   org.scalatest.exceptions.TestFailedException:
   [info]   at org.scalatest.Assertions.newAssertionFailedException(Assertions.scala:472)
   [info]   at org.scalatest.Assertions.newAssertionFailedException$(Assertions.scala:471)
   [info]   at org.scalatest.Assertions$.newAssertionFailedException(Assertions.scala:1231)
   [info]   at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:1295)
   [info]   at org.apache.spark.SparkTestSuite.checkError(SparkTestSuite.scala:324)
   [info]   at org.apache.spark.SparkTestSuite.checkError$(SparkTestSuite.scala:297)
   [info]   at org.apache.spark.SparkFunSuite.checkError(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$200(AvroSuite.scala:1822)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$200$adapted(AvroSuite.scala:1820)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1(SQLTestUtils.scala:81)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1$adapted(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir(SparkTestSuite.scala:193)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir$(SparkTestSuite.scala:191)
   [info]   at org.apache.spark.sql.avro.AvroSuite.org$apache$spark$sql$test$SQLTestUtils$$super$withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir$(SQLTestUtils.scala:79)
   [info]   at org.apache.spark.sql.avro.AvroSuite.withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$199(AvroSuite.scala:1820)
   [info]   at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
   [info]   at org.apache.spark.sql.catalyst.SQLConfHelper.withSQLConf(SQLConfHelper.scala:54)
   [info]   at org.apache.spark.sql.catalyst.SQLConfHelper.withSQLConf$(SQLConfHelper.scala:38)
   [info]   at org.apache.spark.sql.avro.AvroSuite.org$apache$spark$sql$test$SQLTestUtilsBase$$super$withSQLConf(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.test.SQLTestUtilsBase.withSQLConf(SQLTestUtils.scala:255)
   [info]   at org.apache.spark.sql.test.SQLTestUtilsBase.withSQLConf$(SQLTestUtils.scala:253)
   [info]   at org.apache.spark.sql.avro.AvroSuite.withSQLConf(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$198(AvroSuite.scala:1820)
   [info]   at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
   [info]   at org.scalatest.enablers.Timed$$anon$1.timeoutAfter(Timed.scala:127)
   [info]   at org.scalatest.concurrent.TimeLimits$.failAfterImpl(TimeLimits.scala:282)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter(TimeLimits.scala:231)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter$(TimeLimits.scala:230)
   [info]   at org.apache.spark.SparkFunSuite.failAfter(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.SparkFunSuite.$anonfun$test$2(SparkFunSuite.scala:41)
   [info]   at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
   [info]   at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
   [info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:22)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:20)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike$$anon$1.apply(AnyFunSuiteLike.scala:226)
   [info]   at org.apache.spark.SparkTestSuite.withFixture(SparkTestSuite.scala:175)
   [info]   at org.apache.spark.SparkTestSuite.withFixture$(SparkTestSuite.scala:169)
   [info]   at org.apache.spark.SparkFunSuite.withFixture(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.invokeWithFixture$1(AnyFunSuiteLike.scala:224)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTest$1(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest$(AnyFunSuiteLike.scala:218)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterEach$$super$runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest(BeforeAndAfterEach.scala:234)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest$(BeforeAndAfterEach.scala:227)
   [info]   at org.apache.spark.SparkFunSuite.runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTests$1(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
   [info]   at scala.collection.immutable.List.foreach(List.scala:323)
   [info]   at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
   [info]   at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
   [info]   at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests$(AnyFunSuiteLike.scala:268)
   [info]   at org.scalatest.funsuite.AnyFunSuite.runTests(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.Suite.run(Suite.scala:1114)
   [info]   at org.scalatest.Suite.run$(Suite.scala:1096)
   [info]   at org.scalatest.funsuite.AnyFunSuite.org$scalatest$funsuite$AnyFunSuiteLike$$super$run(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$run$1(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.SuperEngine.runImpl(Engine.scala:535)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run$(AnyFunSuiteLike.scala:272)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterAll$$super$run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterAll.liftedTree1$1(BeforeAndAfterAll.scala:213)
   [info]   at org.scalatest.BeforeAndAfterAll.run(BeforeAndAfterAll.scala:210)
   [info]   at org.scalatest.BeforeAndAfterAll.run$(BeforeAndAfterAll.scala:208)
   [info]   at org.apache.spark.SparkFunSuite.run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:321)
   [info]   at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:517)
   [info]   at sbt.ForkMain$Run.lambda$runTest$1(ForkMain.java:414)
   [info]   at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
   [info]   at java.base/java.lang.Thread.run(Thread.java:840)
   
   ...
   
   [info] - Geospatial types are not supported in Avro *** FAILED *** (6 milliseconds)
   [info]   HashMap("columnType" -> ""GEOMETRY(0)"", "format" -> "AVRO", "columnName" -> "`g`") did not equal Map("columnName" -> "`g`", "columnType" -> ""GEOMETRY(0)"", "format" -> "Avro") (SparkTestSuite.scala:324)
   [info]   Analysis:
   [info]   HashMap("format": "AVRO" -> "Avro")
   [info]   org.scalatest.exceptions.TestFailedException:
   [info]   at org.scalatest.Assertions.newAssertionFailedException(Assertions.scala:472)
   [info]   at org.scalatest.Assertions.newAssertionFailedException$(Assertions.scala:471)
   [info]   at org.scalatest.Assertions$.newAssertionFailedException(Assertions.scala:1231)
   [info]   at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:1295)
   [info]   at org.apache.spark.SparkTestSuite.checkError(SparkTestSuite.scala:324)
   [info]   at org.apache.spark.SparkTestSuite.checkError$(SparkTestSuite.scala:297)
   [info]   at org.apache.spark.SparkFunSuite.checkError(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$488(AvroSuite.scala:3677)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$488$adapted(AvroSuite.scala:3676)
   [info]   at scala.collection.immutable.List.foreach(List.scala:323)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$487(AvroSuite.scala:3676)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$487$adapted(AvroSuite.scala:3666)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1(SQLTestUtils.scala:81)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1$adapted(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir(SparkTestSuite.scala:193)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir$(SparkTestSuite.scala:191)
   [info]   at org.apache.spark.sql.avro.AvroSuite.org$apache$spark$sql$test$SQLTestUtils$$super$withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir$(SQLTestUtils.scala:79)
   [info]   at org.apache.spark.sql.avro.AvroSuite.withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$486(AvroSuite.scala:3666)
   [info]   at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
   [info]   at org.scalatest.enablers.Timed$$anon$1.timeoutAfter(Timed.scala:127)
   [info]   at org.scalatest.concurrent.TimeLimits$.failAfterImpl(TimeLimits.scala:282)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter(TimeLimits.scala:231)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter$(TimeLimits.scala:230)
   [info]   at org.apache.spark.SparkFunSuite.failAfter(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.SparkFunSuite.$anonfun$test$2(SparkFunSuite.scala:41)
   [info]   at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
   [info]   at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
   [info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:22)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:20)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike$$anon$1.apply(AnyFunSuiteLike.scala:226)
   [info]   at org.apache.spark.SparkTestSuite.withFixture(SparkTestSuite.scala:175)
   [info]   at org.apache.spark.SparkTestSuite.withFixture$(SparkTestSuite.scala:169)
   [info]   at org.apache.spark.SparkFunSuite.withFixture(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.invokeWithFixture$1(AnyFunSuiteLike.scala:224)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTest$1(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest$(AnyFunSuiteLike.scala:218)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterEach$$super$runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest(BeforeAndAfterEach.scala:234)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest$(BeforeAndAfterEach.scala:227)
   [info]   at org.apache.spark.SparkFunSuite.runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTests$1(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
   [info]   at scala.collection.immutable.List.foreach(List.scala:323)
   [info]   at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
   [info]   at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
   [info]   at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests$(AnyFunSuiteLike.scala:268)
   [info]   at org.scalatest.funsuite.AnyFunSuite.runTests(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.Suite.run(Suite.scala:1114)
   [info]   at org.scalatest.Suite.run$(Suite.scala:1096)
   [info]   at org.scalatest.funsuite.AnyFunSuite.org$scalatest$funsuite$AnyFunSuiteLike$$super$run(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$run$1(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.SuperEngine.runImpl(Engine.scala:535)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run$(AnyFunSuiteLike.scala:272)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterAll$$super$run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterAll.liftedTree1$1(BeforeAndAfterAll.scala:213)
   [info]   at org.scalatest.BeforeAndAfterAll.run(BeforeAndAfterAll.scala:210)
   [info]   at org.scalatest.BeforeAndAfterAll.run$(BeforeAndAfterAll.scala:208)
   [info]   at org.apache.spark.SparkFunSuite.run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:321)
   [info]   at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:517)
   [info]   at sbt.ForkMain$Run.lambda$runTest$1(ForkMain.java:414)
   [info]   at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
   [info]   at java.base/java.lang.Thread.run(Thread.java:840)
   ```
   
   Before this pr, the function `formatName` will not be invoked.



-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "LuciferYang (via GitHub)" <gi...@apache.org>.
LuciferYang commented on code in PR #54998:
URL: https://github.com/apache/spark/pull/54998#discussion_r3069564236


##########
connector/avro/src/main/scala/org/apache/spark/sql/v2/avro/AvroTable.scala:
##########
@@ -43,13 +43,14 @@ case class AvroTable(
     AvroUtils.inferSchema(sparkSession, options.asScala.toMap, files)
 
   override def newWriteBuilder(info: LogicalWriteInfo): WriteBuilder = {
-    new WriteBuilder {
-      override def build(): Write =
-        AvroWrite(paths, formatName, supportsDataType, mergedWriteInfo(info))
+    createFileWriteBuilder(info) {
+      (mergedInfo, partSchema, customLocs, dynamicOverwrite, truncate) =>
+      AvroWrite(paths, formatName, supportsDataType, mergedInfo, partSchema, customLocs,
+        dynamicOverwrite, truncate)
     }
   }
 
   override def supportsDataType(dataType: DataType): Boolean = AvroUtils.supportsDataType(dataType)
 
-  override def formatName: String = "AVRO"
+  override def formatName: String = "Avro"

Review Comment:
   To fix test failed:
   
   ```
   [info] - error handling for unsupported Interval data types *** FAILED *** (19 milliseconds)
   [info]   HashMap("columnType" -> ""INTERVAL"", "format" -> "AVRO", "columnName" -> "`INTERVAL '1 days'`") did not equal Map("format" -> "Avro", "columnName" -> "`INTERVAL '1 days'`", "columnType" -> ""INTERVAL"") (SparkTestSuite.scala:324)
   [info]   Analysis:
   [info]   HashMap("format": "AVRO" -> "Avro")
   [info]   org.scalatest.exceptions.TestFailedException:
   [info]   at org.scalatest.Assertions.newAssertionFailedException(Assertions.scala:472)
   [info]   at org.scalatest.Assertions.newAssertionFailedException$(Assertions.scala:471)
   [info]   at org.scalatest.Assertions$.newAssertionFailedException(Assertions.scala:1231)
   [info]   at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:1295)
   [info]   at org.apache.spark.SparkTestSuite.checkError(SparkTestSuite.scala:324)
   [info]   at org.apache.spark.SparkTestSuite.checkError$(SparkTestSuite.scala:297)
   [info]   at org.apache.spark.SparkFunSuite.checkError(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$200(AvroSuite.scala:1822)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$200$adapted(AvroSuite.scala:1820)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1(SQLTestUtils.scala:81)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1$adapted(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir(SparkTestSuite.scala:193)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir$(SparkTestSuite.scala:191)
   [info]   at org.apache.spark.sql.avro.AvroSuite.org$apache$spark$sql$test$SQLTestUtils$$super$withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir$(SQLTestUtils.scala:79)
   [info]   at org.apache.spark.sql.avro.AvroSuite.withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$199(AvroSuite.scala:1820)
   [info]   at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
   [info]   at org.apache.spark.sql.catalyst.SQLConfHelper.withSQLConf(SQLConfHelper.scala:54)
   [info]   at org.apache.spark.sql.catalyst.SQLConfHelper.withSQLConf$(SQLConfHelper.scala:38)
   [info]   at org.apache.spark.sql.avro.AvroSuite.org$apache$spark$sql$test$SQLTestUtilsBase$$super$withSQLConf(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.test.SQLTestUtilsBase.withSQLConf(SQLTestUtils.scala:255)
   [info]   at org.apache.spark.sql.test.SQLTestUtilsBase.withSQLConf$(SQLTestUtils.scala:253)
   [info]   at org.apache.spark.sql.avro.AvroSuite.withSQLConf(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$198(AvroSuite.scala:1820)
   [info]   at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
   [info]   at org.scalatest.enablers.Timed$$anon$1.timeoutAfter(Timed.scala:127)
   [info]   at org.scalatest.concurrent.TimeLimits$.failAfterImpl(TimeLimits.scala:282)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter(TimeLimits.scala:231)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter$(TimeLimits.scala:230)
   [info]   at org.apache.spark.SparkFunSuite.failAfter(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.SparkFunSuite.$anonfun$test$2(SparkFunSuite.scala:41)
   [info]   at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
   [info]   at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
   [info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:22)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:20)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike$$anon$1.apply(AnyFunSuiteLike.scala:226)
   [info]   at org.apache.spark.SparkTestSuite.withFixture(SparkTestSuite.scala:175)
   [info]   at org.apache.spark.SparkTestSuite.withFixture$(SparkTestSuite.scala:169)
   [info]   at org.apache.spark.SparkFunSuite.withFixture(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.invokeWithFixture$1(AnyFunSuiteLike.scala:224)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTest$1(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest$(AnyFunSuiteLike.scala:218)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterEach$$super$runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest(BeforeAndAfterEach.scala:234)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest$(BeforeAndAfterEach.scala:227)
   [info]   at org.apache.spark.SparkFunSuite.runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTests$1(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
   [info]   at scala.collection.immutable.List.foreach(List.scala:323)
   [info]   at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
   [info]   at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
   [info]   at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests$(AnyFunSuiteLike.scala:268)
   [info]   at org.scalatest.funsuite.AnyFunSuite.runTests(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.Suite.run(Suite.scala:1114)
   [info]   at org.scalatest.Suite.run$(Suite.scala:1096)
   [info]   at org.scalatest.funsuite.AnyFunSuite.org$scalatest$funsuite$AnyFunSuiteLike$$super$run(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$run$1(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.SuperEngine.runImpl(Engine.scala:535)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run$(AnyFunSuiteLike.scala:272)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterAll$$super$run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterAll.liftedTree1$1(BeforeAndAfterAll.scala:213)
   [info]   at org.scalatest.BeforeAndAfterAll.run(BeforeAndAfterAll.scala:210)
   [info]   at org.scalatest.BeforeAndAfterAll.run$(BeforeAndAfterAll.scala:208)
   [info]   at org.apache.spark.SparkFunSuite.run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:321)
   [info]   at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:517)
   [info]   at sbt.ForkMain$Run.lambda$runTest$1(ForkMain.java:414)
   [info]   at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
   [info]   at java.base/java.lang.Thread.run(Thread.java:840)
   
   ...
   
   [info] - Geospatial types are not supported in Avro *** FAILED *** (6 milliseconds)
   [info]   HashMap("columnType" -> ""GEOMETRY(0)"", "format" -> "AVRO", "columnName" -> "`g`") did not equal Map("columnName" -> "`g`", "columnType" -> ""GEOMETRY(0)"", "format" -> "Avro") (SparkTestSuite.scala:324)
   [info]   Analysis:
   [info]   HashMap("format": "AVRO" -> "Avro")
   [info]   org.scalatest.exceptions.TestFailedException:
   [info]   at org.scalatest.Assertions.newAssertionFailedException(Assertions.scala:472)
   [info]   at org.scalatest.Assertions.newAssertionFailedException$(Assertions.scala:471)
   [info]   at org.scalatest.Assertions$.newAssertionFailedException(Assertions.scala:1231)
   [info]   at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:1295)
   [info]   at org.apache.spark.SparkTestSuite.checkError(SparkTestSuite.scala:324)
   [info]   at org.apache.spark.SparkTestSuite.checkError$(SparkTestSuite.scala:297)
   [info]   at org.apache.spark.SparkFunSuite.checkError(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$488(AvroSuite.scala:3677)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$488$adapted(AvroSuite.scala:3676)
   [info]   at scala.collection.immutable.List.foreach(List.scala:323)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$487(AvroSuite.scala:3676)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$487$adapted(AvroSuite.scala:3666)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1(SQLTestUtils.scala:81)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1$adapted(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir(SparkTestSuite.scala:193)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir$(SparkTestSuite.scala:191)
   [info]   at org.apache.spark.sql.avro.AvroSuite.org$apache$spark$sql$test$SQLTestUtils$$super$withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir$(SQLTestUtils.scala:79)
   [info]   at org.apache.spark.sql.avro.AvroSuite.withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.avro.AvroV2Suite.$anonfun$new$486(AvroSuite.scala:3666)
   [info]   at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
   [info]   at org.scalatest.enablers.Timed$$anon$1.timeoutAfter(Timed.scala:127)
   [info]   at org.scalatest.concurrent.TimeLimits$.failAfterImpl(TimeLimits.scala:282)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter(TimeLimits.scala:231)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter$(TimeLimits.scala:230)
   [info]   at org.apache.spark.SparkFunSuite.failAfter(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.SparkFunSuite.$anonfun$test$2(SparkFunSuite.scala:41)
   [info]   at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
   [info]   at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
   [info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:22)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:20)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike$$anon$1.apply(AnyFunSuiteLike.scala:226)
   [info]   at org.apache.spark.SparkTestSuite.withFixture(SparkTestSuite.scala:175)
   [info]   at org.apache.spark.SparkTestSuite.withFixture$(SparkTestSuite.scala:169)
   [info]   at org.apache.spark.SparkFunSuite.withFixture(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.invokeWithFixture$1(AnyFunSuiteLike.scala:224)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTest$1(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest$(AnyFunSuiteLike.scala:218)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterEach$$super$runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest(BeforeAndAfterEach.scala:234)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest$(BeforeAndAfterEach.scala:227)
   [info]   at org.apache.spark.SparkFunSuite.runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTests$1(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
   [info]   at scala.collection.immutable.List.foreach(List.scala:323)
   [info]   at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
   [info]   at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
   [info]   at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests$(AnyFunSuiteLike.scala:268)
   [info]   at org.scalatest.funsuite.AnyFunSuite.runTests(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.Suite.run(Suite.scala:1114)
   [info]   at org.scalatest.Suite.run$(Suite.scala:1096)
   [info]   at org.scalatest.funsuite.AnyFunSuite.org$scalatest$funsuite$AnyFunSuiteLike$$super$run(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$run$1(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.SuperEngine.runImpl(Engine.scala:535)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run$(AnyFunSuiteLike.scala:272)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterAll$$super$run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterAll.liftedTree1$1(BeforeAndAfterAll.scala:213)
   [info]   at org.scalatest.BeforeAndAfterAll.run(BeforeAndAfterAll.scala:210)
   [info]   at org.scalatest.BeforeAndAfterAll.run$(BeforeAndAfterAll.scala:208)
   [info]   at org.apache.spark.SparkFunSuite.run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:321)
   [info]   at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:517)
   [info]   at sbt.ForkMain$Run.lambda$runTest$1(ForkMain.java:414)
   [info]   at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
   [info]   at java.base/java.lang.Thread.run(Thread.java:840)
   ```
   
   Before this pr, the function `formatName` will not be invoked.



-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "dongjoon-hyun (via GitHub)" <gi...@apache.org>.
dongjoon-hyun commented on code in PR #54998:
URL: https://github.com/apache/spark/pull/54998#discussion_r3064203469


##########
sql/core/src/test/scala/org/apache/spark/sql/connector/FileDataSourceV2WriteSuite.scala:
##########
@@ -0,0 +1,553 @@
+/*
+ * 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.connector
+
+import scala.collection.mutable.ArrayBuffer
+
+import org.apache.spark.{SparkConf, SparkException}
+import org.apache.spark.sql.{DataFrame, QueryTest, Row}
+import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan
+import org.apache.spark.sql.connector.catalog.{SupportsRead, SupportsWrite, Table, TableCapability}
+import org.apache.spark.sql.connector.read.ScanBuilder
+import org.apache.spark.sql.connector.write.{LogicalWriteInfo, WriteBuilder}
+import org.apache.spark.sql.execution.{FileSourceScanExec, QueryExecution}
+import org.apache.spark.sql.execution.datasources.{FileFormat, InsertIntoHadoopFsRelationCommand}
+import org.apache.spark.sql.execution.datasources.parquet.ParquetFileFormat
+import org.apache.spark.sql.execution.datasources.v2.FileDataSourceV2
+import org.apache.spark.sql.execution.datasources.v2.parquet.ParquetDataSourceV2
+import org.apache.spark.sql.internal.SQLConf
+import org.apache.spark.sql.test.SharedSparkSession
+import org.apache.spark.sql.types.StructType
+import org.apache.spark.sql.util.{CaseInsensitiveStringMap, QueryExecutionListener}
+
+class DummyReadOnlyFileDataSourceV2 extends FileDataSourceV2 {
+
+  override def fallbackFileFormat: Class[_ <: FileFormat] = classOf[ParquetFileFormat]
+
+  override def shortName(): String = "parquet"
+
+  override def getTable(options: CaseInsensitiveStringMap): Table = {
+    new DummyReadOnlyFileTable
+  }
+}
+
+class DummyReadOnlyFileTable extends Table with SupportsRead {
+  override def name(): String = "dummy"
+
+  override def schema(): StructType = StructType(Nil)
+
+  override def newScanBuilder(options: CaseInsensitiveStringMap): ScanBuilder = {
+    throw SparkException.internalError("Dummy file reader")
+  }
+
+  override def capabilities(): java.util.Set[TableCapability] =
+    java.util.EnumSet.of(TableCapability.BATCH_READ, TableCapability.ACCEPT_ANY_SCHEMA)
+}
+
+class DummyWriteOnlyFileDataSourceV2 extends FileDataSourceV2 {
+
+  override def fallbackFileFormat: Class[_ <: FileFormat] = classOf[ParquetFileFormat]
+
+  override def shortName(): String = "parquet"
+
+  override def getTable(options: CaseInsensitiveStringMap): Table = {
+    new DummyWriteOnlyFileTable
+  }
+}
+
+class DummyWriteOnlyFileTable extends Table with SupportsWrite {
+  override def name(): String = "dummy"
+
+  override def schema(): StructType = StructType(Nil)
+
+  override def newWriteBuilder(info: LogicalWriteInfo): WriteBuilder =
+    throw SparkException.internalError("Dummy file writer")
+
+  override def capabilities(): java.util.Set[TableCapability] =
+    java.util.EnumSet.of(TableCapability.BATCH_WRITE, TableCapability.ACCEPT_ANY_SCHEMA)
+}
+
+class FileDataSourceV2WriteSuite extends QueryTest with SharedSparkSession {
+
+  private val dummyReadOnlyFileSourceV2 = classOf[DummyReadOnlyFileDataSourceV2].getName
+  private val dummyWriteOnlyFileSourceV2 = classOf[DummyWriteOnlyFileDataSourceV2].getName
+
+  // Built-in file formats for write testing. Text is excluded
+  // because it only supports a single string column.
+  private val fileFormats = Seq("parquet", "orc", "json", "csv")

Review Comment:
   - Shall we revisit the comment because `avro` is also excluded in this suite?
   - Do we have the same test coverage for `avro`?



-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "LuciferYang (via GitHub)" <gi...@apache.org>.
LuciferYang commented on PR #54998:
URL: https://github.com/apache/spark/pull/54998#issuecomment-4123031442

   Follow-up tickets
   
   | Ticket | Description |
   |--------|-------------|
   | SPARK-56174 | V2 file write ErrorIfExists/Ignore modes |
   | SPARK-56175 | FileTable implements SupportsPartitionManagement |
   | SPARK-56185 | V2 FileTable catalog table loading (stats, NOT NULL, validation, gate removal) |
   


-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on PR #54998:
URL: https://github.com/apache/spark/pull/54998#issuecomment-5064941846

   We're closing this PR because it hasn't been updated in a while. This isn't a judgement on the merit of the PR in any way. It's just a way of keeping the PR queue manageable.
   If you'd like to revive this PR, please reopen it and ask a committer to remove the Stale tag!


-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "LuciferYang (via GitHub)" <gi...@apache.org>.
LuciferYang commented on code in PR #54998:
URL: https://github.com/apache/spark/pull/54998#discussion_r3069564236


##########
connector/avro/src/main/scala/org/apache/spark/sql/v2/avro/AvroTable.scala:
##########
@@ -43,13 +43,14 @@ case class AvroTable(
     AvroUtils.inferSchema(sparkSession, options.asScala.toMap, files)
 
   override def newWriteBuilder(info: LogicalWriteInfo): WriteBuilder = {
-    new WriteBuilder {
-      override def build(): Write =
-        AvroWrite(paths, formatName, supportsDataType, mergedWriteInfo(info))
+    createFileWriteBuilder(info) {
+      (mergedInfo, partSchema, customLocs, dynamicOverwrite, truncate) =>
+      AvroWrite(paths, formatName, supportsDataType, mergedInfo, partSchema, customLocs,
+        dynamicOverwrite, truncate)
     }
   }
 
   override def supportsDataType(dataType: DataType): Boolean = AvroUtils.supportsDataType(dataType)
 
-  override def formatName: String = "AVRO"
+  override def formatName: String = "Avro"

Review Comment:
   To fix test failed:
   
   ```
   [info] - error handling for unsupported Interval data types *** FAILED *** (19 milliseconds)
   [info]   HashMap("columnType" -> ""INTERVAL"", "format" -> "AVRO", "columnName" -> "`INTERVAL '1 days'`") did not equal Map("format" -> "Avro", "columnName" -> "`INTERVAL '1 days'`", "columnType" -> ""INTERVAL"") (SparkTestSuite.scala:324)
   [info]   Analysis:
   [info]   HashMap("format": "AVRO" -> "Avro")
   [info]   org.scalatest.exceptions.TestFailedException:
   [info]   at org.scalatest.Assertions.newAssertionFailedException(Assertions.scala:472)
   [info]   at org.scalatest.Assertions.newAssertionFailedException$(Assertions.scala:471)
   [info]   at org.scalatest.Assertions$.newAssertionFailedException(Assertions.scala:1231)
   [info]   at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:1295)
   [info]   at org.apache.spark.SparkTestSuite.checkError(SparkTestSuite.scala:324)
   [info]   at org.apache.spark.SparkTestSuite.checkError$(SparkTestSuite.scala:297)
   [info]   at org.apache.spark.SparkFunSuite.checkError(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$200(AvroSuite.scala:1822)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$200$adapted(AvroSuite.scala:1820)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1(SQLTestUtils.scala:81)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.$anonfun$withTempDir$1$adapted(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir(SparkTestSuite.scala:193)
   [info]   at org.apache.spark.SparkTestSuite.withTempDir$(SparkTestSuite.scala:191)
   [info]   at org.apache.spark.sql.avro.AvroSuite.org$apache$spark$sql$test$SQLTestUtils$$super$withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir(SQLTestUtils.scala:80)
   [info]   at org.apache.spark.sql.test.SQLTestUtils.withTempDir$(SQLTestUtils.scala:79)
   [info]   at org.apache.spark.sql.avro.AvroSuite.withTempDir(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$199(AvroSuite.scala:1820)
   [info]   at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
   [info]   at org.apache.spark.sql.catalyst.SQLConfHelper.withSQLConf(SQLConfHelper.scala:54)
   [info]   at org.apache.spark.sql.catalyst.SQLConfHelper.withSQLConf$(SQLConfHelper.scala:38)
   [info]   at org.apache.spark.sql.avro.AvroSuite.org$apache$spark$sql$test$SQLTestUtilsBase$$super$withSQLConf(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.test.SQLTestUtilsBase.withSQLConf(SQLTestUtils.scala:255)
   [info]   at org.apache.spark.sql.test.SQLTestUtilsBase.withSQLConf$(SQLTestUtils.scala:253)
   [info]   at org.apache.spark.sql.avro.AvroSuite.withSQLConf(AvroSuite.scala:57)
   [info]   at org.apache.spark.sql.avro.AvroSuite.$anonfun$new$198(AvroSuite.scala:1820)
   [info]   at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
   [info]   at org.scalatest.enablers.Timed$$anon$1.timeoutAfter(Timed.scala:127)
   [info]   at org.scalatest.concurrent.TimeLimits$.failAfterImpl(TimeLimits.scala:282)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter(TimeLimits.scala:231)
   [info]   at org.scalatest.concurrent.TimeLimits.failAfter$(TimeLimits.scala:230)
   [info]   at org.apache.spark.SparkFunSuite.failAfter(SparkFunSuite.scala:30)
   [info]   at org.apache.spark.SparkFunSuite.$anonfun$test$2(SparkFunSuite.scala:41)
   [info]   at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
   [info]   at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
   [info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:22)
   [info]   at org.scalatest.Transformer.apply(Transformer.scala:20)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike$$anon$1.apply(AnyFunSuiteLike.scala:226)
   [info]   at org.apache.spark.SparkTestSuite.withFixture(SparkTestSuite.scala:175)
   [info]   at org.apache.spark.SparkTestSuite.withFixture$(SparkTestSuite.scala:169)
   [info]   at org.apache.spark.SparkFunSuite.withFixture(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.invokeWithFixture$1(AnyFunSuiteLike.scala:224)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTest$1(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest(AnyFunSuiteLike.scala:236)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTest$(AnyFunSuiteLike.scala:218)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterEach$$super$runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest(BeforeAndAfterEach.scala:234)
   [info]   at org.scalatest.BeforeAndAfterEach.runTest$(BeforeAndAfterEach.scala:227)
   [info]   at org.apache.spark.SparkFunSuite.runTest(SparkFunSuite.scala:30)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$runTests$1(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
   [info]   at scala.collection.immutable.List.foreach(List.scala:323)
   [info]   at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
   [info]   at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
   [info]   at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests(AnyFunSuiteLike.scala:269)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.runTests$(AnyFunSuiteLike.scala:268)
   [info]   at org.scalatest.funsuite.AnyFunSuite.runTests(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.Suite.run(Suite.scala:1114)
   [info]   at org.scalatest.Suite.run$(Suite.scala:1096)
   [info]   at org.scalatest.funsuite.AnyFunSuite.org$scalatest$funsuite$AnyFunSuiteLike$$super$run(AnyFunSuite.scala:1564)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.$anonfun$run$1(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.SuperEngine.runImpl(Engine.scala:535)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run(AnyFunSuiteLike.scala:273)
   [info]   at org.scalatest.funsuite.AnyFunSuiteLike.run$(AnyFunSuiteLike.scala:272)
   [info]   at org.apache.spark.SparkFunSuite.org$scalatest$BeforeAndAfterAll$$super$run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.BeforeAndAfterAll.liftedTree1$1(BeforeAndAfterAll.scala:213)
   [info]   at org.scalatest.BeforeAndAfterAll.run(BeforeAndAfterAll.scala:210)
   [info]   at org.scalatest.BeforeAndAfterAll.run$(BeforeAndAfterAll.scala:208)
   [info]   at org.apache.spark.SparkFunSuite.run(SparkFunSuite.scala:30)
   [info]   at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:321)
   [info]   at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:517)
   [info]   at sbt.ForkMain$Run.lambda$runTest$1(ForkMain.java:414)
   [info]   at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
   [info]   at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
   [info]   at java.base/java.lang.Thread.run(Thread.java:840)
   ```
   
   Before this pr, the function `formatName` will not be invoked.



-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "LuciferYang (via GitHub)" <gi...@apache.org>.
LuciferYang commented on code in PR #54998:
URL: https://github.com/apache/spark/pull/54998#discussion_r3064829049


##########
sql/core/src/test/scala/org/apache/spark/sql/connector/FileDataSourceV2WriteSuite.scala:
##########
@@ -0,0 +1,553 @@
+/*
+ * 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.connector
+
+import scala.collection.mutable.ArrayBuffer
+
+import org.apache.spark.{SparkConf, SparkException}
+import org.apache.spark.sql.{DataFrame, QueryTest, Row}
+import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan
+import org.apache.spark.sql.connector.catalog.{SupportsRead, SupportsWrite, Table, TableCapability}
+import org.apache.spark.sql.connector.read.ScanBuilder
+import org.apache.spark.sql.connector.write.{LogicalWriteInfo, WriteBuilder}
+import org.apache.spark.sql.execution.{FileSourceScanExec, QueryExecution}
+import org.apache.spark.sql.execution.datasources.{FileFormat, InsertIntoHadoopFsRelationCommand}
+import org.apache.spark.sql.execution.datasources.parquet.ParquetFileFormat
+import org.apache.spark.sql.execution.datasources.v2.FileDataSourceV2
+import org.apache.spark.sql.execution.datasources.v2.parquet.ParquetDataSourceV2
+import org.apache.spark.sql.internal.SQLConf
+import org.apache.spark.sql.test.SharedSparkSession
+import org.apache.spark.sql.types.StructType
+import org.apache.spark.sql.util.{CaseInsensitiveStringMap, QueryExecutionListener}
+
+class DummyReadOnlyFileDataSourceV2 extends FileDataSourceV2 {
+
+  override def fallbackFileFormat: Class[_ <: FileFormat] = classOf[ParquetFileFormat]
+
+  override def shortName(): String = "parquet"
+
+  override def getTable(options: CaseInsensitiveStringMap): Table = {
+    new DummyReadOnlyFileTable
+  }
+}
+
+class DummyReadOnlyFileTable extends Table with SupportsRead {
+  override def name(): String = "dummy"
+
+  override def schema(): StructType = StructType(Nil)
+
+  override def newScanBuilder(options: CaseInsensitiveStringMap): ScanBuilder = {
+    throw SparkException.internalError("Dummy file reader")
+  }
+
+  override def capabilities(): java.util.Set[TableCapability] =
+    java.util.EnumSet.of(TableCapability.BATCH_READ, TableCapability.ACCEPT_ANY_SCHEMA)
+}
+
+class DummyWriteOnlyFileDataSourceV2 extends FileDataSourceV2 {
+
+  override def fallbackFileFormat: Class[_ <: FileFormat] = classOf[ParquetFileFormat]
+
+  override def shortName(): String = "parquet"
+
+  override def getTable(options: CaseInsensitiveStringMap): Table = {
+    new DummyWriteOnlyFileTable
+  }
+}
+
+class DummyWriteOnlyFileTable extends Table with SupportsWrite {
+  override def name(): String = "dummy"
+
+  override def schema(): StructType = StructType(Nil)
+
+  override def newWriteBuilder(info: LogicalWriteInfo): WriteBuilder =
+    throw SparkException.internalError("Dummy file writer")
+
+  override def capabilities(): java.util.Set[TableCapability] =
+    java.util.EnumSet.of(TableCapability.BATCH_WRITE, TableCapability.ACCEPT_ANY_SCHEMA)
+}
+
+class FileDataSourceV2WriteSuite extends QueryTest with SharedSparkSession {
+
+  private val dummyReadOnlyFileSourceV2 = classOf[DummyReadOnlyFileDataSourceV2].getName
+  private val dummyWriteOnlyFileSourceV2 = classOf[DummyWriteOnlyFileDataSourceV2].getName
+
+  // Built-in file formats for write testing. Text is excluded
+  // because it only supports a single string column.
+  private val fileFormats = Seq("parquet", "orc", "json", "csv")

Review Comment:
   Updated the comments and added some test cases for Avro to maintain the same scenario coverage as here.Their corresponding relationships are as follows:
   
   
     | FileDataSourceV2WriteSuite test | Avro coverage |
   |---|---|
   | File write for multiple formats | AvroSuite `test save and load` |
   | File write V1-vs-V2 comparison | `SPARK-56171: Avro V2 write produces same results as V1 write` |
   | Partitioned file write | AvroSuite `reading and writing partitioned data` |
   | Partitioned write V1-vs-V2 comparison | `SPARK-56171: Avro V2 partitioned write produces same results as V1` |
   | Multi-level partitioned write | `SPARK-56171: Avro V2 multi-level partitioned write` |
   | Dynamic partition overwrite | `SPARK-56171: Avro V2 dynamic partition overwrite` |
   | Dynamic partition overwrite V1-vs-V2 | `SPARK-56171: Avro V2 dynamic partition overwrite produces same results as V1` |
   | DataFrame API write (append + overwrite) | Covered by cache invalidation tests |
   | DataFrame API partitioned write | Covered by multi-level partitioned test |
   | DataFrame API write with compression | AvroSuite `write with compression` (738, 2350) |
   | Catalog table INSERT INTO | `SPARK-56171: Avro V2 catalog table INSERT INTO` |
   | Catalog table partitioned INSERT INTO | `SPARK-56171: Avro V2 catalog table partitioned INSERT INTO` |
   | V2 cache invalidation on overwrite | `SPARK-56171: Avro V2 cache invalidation on overwrite` |
   | V2 cache invalidation on append | `SPARK-56171: Avro V2 cache invalidation on append` |
   | Cache invalidation on catalog table overwrite | `SPARK-56171: Avro V2 cache invalidation on catalog table overwrite` |
   | CTAS | `SPARK-56171: Avro V2 CTAS` |
   | Partitioned write to empty directory | `SPARK-56171: Avro V2 partitioned write to empty directory` |
   | Partitioned overwrite to existing directory | `SPARK-56171: Avro V2 partitioned overwrite to existing directory` |
   



-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "dongjoon-hyun (via GitHub)" <gi...@apache.org>.
dongjoon-hyun commented on code in PR #54998:
URL: https://github.com/apache/spark/pull/54998#discussion_r3064869826


##########
connector/avro/src/main/scala/org/apache/spark/sql/v2/avro/AvroTable.scala:
##########
@@ -43,13 +43,14 @@ case class AvroTable(
     AvroUtils.inferSchema(sparkSession, options.asScala.toMap, files)
 
   override def newWriteBuilder(info: LogicalWriteInfo): WriteBuilder = {
-    new WriteBuilder {
-      override def build(): Write =
-        AvroWrite(paths, formatName, supportsDataType, mergedWriteInfo(info))
+    createFileWriteBuilder(info) {
+      (mergedInfo, partSchema, customLocs, dynamicOverwrite, truncate) =>
+      AvroWrite(paths, formatName, supportsDataType, mergedInfo, partSchema, customLocs,
+        dynamicOverwrite, truncate)
     }
   }
 
   override def supportsDataType(dataType: DataType): Boolean = AvroUtils.supportsDataType(dataType)
 
-  override def formatName: String = "AVRO"
+  override def formatName: String = "Avro"

Review Comment:
   Just a question. Why do we need this change in this PR? Can we avoid this change or proceed this independently if needed?



-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "LuciferYang (via GitHub)" <gi...@apache.org>.
LuciferYang commented on code in PR #54998:
URL: https://github.com/apache/spark/pull/54998#discussion_r3064829049


##########
sql/core/src/test/scala/org/apache/spark/sql/connector/FileDataSourceV2WriteSuite.scala:
##########
@@ -0,0 +1,553 @@
+/*
+ * 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.connector
+
+import scala.collection.mutable.ArrayBuffer
+
+import org.apache.spark.{SparkConf, SparkException}
+import org.apache.spark.sql.{DataFrame, QueryTest, Row}
+import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan
+import org.apache.spark.sql.connector.catalog.{SupportsRead, SupportsWrite, Table, TableCapability}
+import org.apache.spark.sql.connector.read.ScanBuilder
+import org.apache.spark.sql.connector.write.{LogicalWriteInfo, WriteBuilder}
+import org.apache.spark.sql.execution.{FileSourceScanExec, QueryExecution}
+import org.apache.spark.sql.execution.datasources.{FileFormat, InsertIntoHadoopFsRelationCommand}
+import org.apache.spark.sql.execution.datasources.parquet.ParquetFileFormat
+import org.apache.spark.sql.execution.datasources.v2.FileDataSourceV2
+import org.apache.spark.sql.execution.datasources.v2.parquet.ParquetDataSourceV2
+import org.apache.spark.sql.internal.SQLConf
+import org.apache.spark.sql.test.SharedSparkSession
+import org.apache.spark.sql.types.StructType
+import org.apache.spark.sql.util.{CaseInsensitiveStringMap, QueryExecutionListener}
+
+class DummyReadOnlyFileDataSourceV2 extends FileDataSourceV2 {
+
+  override def fallbackFileFormat: Class[_ <: FileFormat] = classOf[ParquetFileFormat]
+
+  override def shortName(): String = "parquet"
+
+  override def getTable(options: CaseInsensitiveStringMap): Table = {
+    new DummyReadOnlyFileTable
+  }
+}
+
+class DummyReadOnlyFileTable extends Table with SupportsRead {
+  override def name(): String = "dummy"
+
+  override def schema(): StructType = StructType(Nil)
+
+  override def newScanBuilder(options: CaseInsensitiveStringMap): ScanBuilder = {
+    throw SparkException.internalError("Dummy file reader")
+  }
+
+  override def capabilities(): java.util.Set[TableCapability] =
+    java.util.EnumSet.of(TableCapability.BATCH_READ, TableCapability.ACCEPT_ANY_SCHEMA)
+}
+
+class DummyWriteOnlyFileDataSourceV2 extends FileDataSourceV2 {
+
+  override def fallbackFileFormat: Class[_ <: FileFormat] = classOf[ParquetFileFormat]
+
+  override def shortName(): String = "parquet"
+
+  override def getTable(options: CaseInsensitiveStringMap): Table = {
+    new DummyWriteOnlyFileTable
+  }
+}
+
+class DummyWriteOnlyFileTable extends Table with SupportsWrite {
+  override def name(): String = "dummy"
+
+  override def schema(): StructType = StructType(Nil)
+
+  override def newWriteBuilder(info: LogicalWriteInfo): WriteBuilder =
+    throw SparkException.internalError("Dummy file writer")
+
+  override def capabilities(): java.util.Set[TableCapability] =
+    java.util.EnumSet.of(TableCapability.BATCH_WRITE, TableCapability.ACCEPT_ANY_SCHEMA)
+}
+
+class FileDataSourceV2WriteSuite extends QueryTest with SharedSparkSession {
+
+  private val dummyReadOnlyFileSourceV2 = classOf[DummyReadOnlyFileDataSourceV2].getName
+  private val dummyWriteOnlyFileSourceV2 = classOf[DummyWriteOnlyFileDataSourceV2].getName
+
+  // Built-in file formats for write testing. Text is excluded
+  // because it only supports a single string column.
+  private val fileFormats = Seq("parquet", "orc", "json", "csv")

Review Comment:
   Updated the comments and added some test cases for Avro to maintain the same scenario coverage as here.Their corresponding relationships are as follows:
   
   
     ┌───────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────────────────────┐
     │        FileDataSourceV2WriteSuite test        │                                  Avro coverage                                  │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ File write for multiple formats               │ AvroSuite test save and load ✅                                                 │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ File write V1-vs-V2 comparison                │ SPARK-56171: Avro V2 write produces same results as V1 write ✅                 │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ Partitioned file write                        │ AvroSuite reading and writing partitioned data ✅                               │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ Partitioned write V1-vs-V2 comparison         │ SPARK-56171: Avro V2 partitioned write produces same results as V1 ✅           │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ Multi-level partitioned write                 │ SPARK-56171: Avro V2 multi-level partitioned write ✅                           │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ Dynamic partition overwrite                   │ SPARK-56171: Avro V2 dynamic partition overwrite ✅                             │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ Dynamic partition overwrite V1-vs-V2          │ SPARK-56171: Avro V2 dynamic partition overwrite produces same results as V1 ✅ │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ DataFrame API write (append + overwrite)      │ Covered by cache invalidation tests ✅                                          │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ DataFrame API partitioned write               │ Covered by multi-level partitioned test ✅                                      │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ DataFrame API write with compression          │ AvroSuite write with compression (738, 2350) ✅                                 │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ Catalog table INSERT INTO                     │ SPARK-56171: Avro V2 catalog table INSERT INTO ✅                               │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ Catalog table partitioned INSERT INTO         │ SPARK-56171: Avro V2 catalog table partitioned INSERT INTO ✅                   │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ V2 cache invalidation on overwrite            │ SPARK-56171: Avro V2 cache invalidation on overwrite ✅                         │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ V2 cache invalidation on append               │ SPARK-56171: Avro V2 cache invalidation on append ✅                            │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ Cache invalidation on catalog table overwrite │ SPARK-56171: Avro V2 cache invalidation on catalog table overwrite ✅           │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ CTAS                                          │ SPARK-56171: Avro V2 CTAS ✅                                                    │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ Partitioned write to empty directory          │ SPARK-56171: Avro V2 partitioned write to empty directory ✅                    │
     ├───────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┤
     │ Partitioned overwrite to existing directory   │ SPARK-56171: Avro V2 partitioned overwrite to existing directory ✅             │
     └───────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────────────────────┘



-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-56171][SQL] Enable V2 file write path for non-partitioned DataFrame API writes and delete `FallBackFileSourceV2` [spark]

Posted by "dongjoon-hyun (via GitHub)" <gi...@apache.org>.
dongjoon-hyun commented on PR #54998:
URL: https://github.com/apache/spark/pull/54998#issuecomment-4123425006

   Wow, this and many TODO IDs. Thank you for working on this area, @LuciferYang .


-- 
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: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org