peter-toth commented on code in PR #57227:
URL: https://github.com/apache/spark/pull/57227#discussion_r3604863220


##########
sql/core/src/test/scala/org/apache/spark/sql/connector/MergeIntoTableSuiteBase.scala:
##########
@@ -2851,6 +2853,127 @@ abstract class MergeIntoTableSuiteBase extends 
RowLevelOperationSuiteBase
     assert(catalog.lastTransaction.isClosed)
   }
 
+  test("SPARK-58007: merge with dynamic options on the target") {
+    withTable(sourceNameAsString) {
+      createAndInitTable("pk INT NOT NULL, salary INT, dep STRING",
+        """{ "pk": 1, "salary": 100, "dep": "hr" }
+          |{ "pk": 2, "salary": 200, "dep": "software" }
+          |""".stripMargin)
+      sql(s"CREATE TABLE $sourceNameAsString (pk INT NOT NULL, salary INT, dep 
STRING)")
+      sql(s"INSERT INTO $sourceNameAsString VALUES (1, 150, 'hr'), (3, 300, 
'hr')")
+
+      // the target options become the row-level operation options: they reach 
the rewritten
+      // DataSourceV2Relation, the RowLevelOperationInfo, and the write 
builder's LogicalWriteInfo
+      val Seq(qe) = withQueryExecutionsCaptured(spark) {
+        sql(
+          s"""MERGE INTO $tableNameAsString t WITH (`write.split-size` = 10)
+             |USING $sourceNameAsString s
+             |ON t.pk = s.pk
+             |WHEN MATCHED THEN UPDATE SET t.salary = s.salary

Review Comment:
   Every one of the three new tests has a `WHEN MATCHED` action, so they all 
take the full row-level rewrite (`ReplaceData`/`WriteDelta`). The MATCHED-free 
fast path is untested with options: `RewriteMergeIntoTable` turns a MERGE with 
only `WHEN NOT MATCHED THEN INSERT` into an `InsertOnlyMerge` 
(`RewriteMergeIntoTable.scala:77,119`), whose write is built from `r.options` 
at a separate site (`V2Writes.scala:55`) that these tests never reach. Worth 
one more test: target options on a `WHEN NOT MATCHED THEN INSERT *`-only merge, 
asserting the option lands on `table.lastWriteInfo`.
   



##########
sql/core/src/test/scala/org/apache/spark/sql/connector/MergeIntoTableSuiteBase.scala:
##########
@@ -2851,6 +2853,127 @@ abstract class MergeIntoTableSuiteBase extends 
RowLevelOperationSuiteBase
     assert(catalog.lastTransaction.isClosed)
   }
 
+  test("SPARK-58007: merge with dynamic options on the target") {
+    withTable(sourceNameAsString) {
+      createAndInitTable("pk INT NOT NULL, salary INT, dep STRING",
+        """{ "pk": 1, "salary": 100, "dep": "hr" }
+          |{ "pk": 2, "salary": 200, "dep": "software" }
+          |""".stripMargin)
+      sql(s"CREATE TABLE $sourceNameAsString (pk INT NOT NULL, salary INT, dep 
STRING)")
+      sql(s"INSERT INTO $sourceNameAsString VALUES (1, 150, 'hr'), (3, 300, 
'hr')")
+
+      // the target options become the row-level operation options: they reach 
the rewritten
+      // DataSourceV2Relation, the RowLevelOperationInfo, and the write 
builder's LogicalWriteInfo
+      val Seq(qe) = withQueryExecutionsCaptured(spark) {
+        sql(
+          s"""MERGE INTO $tableNameAsString t WITH (`write.split-size` = 10)
+             |USING $sourceNameAsString s
+             |ON t.pk = s.pk
+             |WHEN MATCHED THEN UPDATE SET t.salary = s.salary
+             |WHEN NOT MATCHED THEN INSERT *
+             |""".stripMargin)
+      }
+      val writeRelation = qe.optimizedPlan.collectFirst {
+        case rd: ReplaceData => rd.table
+        case wd: WriteDelta => wd.table
+      }.getOrElse(fail("couldn't find row-level operation in optimized plan"))
+        .asInstanceOf[DataSourceV2Relation]
+      val operation = 
writeRelation.table.asInstanceOf[RowLevelOperationTable].operation
+        .asInstanceOf[RowLevelOperationWithOptions]
+      assert(writeRelation.options.get("write.split-size") === "10", "relation 
option")

Review Comment:
   These three lines are exactly 
`UpdateTableSuiteBase.checkRowLevelOperationOptions` 
(`UpdateTableSuiteBase.scala:1242`), and the "both" test repeats them again at 
2955-2958. Since both `MergeIntoTableSuiteBase` and `UpdateTableSuiteBase` 
extend `RowLevelOperationSuiteBase`, consider lifting that helper into the 
shared base and calling it here:
   
   ```scala
   checkRowLevelOperationOptions(
     sql(s"""MERGE INTO ... """.stripMargin),
     "write.split-size" -> "10")
   ```
   
   That keeps the target-side verification identical across UPDATE and MERGE 
and drops the duplicated block (the helper already wraps the 
`collectFirst`/capture).
   



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

To unsubscribe, e-mail: [email protected]

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


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

Reply via email to