zhuxiangyi opened a new pull request, #9372:
URL: https://github.com/apache/paimon/pull/9372

   ### Purpose
   
   `primary-key` and `bucket-key` are plain strings in `TBLPROPERTIES`, so they 
reach Paimon exactly as
   the user typed them and are then matched against the schema exactly. Every 
other identifier in the
   same statement follows `spark.sql.caseSensitive` — the partition columns in 
particular, because
   Spark's analyzer has already resolved them by the time the catalog sees 
them. That leaves a single
   statement obeying two different rules:
   
   ```sql
   -- accepted: the partition column resolves case-insensitively
   CREATE TABLE t (Id INT, Pt STRING) PARTITIONED BY (pt);
   
   -- rejected
   CREATE TABLE t (Id INT, A INT) TBLPROPERTIES ('primary-key'='id', 
'bucket'='1');
   -- IllegalStateException: Table column [Id, A] should include all primary 
key constraint [id]
   
   -- rejected
   CREATE TABLE t (Id INT, A INT) TBLPROPERTIES ('bucket-key'='id', 
'bucket'='1');
   -- RuntimeException: Field names [Id, A] should contains all bucket keys 
[id].
   ```
   
   Since `spark.sql.caseSensitive` is `false` by default, `Id` and `id` are the 
same identifier
   everywhere else in Spark, so this is surprising.
   
   **Fix.** Resolve both properties against the schema in `SparkCatalog`, 
honouring the session's
   case-sensitivity setting:
   
   - `toInitialSchema` — for the `primary-key` list and the `bucket-key` option 
value.
   - `alterTable` — for `bucket-key` only; `primary-key` cannot reach there 
because
     `validateAlterProperty` already rejects altering it. The table is loaded 
only when the property
     being set is `bucket-key`, so other `SET TBLPROPERTIES` calls are 
unaffected.
   
   Two deliberate choices:
   
   - **With `spark.sql.caseSensitive=true` nothing changes** — the exact-match 
requirement stays.
   - **A name matching no column is passed through untouched**, so Paimon still 
reports it exactly as
     the user wrote it instead of a rewritten one.
   
   **Why this stays on the Spark side.** The exact matching in core is 
*correct* for Flink: its
   identifiers are case-sensitive, so `Id` and `id` really are two different 
identifiers there, and its
   primary keys come from the resolved `PRIMARY KEY` DDL constraint 
(`FlinkCatalog`
   `builder.primaryKey(table.primaryKeys())`) rather than an option string. 
Changing core would break
   that. This mirrors how Iceberg handles it — a case-sensitivity flag plumbed 
through the connector
   (`SparkUtil.caseSensitive`, `PartitionSpec.Builder#caseSensitive`) rather 
than exact matching pushed
   down into the format. Paimon already has the same precedent on the Spark 
write path, where
   `SchemaEvolutionHelper` reads `conf.caseSensitiveAnalysis`.
   
   **Side effect worth noting.** `bucket-key` values are now split on `,` and 
trimmed before being
   stored, which `primary-key` already did. `'bucket-key' = 'id, sub'` 
previously failed, because
   `TableSchema#originalBucketKeys` splits on `,` without trimming and then 
looked for a column named
   `" sub"`. It now works, making the two properties consistent.
   
   Not covered here: other options whose values name columns (for example 
`sequence.field`) have the
   same shape and could be given the same treatment as a follow-up.
   
   ### Tests
   
   New `KeyPropertyCaseResolutionTestBase` with concrete suites for Spark 3.2, 
3.3, 3.4, 3.5, 4.0 and
   4.1 — 7 cases, asserting the stored key uses the column's real spelling and 
that the table is
   actually writable and readable afterwards:
   
   - `primary-key` / `bucket-key` resolve like every other identifier
   - multi-column and partitioned keys resolve (`'primary-key'='id,sub,pt'`)
   - `ALTER TABLE SET TBLPROPERTIES` resolves `bucket-key`
   - an exact spelling keeps working
   - an unknown column still reports the original name
   - `spark.sql.caseSensitive=true` keeps the exact-match requirement
   
   Verified green on Spark 3.2, 3.3, 3.4, 3.5 and 4.0 (7/7 each), and the full 
`paimon-spark-ut` module
   shows no new failures.
   


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