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


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/RelationResolution.scala:
##########
@@ -358,6 +364,12 @@ class RelationResolution(
     CatalogV2Util.lookupCachedRelation(sharedRelationCache, catalog, ident, 
table, conf)
   }
 
+  private def applyOptions(
+      cached: LogicalPlan,
+      options: CaseInsensitiveStringMap): LogicalPlan = cached transform {
+    case r: DataSourceV2Relation => r.copy(options = options)

Review Comment:
   **Finding 2.** This only rewrites `DataSourceV2Relation`, so the same bug 
survives for v1 relations. A v1 table (session-catalog data-source or Hive 
table) resolves through `createDataSourceV1Scan` -> 
`SessionCatalog.getRelation(v1Table, options)` -> `SubqueryAlias(_, 
UnresolvedCatalogRelation(metadata, options))` (`SessionCatalog.scala:1140`), 
that plan goes into the same `relationCache`, and the options on it are live: 
`FindDataSourceTable` hands them to `readDataSourceTable` -> 
`DataSourceUtils.generateDatasourceOptions` (`DataSourceStrategy.scala:382`, 
`:259`), which even rebuilds a cached `HadoopFsRelation` when the options 
differ. v1 dynamic options aren't theoretical - `DDLSuite.scala:1394` 
("SPARK-51747: Data source cached plan respects options if ignore conf 
disabled") asserts that `SELECT * FROM t WITH ('delimiter' = ';')` on a CSV 
table changes the returned rows. So `INSERT INTO v1t WITH (a) SELECT * FROM v1t 
WITH (b)`, or a plain self-join on a v1 table, still ends up 
 with one set of options for both references.
   
   `UnresolvedCatalogRelation` is already imported here, so it's a one-liner:
   
   ```suggestion
       case r: DataSourceV2Relation => r.copy(options = options)
       case r: UnresolvedCatalogRelation => r.copy(options = options)
   ```
   
   If you'd rather keep this PR DSv2-only, could you say that in the 
description and leave a short note here? This PR removes the `AstBuilder` 
comment that was the only record of the limitation.
   



##########
sql/core/src/test/scala/org/apache/spark/sql/connector/DataSourceV2OptionSuite.scala:
##########
@@ -121,6 +121,44 @@ class DataSourceV2OptionSuite extends DatasourceV2SQLBase {
     }
   }
 
+  test("SPARK-58330: dynamic options are not lost when INSERT selects from the 
same table") {

Review Comment:
   **Finding 3.** All three new tests pair a write reference with a read 
reference. The plainest instance of the bug - two *read* references in one 
query - isn't covered, and that's the case where the fix changes behavior in 
both directions (neither scan inherits the other's options). On master both 
scans come out with `split-size = 5`, because the second reference hits the 
cache. Roughly ten lines here:
   
   ```scala
   test("SPARK-58330: each reference in a self-join keeps its own dynamic 
options") {
     val t1 = s"${catalogAndNamespace}table"
     withTable(t1) {
       sql(s"CREATE TABLE $t1 (id bigint, data string)")
       sql(s"INSERT INTO $t1 VALUES (1, 'a'), (2, 'b')")
   
       val df = sql(s"SELECT a.id FROM $t1 WITH (`split-size` = 5) a " +
         s"JOIN $t1 WITH (`split-size` = 9) b ON a.id = b.id")
       val splitSizes = df.queryExecution.optimizedPlan.collect {
         case s: DataSourceV2ScanRelation => 
s.relation.options.get("split-size")
       }
       assert(splitSizes.sorted === Seq("5", "9"))
     }
   }
   ```
   



-- 
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