cloud-fan commented on code in PR #59467:
URL: https://github.com/apache/spark/pull/59467#discussion_r4280002942


##########
sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/v2/PushDownUtils.scala:
##########
@@ -717,9 +717,21 @@ object PushDownUtils extends Logging {
       relation: DataSourceV2Relation): Seq[AttributeReference] = {
     val nameToAttr = Utils.toMap(relation.output.map(_.name), relation.output)
     val cleaned = CharVarcharUtils.replaceCharVarcharWithStringInSchema(schema)
-    toAttributes(cleaned).map {
-      // we have to keep the attribute id during transformation
-      a => a.withExprId(nameToAttr(a.name).exprId)
+    toAttributes(cleaned).map { a =>
+      val orig = nameToAttr(a.name)
+      // Keep exprId. Do not re-stamp __CHAR_VARCHAR_TYPE_STRING after
+      // ApplyCharTypePadding cleaned it: that marker means "not yet padded",
+      // and this runs in the optimizer with no second padding pass. File
+      // sources usually already substituted STRING, so the stamp was latent;
+      // a V2 scan whose readSchema() still surfaces CHAR/VARCHAR would
+      // otherwise look unpadded. Key off the relation's own padding state,
+      // not the session conf: a still-stamped relation was not padded.

Review Comment:
   **Nit (P3):** This sentence doesn't hold for versioned tables. In a 
non-command query, `QueryExecution`'s table-version refresh runs 
`AnalyzedSchemaProjection.rebindToAnalyzedSchema`, which re-creates the 
relation output through `DataSourceV2Relation.create` and so re-stamps the 
marker. `sameAttributeShape` compares metadata, so the cleaned attribute isn't 
reused. The relation that reaches `toOutputAttrs` is then stamped even though 
`ApplyCharTypePadding` already padded it. Your test comment in 
`CharVarcharTestSuite` ('The InMemory prune path can still see a stamped 
relation object') says the same thing.
   
   Could you reword this to describe the rule the code applies? The marker is 
dropped when the relation attribute passed in has none, and kept otherwise, 
including for a padded versioned relation that the refresh rebound. The final 
wording depends on the versioned-table decision challenge in the review body.
   
   **Verification:**
   - **Inspection:** The comment's stated rule matches the branch condition on 
the relation attribute's marker. It claims no equivalence between the marker 
and padding state that the versioned refresh rebind violates, and it is 
consistent with the DSv2 test comments about the InMemory prune path.



##########
sql/core/src/test/scala/org/apache/spark/sql/CharVarcharTestSuite.scala:
##########
@@ -3999,4 +4085,78 @@ class DSV2CharVarcharTestSuite extends 
CharVarcharTestSuite
       }
     }
   }
+
+  private def withPrunedV2CharRelation(body: (DataFrame, DataSourceV2Relation) 
=> Unit): Unit = {
+    withTable("std_v2_prune") {
+      sql(s"CREATE TABLE std_v2_prune (c CHAR(5), extra INT) USING $format")
+      sql("INSERT INTO std_v2_prune VALUES ('ab', 1)")
+      val df = sql("SELECT c FROM std_v2_prune")
+      val rel = df.queryExecution.analyzed.collect {
+        case r: DataSourceV2Relation => r
+      }.head
+      body(df, rel)
+    }
+  }
+
+  private def attrsFromCharReadSchema(rel: DataSourceV2Relation) =
+    PushDownUtils.toOutputAttrs(new StructType().add("c", CharType(5)), rel)
+
+  test("SPARK-59016: V2 column prune does not re-stamp CHAR padding 
breadcrumb") {
+    withSQLConf(SQLConf.CHAR_VARCHAR_STANDARD_SEMANTICS.key -> "true") {

Review Comment:
   **Nit (P3):** One configuration is missing from this matrix: standard 
semantics on with `READ_SIDE_CHAR_PADDING=false`. There `ApplyCharTypePadding` 
only logs a warning and still pads and cleans the relation 
(`ApplyCharTypePadding.scala:59-70`), so the gate should drop the marker. None 
of the three tests runs it, so a gate written as `if 
(SQLConf.get.readSideCharPadding) cleanMetadata(...) else ...` would pass all 
three. Could you add a case next to this one with standard semantics on and 
read-side padding off? It should assert that the relation is cleaned, that the 
direct `toOutputAttrs` call drops the marker, and that the query returns the 
padded value.
   
   This case doesn't separate the structural gate from the earlier 
`charVarcharStandardSemantics` disjunct, because both strip there. That choice 
is part of the decision challenge in the review body.
   
   This extends an [existing 
discussion](https://github.com/apache/spark/pull/59467#discussion_r4275151188).
   
   **Verification:**
   - **Regression:** Replacing the relation-state gate with a 
readSideCharPadding-keyed condition makes the new case fail, while the three 
existing prune cases keep passing.
   - **Behavior:** With standard semantics on and read-side padding disabled, 
the pruned single-column query over a CHAR(5) DSv2 column returns the padded 
value.



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