morningman opened a new pull request, #69567:
URL: https://github.com/apache/doris/pull/69567

   ### What problem does this PR solve?
   
   Issue Number: None
   
   Related PR: #68874
   
   Problem Summary:
   
   **In short.** This follows up #68874 on Paimon tables with a BINARY / 
VARBINARY partition column. A write to such a table whose partitions use 
Paimon's legacy names now fails while it is planned, with a hint to set 
`'partition.legacy-name' = 'false'`, instead of failing its commit and leaving 
files behind. On a table with the new names, `INSERT OVERWRITE ... PARTITION (p 
= X'...')` is supported when the bytes are UTF-8 text; #68874 had to reject 
every non-NULL binary static overwrite.
   
   **Background.** Paimon names a partition directory after the string of each 
partition value. With `partition.legacy-name = true`, the default, that string 
is `toString()` of the value, which for a binary value is the Java array object 
(`[B@1b6d3586`) rather than its bytes. With `partition.legacy-name = false` it 
is the text of the bytes (`p=AB` for `X'4142'`). Doris cannot create such a 
table itself (its DDL rejects VARBINARY columns), so these tables come from 
Spark, Flink or the Paimon API. Paimon's static overwrite 
(`withOverwrite(Map<String, String>)`) names the partition to replace by a 
string as well, and takes the UTF-8 bytes of that string as a binary value.
   
   **The problem, and what it cost.** Measured on master with Paimon 2.1.0, on 
a `file://` Paimon catalog of a local FE + BE, with tables created through the 
Paimon API:
   
   | Table / statement | Paimon API | Doris before this PR |
   |---|---|---|
   | `legacy-name = true`, write `X'4142'`, then read | the write succeeds, the 
read fails with `FileNotFoundException` (every resolution of the name gives 
another `[B@...`) | `INSERT` fails at commit: `Cannot recover from this 
checkpoint because some files in the snapshot that need to be resubmitted have 
been deleted`, and the BE's files stay under `p=%5BB@...` |
   | `legacy-name = false`, `INSERT` of `X'4142'`, `X'EF'`, NULL (also 
`BINARY(4)`, and a multi-instance `INSERT ... SELECT`) | writes and reads | 
writes and reads correctly |
   | `legacy-name = false`, `INSERT OVERWRITE ... PARTITION (p = X'4142') 
SELECT ...` | — | rejected: `Static overwrite of binary partition column 'p' is 
not supported` |
   
   The rejection came from #68874: the cast value of a binary static partition 
reaches the connector as `0x` and its hex digits, and Paimon would take the six 
bytes of `"0x4142"`, naming another partition; an overwrite without rows then 
reported success and left the given partition in place. The legacy failure 
costs a failed statement whose files nobody cleans up, on a table that Paimon 
itself cannot read back.
   
   **How this PR fixes it.**
   
   - `PaimonWriteBinding.create`, which every Paimon write (INSERT, OVERWRITE, 
row-level DML) goes through while it is planned, rejects a table that has a 
binary partition column and legacy partition names, naming the table option to 
set.
   - `PaimonWriteBinding.resolveStaticPartition` decodes the hex digits of a 
binary static value and passes Paimon the text the bytes decode to as UTF-8, 
which Paimon encodes back to the same bytes. The decoder is strict, so bytes 
that are not UTF-8 text (a lone `0xEF`, an overlong or surrogate sequence), 
which no string names, are still rejected, with the value in the message. A 
NULL static value keeps naming the `partition.default-name` partition, and a 
text equal to that name is still rejected, as for other types.
   
   **Results.** On the same local cluster, with a `legacy-name = false` table 
holding `(1, X'4142')`, `(2, X'4344')`, `(3, X'EF')`, `(4, NULL)`, `(6, X'')`:
   
   | Statement | After this PR (Doris read = Paimon API read) |
   |---|---|
   | `INSERT OVERWRITE ... PARTITION (p = X'4142') SELECT 5` | the `X'4142'` 
partition holds only 5 |
   | `INSERT OVERWRITE ... PARTITION (p = X'4344') SELECT 1 LIMIT 0` | the 
`X'4344'` partition is empty, the others are untouched |
   | `INSERT OVERWRITE ... PARTITION (p = X'EF') SELECT 1` | fails: `Static 
partition value 0xEF of binary column 'p' is not UTF-8 text, ...`; 3 stays |
   | `INSERT OVERWRITE ... PARTITION (p = NULL) SELECT 9` | the NULL partition 
holds only 9 |
   | `INSERT OVERWRITE ... PARTITION (p = X'') SELECT 7` | the empty-bytes 
partition holds only 7; the NULL partition keeps 9 |
   | `INSERT` / `INSERT OVERWRITE` into a `legacy-name = true` table | fails 
while planning: `... its binary partition column 'p' needs the table option 
'partition.legacy-name' = 'false' ...`; no files are written |
   
   `PaimonWriteBindingTest` replaces the test of the #68874 rejection with 
three tests: a binary static value becomes the text of its bytes and Paimon 
parses it back to them (for `BYTES`, `VARBINARY(2)`, `BINARY(2)`), bytes that 
are not UTF-8 are rejected, and a write of a binary partition with legacy names 
fails while one with new names, or a legacy table without a binary partition, 
is planned. They fail when the legacy check is dropped, when the cast value is 
passed through, and when the decoding replaces malformed bytes. All 847 tests 
of fe-connector-paimon pass.
   
   No regression test is added: Doris cannot create a binary column, so the 
table would have to come from the Spark container of the Paimon docker 
environment, which was not run locally.
   
   ### Release note
   
   Fix: a write to a Paimon table whose binary partition column uses legacy 
partition names fails at planning with a hint to set `'partition.legacy-name' = 
'false'`, instead of failing its commit and leaving files behind. `INSERT 
OVERWRITE ... PARTITION (p = X'...')` on a binary partition column of a Paimon 
table is supported when the bytes are UTF-8 text.
   
   ### Check List (For Author)
   
   - Test <!-- At least one of them must be included. -->
       - [ ] Regression test
       - [x] Unit Test
       - [x] Manual test (add detailed scripts or steps below)
         Local FE + BE with `CREATE CATALOG ... PROPERTIES ('type' = 'paimon', 
'warehouse' = 'file:///...')`; tables created with the Paimon Catalog API 
(`Schema.newBuilder().column("p", DataTypes.BYTES()).partitionKeys("p")`, with 
and without `partition.legacy-name = false`); the statements in the tables 
above, read back through Doris and through the Paimon API.
       - [ ] No need to test or manual test. Explain why:
           - [ ] This is a refactor/code format and no logic has been changed.
           - [ ] Previous test can cover this change.
           - [ ] No code files have been changed.
           - [ ] Other reason <!-- Add your reason?  -->
   
   - Behavior changed:
       - [ ] No.
       - [x] Yes. <!-- Explain the behavior change -->
         A write to a Paimon table with a binary partition column and legacy 
partition names fails at planning instead of at commit. A static overwrite of a 
binary partition column with a binary literal whose bytes are UTF-8 text is 
accepted instead of rejected.
   
   - Does this need documentation?
       - [x] No.
       - [ ] Yes. <!-- Add document PR link here. eg: 
https://github.com/apache/doris-website/pull/1214 -->
   
   ### Check List (For Reviewer who merge this PR)
   
   - [ ] Confirm the release note
   - [ ] Confirm test cases
   - [ ] Confirm document
   - [ ] Add branch pick label <!-- Add branch pick label that this PR should 
merge into -->
   


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