kerwin-zk commented on code in PR #8456:
URL: https://github.com/apache/paimon/pull/8456#discussion_r3523356787


##########
paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/write/PaimonV2WriteBuilder.scala:
##########
@@ -55,4 +61,63 @@ class PaimonV2WriteBuilder(table: FileStoreTable, 
dataSchema: StructType, option
   }
 
   override def partitionRowType(): RowType = 
table.schema().logicalPartitionType()
+
+  /**
+   * Fail fast when the query schema is binary-incompatible with the table 
schema.
+   *
+   * Paimon tables declare `ACCEPT_ANY_SCHEMA`, so Spark skips its own output 
resolution and the
+   * query is aligned to the table schema by `PaimonAnalysis` instead, which 
is only injected when
+   * `PaimonSparkSessionExtensions` is configured. If a write is planned 
without it, a
+   * type-mismatched query would reach the writer as-is and be interpreted 
with the table's row
+   * type, silently corrupting data or failing with errors like 
`NegativeArraySizeException` deep
+   * inside the format writer.
+   */
+  private def validateDataSchema(): Unit = {
+    // Row-level operations write the table's own rows back; schema evolution 
intentionally
+    // diverges from the current table schema and is validated when merging.
+    if (copyOnWriteScan.nonEmpty || 
SchemaEvolutionHelper.mergeSchemaEnabled(options)) {
+      return
+    }
+
+    val expectedFields = 
SparkTypeUtils.fromPaimonRowType(table.rowType()).fields
+    val actualFields = 
SparkSystemColumns.filterSparkSystemColumns(dataSchema).fields

Review Comment:
   Thanks for checking! I believe that run picked up a stale 
`paimon-spark-common_2.12-1.5-SNAPSHOT` from the local repository instead of 
the one from this branch, so the PR's change was never on the classpath.
   
   `-Pfast-build` explicitly activates a profile, which disables the 
`activeByDefault` activation of the `spark3` profile (standard Maven behavior). 
Without `spark3`, the `paimon-spark-common` modules drop out of the reactor — 
the reactor summary of that exact command only contains:
   
   ```
   [INFO] Paimon : Spark                                                     
[pom]
   [INFO] Paimon : Spark : UT : 2.12                                         
[jar]
   ```
   
   so `-am` never compiles this PR's change to `PaimonV2WriteBuilder`, and the 
test runs against whatever `1.5-SNAPSHOT` is installed in `~/.m2`. If that 
snapshot predates this PR, the test fails with exactly the signature you saw — 
I actually produced the same message on purpose while developing (ran the new 
test against a build with the fix stashed to verify it was red first):
   
   ```
   Expected exception java.lang.RuntimeException to be thrown,
   but org.apache.spark.SparkException was thrown (PaimonOptionTest.scala:331)
   ```
   
   Adding the spark3 profile brings the common modules back into the reactor:
   
   ```
   mvn -pl paimon-spark/paimon-spark-ut -am -Pfast-build,spark3 
-DfailIfNoTests=false \
     
-DwildcardSuites=org.apache.paimon.spark.sql.PaimonV2WriteSchemaValidationTest 
-Dtest=none clean test
   ```
   
   and the suite passes (your exact command also passes once the branch's 
`paimon-spark-common` is installed to the local repo; the PR CI, which builds 
from scratch, is green on both 2.12 and 2.13 as well):
   
   ```
   - Paimon V2 write: fail fast on incompatible query schema without Paimon 
extensions
   Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
   ```
   
   On the layering question: for this insert path `LogicalWriteInfo.schema()` 
is the analyzed query's output schema, which is exactly the row layout the 
writer receives, so validating it against the table row type in `build()` 
catches the mismatch on the driver before any task runs. Row-level operations 
(`copyOnWriteScan`) and `write.merge-schema` writes are exempted since their 
schemas intentionally diverge and are validated elsewhere.
   



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

To unsubscribe, e-mail: [email protected]

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

Reply via email to