szehon-ho commented on code in PR #57722:
URL: https://github.com/apache/spark/pull/57722#discussion_r3725943837


##########
sql/pipelines/src/main/scala/org/apache/spark/sql/pipelines/util/SchemaInferenceUtils.scala:
##########
@@ -39,55 +114,71 @@ object SchemaInferenceUtils {
    *    The user-specified schema will take precedence over the inferred 
schema.
    * Returns an error if encountered during schema inference or merging the 
inferred schema with
    * the user-specified one.
+   *
+   * All merges honor the effective `spark.sql.caseSensitive` of the flows 
writing to
+   * `tableIdentifier`, falling back to `sessionCaseSensitive` for flows that 
do not set it. Under
+   * case-insensitive analysis, flows emitting column names that differ only 
in case contribute a
+   * single column, and a declared column matches a flow column differing only 
in case -- consistent
+   * with how the rest of the engine resolves those names. If two flows differ 
only in column
+   * casing, the first flow's spelling wins because flows are merged in the 
order provided.

Review Comment:
   Suggestion: sort here -- `flows.sortBy(_.identifier.unquotedString)` before 
the fold -- rather than at the single call site in 
`DataflowGraph.inferSchemas`, so every caller merges in the same order.
   
   As written the ordering is the caller's responsibility, and only one of the 
three callers sorts. `GraphValidations.scala:266` is harmless (it compares 
against a declared schema, whose casing wins that merge anyway), but 
`elements.scala:193` produces the schema downstream flows resolve against:
   
   ```sql
   CREATE STREAMING TABLE events;
   -- declared first, identifier sorts second
   CREATE FLOW from_us AS INSERT INTO events BY NAME SELECT id, payload AS 
Value FROM STREAM us_src;
   -- declared second, identifier sorts first
   CREATE FLOW from_eu AS INSERT INTO events BY NAME SELECT id, payload AS 
value FROM STREAM eu_src;
   CREATE MATERIALIZED VIEW events_summary AS SELECT id, value FROM events;
   ```
   
   `events` materializes via `inferSchemas`, which sorts, so it gets `value`. 
`events_summary` resolves against `VirtualTableInput`, whose `availableFlows` 
is in declaration order, so it sees `Value` and persists `Value` -- Spark takes 
the resolved attribute's own name. One clean run therefore leaves the view's 
column spelled differently from both the source column it selects and what the 
user wrote. Swapping the two `CREATE FLOW` statements then flips the virtual 
schema to `value` while the catalog still holds `Value`, and since 
`diffSchemas` keys on exact names the next refresh drops and re-adds the column.
   
   Worth noting `availableFlows` is declaration order, not the resolved graph's 
completion order, so this is reproducible rather than a race.
   
   If the sort moves here, this docstring can own the rule and 
`DataflowGraph.inferSchemas` (line 179) can defer to 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: [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